Merge "USB: Update strings for USB connected notifications"
diff --git a/api/current.txt b/api/current.txt
index 5053859..cf0eda3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -596,10 +596,10 @@
field public static final int layout_centerInParent = 16843151; // 0x101018f
field public static final int layout_centerVertical = 16843153; // 0x1010191
field public static final int layout_column = 16843084; // 0x101014c
- field public static final int layout_columnSpan = 16843646; // 0x101037e
- field public static final int layout_columnWeight = 16843647; // 0x101037f
+ field public static final int layout_columnSpan = 16843645; // 0x101037d
field public static final int layout_gravity = 16842931; // 0x10100b3
field public static final int layout_height = 16842997; // 0x10100f5
+ field public static final int layout_heightSpec = 16843647; // 0x101037f
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
field public static final int layout_marginEnd = 16843675; // 0x101039b
@@ -609,13 +609,13 @@
field public static final int layout_marginTop = 16843000; // 0x10100f8
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
- field public static final int layout_rowWeight = 16843645; // 0x101037d
field public static final int layout_scale = 16843155; // 0x1010193
field public static final int layout_span = 16843085; // 0x101014d
field public static final int layout_toLeftOf = 16843138; // 0x1010182
field public static final int layout_toRightOf = 16843139; // 0x1010183
field public static final int layout_weight = 16843137; // 0x1010181
field public static final int layout_width = 16842996; // 0x10100f4
+ field public static final int layout_widthSpec = 16843646; // 0x101037e
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
@@ -24892,9 +24892,9 @@
}
public class GridLayout extends android.view.ViewGroup {
- ctor public GridLayout(android.content.Context);
ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
ctor public GridLayout(android.content.Context, android.util.AttributeSet);
+ ctor public GridLayout(android.content.Context);
method public int getAlignmentMode();
method public int getColumnCount();
method public int getOrientation();
@@ -24914,8 +24914,11 @@
field public static final int ALIGN_MARGINS = 1; // 0x1
field public static final android.widget.GridLayout.Alignment BASELINE;
field public static final android.widget.GridLayout.Alignment BOTTOM;
+ field public static final android.widget.GridLayout.Spec CAN_SHRINK;
+ field public static final android.widget.GridLayout.Spec CAN_STRETCH;
field public static final android.widget.GridLayout.Alignment CENTER;
field public static final android.widget.GridLayout.Alignment FILL;
+ field public static final android.widget.GridLayout.Spec FIXED;
field public static final int HORIZONTAL = 0; // 0x0
field public static final android.widget.GridLayout.Alignment LEFT;
field public static final android.widget.GridLayout.Alignment RIGHT;
@@ -24942,9 +24945,13 @@
ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
method public void setGravity(int);
field public android.widget.GridLayout.Group columnGroup;
- field public float columnWeight;
+ field public android.widget.GridLayout.Spec heightSpec;
field public android.widget.GridLayout.Group rowGroup;
- field public float rowWeight;
+ field public android.widget.GridLayout.Spec widthSpec;
+ }
+
+ public static abstract class GridLayout.Spec {
+ ctor public GridLayout.Spec();
}
public class GridView extends android.widget.AbsListView {
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index ab0cb50..41d3e71 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -52,18 +52,24 @@
/** 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 voicemail source. */
public static final Uri CONTENT_URI_SOURCE =
Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
+ /** URI to insert/retrieve status of voicemail source. */
+ public static final Uri STATUS_CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/status");
+ /**
+ * Parameter key used in the URI to specify the voicemail source package name.
+ * <p> This field must be set in all requests that originate from a voicemail source.
+ */
+ public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package";
// TODO: Move ACTION_NEW_VOICEMAIL to the Intent class.
/** Broadcast intent when a new voicemail record is inserted. */
public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
-
/**
* Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and
* {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate if the receiving
@@ -72,9 +78,27 @@
public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
/** The mime type for a collection of voicemails. */
- public static final String DIR_TYPE =
- "vnd.android.cursor.dir/voicemails";
+ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+ /**
+ * A convenience method to build voicemail URI specific to a source package. Appends URI param
+ * {@link #PARAM_KEY_SOURCE_PACKAGE} to the base voicemail content URI.
+ */
+ public static Uri buildSourceVoicemailUri(String packageName) {
+ return CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ }
+
+ /**
+ * A convenience method to build status URI specific to a source package. Appends URI param
+ * {@link #PARAM_KEY_SOURCE_PACKAGE} to the base status content URI.
+ */
+ public static Uri buildSourceStatusUri(String packageName) {
+ return STATUS_CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ }
+
+ /** Defines fields exposed through the /voicemail path of this content provider. */
public static final class Voicemails implements BaseColumns {
/** Not instantiable. */
private Voicemails() {
@@ -144,4 +168,76 @@
*/
public static final String _DATA = "_data";
}
+
+ /** Defines fields exposed through the /status path of this content provider. */
+ public static final class Status implements BaseColumns {
+ /** Not instantiable. */
+ private Status() {
+ }
+ /**
+ * The package name of the voicemail source. There can only be a one entry per source.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SOURCE_PACKAGE = "source_package";
+ /**
+ * The URI to call to invoke source specific voicemail settings screen. On a user request
+ * to setup voicemail an intent with action VIEW with this URI will be fired by the system.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SETTINGS_URI = "settings_uri";
+ /**
+ * The URI to call when the user requests to directly access the voicemail from the remote
+ * server. In case of an IVR voicemail system this is typically set to the the voicemail
+ * number specified using a tel:/ URI.
+ * <P>Type: TEXT</P>
+ */
+ public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
+ /**
+ * The configuration state of the voicemail source.
+ * <P> Possible values:
+ * {@link #CONFIGURATION_STATE_OK},
+ * {@link #CONFIGURATION_STATE_NOT_CONFIGURED},
+ * {@link #CONFIGURATION_STATE_CAN_BE_CONFIGURED}
+ * <P>Type: INTEGER</P>
+ */
+ public static final String CONFIGURATION_STATE = "configuration_state";
+ public static final int CONFIGURATION_STATE_OK = 0;
+ public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1;
+ /**
+ * This state must be used when the source has verified that the current user can be
+ * upgraded to visual voicemail and would like to show a set up invitation message.
+ */
+ public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2;
+ /**
+ * The data channel state of the voicemail source. This the channel through which the source
+ * pulls voicemail data from a remote server.
+ * <P> Possible values:
+ * {@link #DATA_CHANNEL_STATE_OK},
+ * {@link #DATA_CHANNEL_STATE_NO_CONNECTION}
+ * </P>
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_CHANNEL_STATE = "data_channel_state";
+ public static final int DATA_CHANNEL_STATE_OK = 0;
+ public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1;
+ /**
+ * The notification channel state of the voicemail source. This is the channel through which
+ * the source gets notified of new voicemails on the remote server.
+ * <P> Possible values:
+ * {@link #NOTIFICATION_CHANNEL_STATE_OK},
+ * {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION},
+ * {@link #NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING}
+ * </P>
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
+ public static final int NOTIFICATION_CHANNEL_STATE_OK = 0;
+ public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1;
+ /**
+ * Use this state when the notification can only tell that there are pending messages on
+ * the server but no details of the sender/time etc are known.
+ */
+ public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2;
+
+ }
}
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 11ab0d7..0ea27a0 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -107,6 +107,7 @@
// After we return from this we can't use the surface any more.
// The current Video View will be destroy when we play a new video.
pauseAndDispatch(mProxy);
+ mPlayer.release();
mSurfaceHolder = null;
if (mMediaController != null) {
mMediaController.hide();
@@ -226,6 +227,10 @@
mProxy.getWebView().getViewManager().showAll();
mProxy = null;
+
+ // Don't show the controller after exiting the full screen.
+ mMediaController = null;
+ mCurrentState = STATE_RELEASED;
}
};
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
index 5983a44..67660b8 100644
--- a/core/java/android/webkit/HTML5VideoView.java
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -34,6 +34,7 @@
static final int STATE_NOTPREPARED = 1;
static final int STATE_PREPARED = 2;
static final int STATE_PLAYING = 3;
+ static final int STATE_RELEASED = 4;
protected int mCurrentState;
protected HTML5VideoViewProxy mProxy;
@@ -84,7 +85,7 @@
}
public void pause() {
- if (mCurrentState == STATE_PREPARED && mPlayer.isPlaying()) {
+ if (isPlaying()) {
mPlayer.pause();
} else if (mCurrentState == STATE_NOTPREPARED) {
mPauseDuringPreparing = true;
@@ -120,11 +121,18 @@
}
public boolean isPlaying() {
- return mPlayer.isPlaying();
+ if (mCurrentState == STATE_PREPARED) {
+ return mPlayer.isPlaying();
+ } else {
+ return false;
+ }
}
public void release() {
- mPlayer.release();
+ if (mCurrentState != STATE_RELEASED) {
+ mPlayer.release();
+ }
+ mCurrentState = STATE_RELEASED;
}
public void stopPlayback() {
@@ -228,7 +236,7 @@
public int getCurrentState() {
- if (mPlayer.isPlaying()) {
+ if (isPlaying()) {
return STATE_PLAYING;
} else {
return mCurrentState;
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 5b4fb1d..4c42cde 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -70,7 +70,11 @@
com.android.internal.R.string.autofill_expiration_month_re, // IDS_AUTOFILL_EXPIRATION_MONTH_RE
com.android.internal.R.string.autofill_expiration_date_re, // IDS_AUTOFILL_EXPIRATION_DATE_RE
com.android.internal.R.string.autofill_card_ignored_re, // IDS_AUTOFILL_CARD_IGNORED_RE
- com.android.internal.R.string.autofill_fax_re // IDS_AUTOFILL_FAX_RE
+ com.android.internal.R.string.autofill_fax_re, // IDS_AUTOFILL_FAX_RE
+ com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE
+ com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
+ com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
+ com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
};
private static Context mApplicationContext;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 1570224..7c0470e 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -24,6 +24,7 @@
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -33,7 +34,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -67,7 +67,7 @@
*
* <h4>Default Cell Assignment</h4>
*
- * If no child specifies the row and column indices of the cell it
+ * If a child does not specify the row and column indices of the cell it
* wishes to occupy, GridLayout assigns cell locations automatically using its:
* {@link GridLayout#setOrientation(int) orientation},
* {@link GridLayout#setRowCount(int) rowCount} and
@@ -94,8 +94,8 @@
*
* Like {@link LinearLayout}, a child's ability to stretch is controlled
* using <em>weights</em>, which are specified using the
- * {@link GridLayout.LayoutParams#rowWeight rowWeight} and
- * {@link GridLayout.LayoutParams#columnWeight columnWeight} layout parameters.
+ * {@link GridLayout.LayoutParams#widthSpec widthSpec} and
+ * {@link GridLayout.LayoutParams#heightSpec heightSpec} layout parameters.
* <p>
* <p>
* See {@link GridLayout.LayoutParams} for a full description of the
@@ -171,9 +171,7 @@
private static final String TAG = GridLayout.class.getName();
private static final boolean DEBUG = false;
private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
- private static final int MIN = 0;
private static final int PRF = 1;
- private static final int MAX = 2;
// Defaults
@@ -184,6 +182,7 @@
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
// todo remove this
private static final int DEFAULT_CONTAINER_MARGIN = 20;
+ private static final int MAX_SIZE = 100000;
// TypedArray indices
@@ -205,36 +204,16 @@
private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
private int mDefaultGravity = Gravity.NO_GRAVITY;
- /* package */ boolean accommodateBothMinAndMax = false;
-
// Constructors
/**
* {@inheritDoc}
*/
- public GridLayout(Context context) {
- this(context, null, 0);
- }
-
- /**
- * {@inheritDoc}
- */
public GridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (DEBUG) {
setWillNotDraw(false);
}
- processAttributes(context, attrs);
- }
-
- /**
- * {@inheritDoc}
- */
- public GridLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- private void processAttributes(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
@@ -249,6 +228,20 @@
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public GridLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public GridLayout(Context context) {
+ this(context, null);
+ }
+
// Implementation
/**
@@ -527,11 +520,10 @@
return result;
}
- private static int sum(float[] a) {
- int result = 0;
- for (int i = 0, length = a.length; i < length; i++) {
- result += a[i];
- }
+ private static <T> T[] append(T[] a, T[] b) {
+ T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
@@ -603,13 +595,13 @@
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams1(c);
- Group colGroup = lp.columnGroup;
- Interval cols = colGroup.span;
- int colSpan = cols.size();
+ final Group colGroup = lp.columnGroup;
+ final Interval cols = colGroup.span;
+ final int colSpan = cols.size();
- Group rowGroup = lp.rowGroup;
- Interval rows = rowGroup.span;
- int rowSpan = rows.size();
+ final Group rowGroup = lp.rowGroup;
+ final Interval rows = rowGroup.span;
+ final int rowSpan = rows.size();
if (horizontal) {
row = valueIfDefined2(rows.min, row);
@@ -700,8 +692,8 @@
}
private void drawRectangle(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
- // x2 = x2 - 1;
- // y2 = y2 - 1;
+ x2 = x2 - 1;
+ y2 = y2 - 1;
graphics.drawLine(x1, y1, x1, y2, paint);
graphics.drawLine(x1, y1, x2, y1, paint);
graphics.drawLine(x1, y2, x2, y2, paint);
@@ -734,9 +726,9 @@
drawLine(canvas, 0, y, width - 1, y, paint);
}
}
+
// Draw bounds
paint.setColor(Color.BLUE);
-
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -748,7 +740,6 @@
// Draw margins
paint.setColor(Color.YELLOW);
-
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -819,11 +810,11 @@
protected void onMeasure(int widthSpec, int heightSpec) {
measureChildrenWithMargins(widthSpec, heightSpec);
- int computedWidth = getPaddingLeft() + mHorizontalAxis.getMin() + getPaddingRight();
- int computedHeight = getPaddingTop() + mVerticalAxis.getMin() + getPaddingBottom();
+ int width = getPaddingLeft() + mHorizontalAxis.getMeasure(widthSpec) + getPaddingRight();
+ int height = getPaddingTop() + mVerticalAxis.getMeasure(heightSpec) + getPaddingBottom();
- int measuredWidth = Math.max(computedWidth, getSuggestedMinimumWidth());
- int measuredHeight = Math.max(computedHeight, getSuggestedMinimumHeight());
+ int measuredWidth = Math.max(width, getSuggestedMinimumWidth());
+ int measuredHeight = Math.max(height, getSuggestedMinimumHeight());
setMeasuredDimension(
resolveSizeAndState(measuredWidth, widthSpec, 0),
@@ -834,12 +825,12 @@
return (alignment == UNDEFINED) ? 0 : alignment;
}
- private int getMeasurement(View c, boolean horizontal, int measurementType) {
+ private int getMeasurement(View c, boolean horizontal) {
return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
}
- private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) {
- int result = getMeasurement(c, horizontal, measurementType);
+ private int getMeasurementIncludingMargin(View c, boolean horizontal) {
+ int result = getMeasurement(c, horizontal);
if (mAlignmentMode == ALIGN_MARGINS) {
return result + getTotalMargin(c, horizontal);
}
@@ -889,17 +880,17 @@
Interval colSpan = columnGroup.span;
Interval rowSpan = rowGroup.span;
- int x1 = mHorizontalAxis.getLocationIncludingMargin(c, true, colSpan.min);
- int y1 = mVerticalAxis.getLocationIncludingMargin(c, true, rowSpan.min);
+ int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
+ int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
- int x2 = mHorizontalAxis.getLocationIncludingMargin(c, false, colSpan.max);
- int y2 = mVerticalAxis.getLocationIncludingMargin(c, false, rowSpan.max);
+ int x2 = mHorizontalAxis.getLocationIncludingMargin(false, colSpan.max);
+ int y2 = mVerticalAxis.getLocationIncludingMargin(false, rowSpan.max);
int cellWidth = x2 - x1;
int cellHeight = y2 - y1;
- int pWidth = getMeasurement(c, true, PRF);
- int pHeight = getMeasurement(c, false, PRF);
+ int pWidth = getMeasurement(c, true);
+ int pHeight = getMeasurement(c, false);
Alignment hAlign = columnGroup.alignment;
Alignment vAlign = rowGroup.alignment;
@@ -910,9 +901,8 @@
Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
- int type = PRF;
- int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(), type));
- int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(), type));
+ int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+ int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
if (mAlignmentMode == ALIGN_MARGINS) {
int leftMargin = getMargin(c, true, true);
@@ -925,8 +915,8 @@
int mHeight = topMargin + pHeight + bottomMargin;
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, type, mWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, type, mHeight);
+ int a2vx = colBounds.getOffset(c, hAlign, mWidth);
+ int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
dx = c2ax + a2vx + leftMargin;
dy = c2ay + a2vy + topMargin;
@@ -935,13 +925,14 @@
cellHeight -= topMargin + bottomMargin;
} else {
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, type, pWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, type, pHeight);
+ int a2vx = colBounds.getOffset(c, hAlign, pWidth);
+ int a2vy = rowBounds.getOffset(c, vAlign, pHeight);
dx = c2ax + a2vx;
dy = c2ay + a2vy;
}
+ int type = PRF;
int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
@@ -962,7 +953,7 @@
private class Axis {
private static final int MIN_VALUE = -1000000;
- private static final int UNVISITED = 0;
+ private static final int NEW = 0;
private static final int PENDING = 1;
private static final int COMPLETE = 2;
@@ -975,8 +966,11 @@
PackedMap<Group, Bounds> groupBounds;
public boolean groupBoundsValid = false;
- PackedMap<Interval, MutableInt> spanSizes;
- public boolean spanSizesValid = false;
+ PackedMap<Interval, MutableInt> forwardLinks;
+ public boolean forwardLinksValid = false;
+
+ PackedMap<Interval, MutableInt> backwardLinks;
+ public boolean backwardLinksValid = false;
public int[] leadingMargins;
public boolean leadingMarginsValid = false;
@@ -987,14 +981,14 @@
public Arc[] arcs;
public boolean arcsValid = false;
- public int[] minima;
- public boolean minimaValid = false;
-
- public float[] weights;
public int[] locations;
+ public boolean locationsValid = false;
private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED;
+ private MutableInt parentMin = new MutableInt(0);
+ private MutableInt parentMax = new MutableInt(-MAX_SIZE);
+
private Axis(boolean horizontal) {
this.horizontal = horizontal;
}
@@ -1036,22 +1030,19 @@
}
private PackedMap<Group, Bounds> createGroupBounds() {
- int N = getChildCount();
- Group[] groups = new Group[N];
- Arrays.fill(groups, Group.GONE);
- Bounds[] bounds = new Bounds[N];
- Arrays.fill(bounds, Bounds.GONE);
- for (int i = 0; i < N; i++) {
+ Assoc<Group, Bounds> assoc = Assoc.of(Group.class, Bounds.class);
+ for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
- LayoutParams lp = getLayoutParams(c);
- Group group = horizontal ? lp.columnGroup : lp.rowGroup;
-
- groups[i] = group;
- bounds[i] = group.alignment.getBounds();
+ if (isGone(c)) {
+ assoc.put(Group.GONE, Bounds.GONE);
+ } else {
+ LayoutParams lp = getLayoutParams(c);
+ Group group = horizontal ? lp.columnGroup : lp.rowGroup;
+ Bounds bounds = group.alignment.getBounds();
+ assoc.put(group, bounds);
+ }
}
-
- return new PackedMap<Group, Bounds>(groups, bounds);
+ return assoc.pack();
}
private void computeGroupBounds() {
@@ -1064,13 +1055,7 @@
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
Group g = horizontal ? lp.columnGroup : lp.rowGroup;
-
- Bounds bounds = groupBounds.getValue(i);
-
- int size = getMeasurementIncludingMargin(c, horizontal, PRF);
- // todo test this works correctly when the returned value is UNDEFINED
- int before = g.alignment.getAlignmentValue(c, size, PRF);
- bounds.include(before, size - before);
+ groupBounds.getValue(i).include(c, g, GridLayout.this, this, lp);
}
}
@@ -1086,80 +1071,91 @@
}
// Add values computed by alignment - taking the max of all alignments in each span
- private PackedMap<Interval, MutableInt> createSpanSizes() {
- PackedMap<Group, Bounds> groupBounds = getGroupBounds();
- int N = groupBounds.keys.length;
- Interval[] spans = new Interval[N];
- MutableInt[] values = new MutableInt[N];
- for (int i = 0; i < N; i++) {
- Interval key = groupBounds.keys[i].span;
-
- spans[i] = key;
- values[i] = new MutableInt();
+ private PackedMap<Interval, MutableInt> createLinks(boolean min) {
+ Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
+ Group[] keys = getGroupBounds().keys;
+ for (int i = 0, N = keys.length; i < N; i++) {
+ Interval span = min ? keys[i].span : keys[i].span.inverse();
+ result.put(span, new MutableInt());
}
- return new PackedMap<Interval, MutableInt>(spans, values);
+ return result.pack();
}
- private void computeSpanSizes() {
- MutableInt[] spans = spanSizes.values;
+ private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
+ MutableInt[] spans = links.values;
for (int i = 0; i < spans.length; i++) {
spans[i].reset();
}
- Bounds[] bounds = getGroupBounds().values; // use getter to trigger a re-evaluation
+ // use getter to trigger a re-evaluation
+ Bounds[] bounds = getGroupBounds().values;
for (int i = 0; i < bounds.length; i++) {
- int value = bounds[i].size();
-
- MutableInt valueHolder = spanSizes.getValue(i);
+ int size = bounds[i].size(min);
+ int value = min ? size : -size;
+ MutableInt valueHolder = links.getValue(i);
valueHolder.value = max(valueHolder.value, value);
}
}
- private PackedMap<Interval, MutableInt> getSpanSizes() {
- if (spanSizes == null) {
- spanSizes = createSpanSizes();
+ private PackedMap<Interval, MutableInt> getForwardLinks() {
+ if (forwardLinks == null) {
+ forwardLinks = createLinks(true);
}
- if (!spanSizesValid) {
- computeSpanSizes();
- spanSizesValid = true;
+ if (!forwardLinksValid) {
+ computeLinks(forwardLinks, true);
+ forwardLinksValid = true;
}
- return spanSizes;
+ return forwardLinks;
}
- private void include(List<Arc> arcs, Interval key, MutableInt size) {
+ private PackedMap<Interval, MutableInt> getBackwardLinks() {
+ if (backwardLinks == null) {
+ backwardLinks = createLinks(false);
+ }
+ if (!backwardLinksValid) {
+ computeLinks(backwardLinks, false);
+ backwardLinksValid = true;
+ }
+ return backwardLinks;
+ }
+
+ private void include(List<Arc> arcs, Interval key, MutableInt size,
+ boolean ignoreIfAlreadyPresent) {
+ /*
+ Remove self referential links.
+ These appear:
+ . as parental constraints when GridLayout has no children
+ . when components have been marked as GONE
+ */
+ if (key.size() == 0) {
+ return;
+ }
// this bit below should really be computed outside here -
- // its just to stop default (col>0) constraints obliterating valid entries
- for (Arc arc : arcs) {
- Interval span = arc.span;
- if (span.equals(key)) {
- return;
+ // its just to stop default (row/col > 0) constraints obliterating valid entries
+ if (ignoreIfAlreadyPresent) {
+ for (Arc arc : arcs) {
+ Interval span = arc.span;
+ if (span.equals(key)) {
+ return;
+ }
}
}
arcs.add(new Arc(key, size));
}
- private void include2(List<Arc> arcs, Interval span, MutableInt min, MutableInt max,
- boolean both) {
- include(arcs, span, min);
- if (both) {
- // todo
-// include(arcs, span.inverse(), max.neg());
- }
- }
-
- private void include2(List<Arc> arcs, Interval span, int min, int max, boolean both) {
- include2(arcs, span, new MutableInt(min), new MutableInt(max), both);
+ private void include(List<Arc> arcs, Interval key, MutableInt size) {
+ include(arcs, key, size, true);
}
// Group arcs by their first vertex, returning an array of arrays.
// This is linear in the number of arcs.
private Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
- int N = getCount() + 1;// the number of vertices
+ int N = getCount() + 1; // the number of vertices
Arc[][] result = new Arc[N][];
int[] sizes = new int[N];
for (Arc arc : arcs) {
sizes[arc.span.min]++;
- }
+ }
for (int i = 0; i < sizes.length; i++) {
result[i] = new Arc[sizes[i]];
}
@@ -1173,38 +1169,46 @@
return result;
}
- private Arc[] topologicalSort(final Arc[] arcs, int start) {
- // todo ensure the <start> vertex is added in edge cases
- final List<Arc> result = new ArrayList<Arc>();
- new Object() {
- Arc[][] arcsByFirstVertex = groupArcsByFirstVertex(arcs);
+ private Arc[] topologicalSort(final Arc[] arcs) {
+ return new Object() {
+ Arc[] result = new Arc[arcs.length];
+ int cursor = result.length - 1;
+ Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
int[] visited = new int[getCount() + 1];
- boolean completesCycle(int loc) {
- int state = visited[loc];
- if (state == UNVISITED) {
- visited[loc] = PENDING;
- for (Arc arc : arcsByFirstVertex[loc]) {
- Interval span = arc.span;
- // the recursive call
- if (completesCycle(span.max)) {
- // which arcs get set here is dependent on the order
- // in which we explore nodes
- arc.completesCycle = true;
+ void walk(int loc) {
+ switch (visited[loc]) {
+ case NEW: {
+ visited[loc] = PENDING;
+ for (Arc arc : arcsByVertex[loc]) {
+ walk(arc.span.max);
+ result[cursor--] = arc;
}
- result.add(arc);
+ visited[loc] = COMPLETE;
+ break;
}
- visited[loc] = COMPLETE;
- } else if (state == PENDING) {
- return true;
- } else if (state == COMPLETE) {
+ case PENDING: {
+ assert false;
+ break;
+ }
+ case COMPLETE: {
+ break;
+ }
}
- return false;
}
- }.completesCycle(start);
- Collections.reverse(result);
- assert arcs.length == result.size();
- return result.toArray(new Arc[result.size()]);
+
+ Arc[] sort() {
+ for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
+ walk(loc);
+ }
+ assert cursor == -1;
+ return result;
+ }
+ }.sort();
+ }
+
+ private Arc[] topologicalSort(List<Arc> arcs) {
+ return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
}
private boolean[] findUsed(Collection<Arc> arcs) {
@@ -1254,43 +1258,64 @@
return result;
}
- private Arc[] createArcs() {
- List<Arc> result = new ArrayList<Arc>();
-
- // Add all the preferred elements that were not defined by the user.
- PackedMap<Interval, MutableInt> spanSizes = getSpanSizes();
- for (int i = 0; i < spanSizes.keys.length; i++) {
- Interval key = spanSizes.keys[i];
- if (key == Interval.GONE) continue;
- MutableInt value = spanSizes.values[i];
- // todo remove value duplicate
- include2(result, key, value, value, accommodateBothMinAndMax);
+ private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
+ for (int i = 0; i < links.keys.length; i++) {
+ Interval key = links.keys[i];
+ include(result, key, links.values[i], false);
}
+ }
+
+ private Arc[] createArcs() {
+ List<Arc> mins = new ArrayList<Arc>();
+ List<Arc> maxs = new ArrayList<Arc>();
+
+ // Add the minimum values from the components.
+ addComponentSizes(mins, getForwardLinks());
+ // Add the maximum values from the components.
+ addComponentSizes(maxs, getBackwardLinks());
// Find redundant rows/cols and glue them together with 0-length arcs to link the tree
- boolean[] used = findUsed(result);
+ boolean[] used = findUsed(mins);
for (int i = 0; i < getCount(); i++) {
if (!used[i]) {
Interval span = new Interval(i, i + 1);
- include(result, span, new MutableInt(0));
- include(result, span.inverse(), new MutableInt(0));
+ include(mins, span, new MutableInt(0));
+ include(maxs, span.inverse(), new MutableInt(0));
}
}
+ // Add ordering constraints to prevent row/col sizes from going negative
if (mOrderPreserved) {
- // Add preferred gaps
+ // Add a constraint for every row/col
for (int i = 0; i < getCount(); i++) {
if (used[i]) {
- include2(result, new Interval(i, i + 1), 0, 0, false);
+ include(mins, new Interval(i, i + 1), new MutableInt(0));
}
}
} else {
+ // Add a constraint for each row/col that separates opposing component edges
for (Interval gap : getSpacers()) {
- include2(result, gap, 0, 0, false);
+ include(mins, gap, new MutableInt(0));
}
}
- Arc[] arcs = result.toArray(new Arc[result.size()]);
- return topologicalSort(arcs, 0);
+
+ // Add the container constraints. Use the version of include that allows
+ // duplicate entries in case a child spans the entire grid.
+ int N = getCount();
+ include(mins, new Interval(0, N), parentMin, false);
+ include(maxs, new Interval(N, 0), parentMax, false);
+
+ // Sort
+ Arc[] sMins = topologicalSort(mins);
+ Arc[] sMaxs = topologicalSort(maxs);
+
+ return append(sMins, sMaxs);
+ }
+
+ private void computeArcs() {
+ // getting the links validates the values that are shared by the arc list
+ getForwardLinks();
+ getBackwardLinks();
}
public Arc[] getArcs() {
@@ -1298,13 +1323,16 @@
arcs = createArcs();
}
if (!arcsValid) {
- getSpanSizes();
+ computeArcs();
arcsValid = true;
}
return arcs;
}
private boolean relax(int[] locations, Arc entry) {
+ if (!entry.valid) {
+ return false;
+ }
Interval span = entry.span;
int u = span.min;
int v = span.max;
@@ -1351,7 +1379,8 @@
typical layout problems complete after the first iteration and the algorithm
completes in O(N) steps with very low constants.
*/
- private int[] solve(Arc[] arcs, int[] locations) {
+ private void solve(Arc[] arcs, int[] locations) {
+ String axis = horizontal ? "horizontal" : "vertical";
int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
boolean changed = false;
@@ -1359,20 +1388,44 @@
for (int i = 0; i < N; i++) {
changed = false;
for (int j = 0, length = arcs.length; j < length; j++) {
- changed = changed | relax(locations, arcs[j]);
+ changed |= relax(locations, arcs[j]);
}
if (!changed) {
if (DEBUG) {
- Log.d(TAG, "Iteration " +
- " completed after " + (1 + i) + " steps out of " + N);
+ Log.d(TAG, axis + " iteration completed in " + (1 + i) + " steps of " + N);
}
+ return;
+ }
+ }
+
+ Log.d(TAG, "The " + axis + " constraints contained a contradiction. Resolving... ");
+ Log.d(TAG, Arrays.toString(arcs));
+
+ boolean[] culprits = new boolean[arcs.length];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0, length = arcs.length; j < length; j++) {
+ culprits[j] |= relax(locations, arcs[j]);
+ }
+ }
+ for (int i = 0; i < culprits.length; i++) {
+ if (culprits[i]) {
+ Arc arc = arcs[i];
+ // Only remove max values, min values alone cannot be inconsistent
+ if (arc.span.min < arc.span.max) {
+ continue;
+ }
+ Log.d(TAG, "Removing: " + arc);
+ arc.valid = false;
break;
}
}
- if (changed) {
- Log.d(TAG, "*** Algorithm failed to terminate ***");
- }
- return locations;
+ solve1(arcs, locations);
+ }
+
+ private void solve1(Arc[] arcs, int[] a) {
+ Arrays.fill(a, MIN_VALUE);
+ a[0] = 0;
+ solve(arcs, a);
}
private void computeMargins(boolean leading) {
@@ -1418,11 +1471,11 @@
for (int i = 0, N = getCount(); i < N; i++) {
int margins = leadingMargins[i] + trailingMargins[i + 1];
delta += margins;
- minima[i + 1] += delta;
+ locations[i + 1] += delta;
}
}
- private int getLocationIncludingMargin(View view, boolean leading, int index) {
+ private int getLocationIncludingMargin(boolean leading, int index) {
int location = locations[index];
int margin;
if (mAlignmentMode != ALIGN_MARGINS) {
@@ -1433,53 +1486,22 @@
return leading ? (location + margin) : (location - margin);
}
- private void computeMinima(int[] a) {
- Arrays.fill(a, MIN_VALUE);
- a[0] = 0;
- solve(getArcs(), a);
+ private void computeLocations(int[] a) {
+ solve1(getArcs(), a);
if (mAlignmentMode != ALIGN_MARGINS) {
addMargins();
}
}
- private int[] getMinima() {
- if (minima == null) {
- int N = getCount() + 1;
- minima = new int[N];
- }
- if (!minimaValid) {
- computeMinima(minima);
- minimaValid = true;
- }
- return minima;
- }
-
- private void computeWeights() {
- for (int i = 0, N = getChildCount(); i < N; i++) {
- View c = getChildAt(i);
- if (isGone(c)) continue;
- LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
- int penultimateIndex = span.max - 1;
- weights[penultimateIndex] += horizontal ? lp.columnWeight : lp.rowWeight;
- }
- }
-
- private float[] getWeights() {
- if (weights == null) {
- int N = getCount();
- weights = new float[N];
- }
- computeWeights();
- return weights;
- }
-
private int[] getLocations() {
if (locations == null) {
int N = getCount() + 1;
locations = new int[N];
}
+ if (!locationsValid) {
+ computeLocations(locations);
+ locationsValid = true;
+ }
return locations;
}
@@ -1489,48 +1511,53 @@
return max2(locations, 0) - locations[0];
}
- private int getMin() {
- return size(getMinima());
+ private void setParentConstraints(int min, int max) {
+ parentMin.value = min;
+ parentMax.value = -max;
+ locationsValid = false;
}
- private void layout(int targetSize) {
- int[] mins = getMinima();
+ private int getMeasure(int min, int max) {
+ setParentConstraints(min, max);
+ return size(getLocations());
+ }
- int totalDelta = max(0, targetSize - size(mins)); // confine to expansion
-
- float[] weights = getWeights();
- float totalWeight = sum(weights);
-
- if (totalWeight == 0f && weights.length > 0) {
- weights[weights.length - 1] = 1;
- totalWeight = 1;
+ private int getMeasure(int measureSpec) {
+ int mode = MeasureSpec.getMode(measureSpec);
+ int size = MeasureSpec.getSize(measureSpec);
+ switch (mode) {
+ case MeasureSpec.UNSPECIFIED: {
+ return getMeasure(0, MAX_SIZE);
+ }
+ case MeasureSpec.EXACTLY: {
+ return getMeasure(size, size);
+ }
+ case MeasureSpec.AT_MOST: {
+ return getMeasure(0, size);
+ }
+ default: {
+ assert false;
+ return 0;
+ }
}
+ }
- int[] locations = getLocations();
- int cumulativeDelta = 0;
-
- // note |weights| = |locations| - 1
- for (int i = 0; i < weights.length; i++) {
- float weight = weights[i];
- int delta = (int) (totalDelta * weight / totalWeight);
- cumulativeDelta += delta;
- locations[i + 1] = mins[i + 1] + cumulativeDelta;
-
- totalDelta -= delta;
- totalWeight -= weight;
- }
+ private void layout(int size) {
+ setParentConstraints(size, size);
+ getLocations();
}
private void invalidateStructure() {
countValid = false;
groupBounds = null;
- spanSizes = null;
+ forwardLinks = null;
+ backwardLinks = null;
+
leadingMargins = null;
trailingMargins = null;
arcs = null;
- minima = null;
- weights = null;
+
locations = null;
invalidateValues();
@@ -1538,11 +1565,14 @@
private void invalidateValues() {
groupBoundsValid = false;
- spanSizesValid = false;
- arcsValid = false;
+ forwardLinksValid = false;
+ backwardLinksValid = false;
+
leadingMarginsValid = false;
trailingMarginsValid = false;
- minimaValid = false;
+ arcsValid = false;
+
+ locationsValid = false;
}
}
@@ -1592,16 +1622,16 @@
* <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li>
* <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li>
* <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li>
- * <li>{@link #rowWeight} = {@code 0f} </li>
- * <li>{@link #columnWeight} = {@code 0f} </li>
+ * <li>{@link #widthSpec} = {@link #FIXED} </li>
+ * <li>{@link #heightSpec} = {@link #FIXED} </li>
* </ul>
*
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
- * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_heightSpec
* @attr ref android.R.styleable#GridLayout_Layout_layout_column
* @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
- * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_widthSpec
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
@@ -1621,14 +1651,15 @@
new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT);
private static final Group DEFAULT_ROW_GROUP =
new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT);
- private static final int DEFAULT_WEIGHT_0 = 0;
- private static final int DEFAULT_WEIGHT_1 = 1;
+ private static final Spec DEFAULT_SPEC = FIXED;
+ private static final int DEFAULT_SPEC_INDEX = 0;
// Misc
private static final Rect CONTAINER_BOUNDS = new Rect(0, 0, 2, 2);
private static final Alignment[] COLUMN_ALIGNMENTS = { LEFT, CENTER, RIGHT };
private static final Alignment[] ROW_ALIGNMENTS = { TOP, CENTER, BOTTOM };
+ private static final Spec[] SPECS = { FIXED, CAN_SHRINK, CAN_STRETCH };
// TypedArray indices
@@ -1641,10 +1672,10 @@
private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
- private static final int COLUMN_WEIGHT = styleable.GridLayout_Layout_layout_columnWeight;
+ private static final int WIDTH_SPEC = styleable.GridLayout_Layout_layout_widthSpec;
private static final int ROW = styleable.GridLayout_Layout_layout_row;
private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
- private static final int ROW_WEIGHT = styleable.GridLayout_Layout_layout_rowWeight;
+ private static final int HEIGHT_SPEC = styleable.GridLayout_Layout_layout_heightSpec;
private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
// Instance variables
@@ -1660,28 +1691,29 @@
*/
public Group columnGroup;
/**
- * The proportional space that should be taken by the associated row group
- * during excess space distribution.
- */
- public float rowWeight;
- /**
* The proportional space that should be taken by the associated column group
* during excess space distribution.
*/
- public float columnWeight;
+ public Spec widthSpec;
+ /**
+ * The proportional space that should be taken by the associated row group
+ * during excess space distribution.
+ */
+ public Spec heightSpec;
// Constructors
private LayoutParams(
int width, int height,
int left, int top, int right, int bottom,
- Group rowGroup, Group columnGroup, float rowWeight, float columnWeight) {
+ Group rowGroup, Group columnGroup,
+ Spec widthSpec, Spec heightSpec) {
super(width, height);
setMargins(left, top, right, bottom);
this.rowGroup = rowGroup;
this.columnGroup = columnGroup;
- this.rowWeight = rowWeight;
- this.columnWeight = columnWeight;
+ this.heightSpec = heightSpec;
+ this.widthSpec = widthSpec;
}
/**
@@ -1695,7 +1727,7 @@
public LayoutParams(Group rowGroup, Group columnGroup) {
this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
- rowGroup, columnGroup, DEFAULT_WEIGHT_0, DEFAULT_WEIGHT_0);
+ rowGroup, columnGroup, DEFAULT_SPEC, DEFAULT_SPEC);
}
/**
@@ -1728,8 +1760,8 @@
super(that);
this.columnGroup = that.columnGroup;
this.rowGroup = that.rowGroup;
- this.columnWeight = that.columnWeight;
- this.rowWeight = that.rowWeight;
+ this.widthSpec = that.widthSpec;
+ this.heightSpec = that.heightSpec;
}
// AttributeSet constructors
@@ -1813,11 +1845,6 @@
!definesVertical(gravity), defaultAlignment);
}
- private int getDefaultWeight(int size) {
- //return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0;
- return DEFAULT_WEIGHT_0;
- }
-
private void init(Context context, AttributeSet attrs, int defaultGravity) {
TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
try {
@@ -1827,13 +1854,13 @@
int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
Interval hSpan = new Interval(column, column + columnSpan);
this.columnGroup = new Group(hSpan, getColumnAlignment(gravity, width));
- this.columnWeight = a.getFloat(COLUMN_WEIGHT, getDefaultWeight(width));
+ this.widthSpec = SPECS[a.getInt(WIDTH_SPEC, DEFAULT_SPEC_INDEX)];
int row = a.getInt(ROW, DEFAULT_ROW);
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
Interval vSpan = new Interval(row, row + rowSpan);
this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height));
- this.rowWeight = a.getFloat(ROW_WEIGHT, getDefaultWeight(height));
+ this.heightSpec = SPECS[a.getInt(HEIGHT_SPEC, DEFAULT_SPEC_INDEX)];
} finally {
a.recycle();
}
@@ -1874,7 +1901,7 @@
private static class Arc {
public final Interval span;
public final MutableInt value;
- public boolean completesCycle;
+ public boolean valid = true;
public Arc(Interval span, MutableInt value) {
this.span = span;
@@ -1883,7 +1910,7 @@
@Override
public String toString() {
- return span + " " + (completesCycle ? "+>" : "->") + " " + value;
+ return span + " " + (!valid ? "+>" : "->") + " " + value;
}
}
@@ -1903,6 +1930,41 @@
private void reset() {
value = Integer.MIN_VALUE;
}
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+ }
+
+ private static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
+ private final Class<K> keyType;
+ private final Class<V> valueType;
+
+ private Assoc(Class<K> keyType, Class<V> valueType) {
+ this.keyType = keyType;
+ this.valueType = valueType;
+ }
+
+ private static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
+ return new Assoc<K, V>(keyType, valueType);
+ }
+
+ public void put(K key, V value) {
+ add(Pair.create(key, value));
+ }
+
+ @SuppressWarnings(value = "unchecked")
+ public PackedMap<K, V> pack() {
+ int N = size();
+ K[] keys = (K[]) Array.newInstance(keyType, N);
+ V[] values = (V[]) Array.newInstance(valueType, N);
+ for (int i = 0; i < N; i++) {
+ keys[i] = get(i).first;
+ values[i] = get(i).second;
+ }
+ return new PackedMap<K, V>(keys, values);
+ }
}
/*
@@ -1989,6 +2051,7 @@
public int before;
public int after;
+ public boolean canStretch;
private Bounds() {
reset();
@@ -1997,6 +2060,7 @@
protected void reset() {
before = Integer.MIN_VALUE;
after = Integer.MIN_VALUE;
+ canStretch = false;
}
protected void include(int before, int after) {
@@ -2004,12 +2068,26 @@
this.after = max(this.after, after);
}
- protected int size() {
+ protected int size(boolean min) {
+ if (!min && canStretch) {
+ return MAX_SIZE;
+ }
return before + after;
}
- protected int getOffset(View c, Alignment alignment, int type, int size) {
- return before - alignment.getAlignmentValue(c, size, type);
+ protected int getOffset(View c, Alignment alignment, int size) {
+ return before - alignment.getAlignmentValue(c, size);
+ }
+
+ protected void include(View c, Group g, GridLayout gridLayout, Axis axis, LayoutParams lp) {
+ Spec spec = axis.horizontal ? lp.widthSpec : lp.heightSpec;
+ if (spec == CAN_STRETCH) {
+ canStretch = true;
+ }
+ int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
+ // todo test this works correctly when the returned value is UNDEFINED
+ int before = g.alignment.getAlignmentValue(c, size);
+ include(before, size - before);
}
@Override
@@ -2032,7 +2110,7 @@
* Intervals are often written as {@code [min, max]} and represent the set of values
* {@code x} such that {@code min <= x < max}.
*/
- /* package */ static class Interval {
+ static class Interval {
private static final Interval GONE = new Interval(UNDEFINED, UNDEFINED);
/**
@@ -2129,7 +2207,7 @@
* See {@link GridLayout} for a description of the conventions used by GridLayout
* for grid indices.
*/
- /* package */ final Interval span;
+ final Interval span;
/**
* Specifies how cells should be aligned in this group.
* For row groups, this specifies the vertical alignment.
@@ -2147,7 +2225,7 @@
* @param span the span
* @param alignment the alignment
*/
- /* package */ Group(Interval span, Alignment alignment) {
+ Group(Interval span, Alignment alignment) {
this.span = span;
this.alignment = alignment;
}
@@ -2248,17 +2326,16 @@
* so that the locations defined by the alignment values
* are the same for all of the views in a group.
* <p>
-
*/
public static abstract class Alignment {
private static final Alignment GONE = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
assert false;
return 0;
}
};
- /*pp*/ Alignment() {
+ Alignment() {
}
/**
@@ -2269,12 +2346,9 @@
*
* @param view the view to which this alignment should be applied
* @param viewSize the measured size of the view
- * @param measurementType This parameter is currently unused as GridLayout only supports
- * one type of measurement: {@link View#measure(int, int)}.
- *
* @return the alignment value
*/
- /*pp*/ abstract int getAlignmentValue(View view, int viewSize, int measurementType);
+ abstract int getAlignmentValue(View view, int viewSize);
/**
* Returns the size of the view specified by this alignment.
@@ -2291,24 +2365,24 @@
*
* @return the aligned size
*/
- /*pp*/ int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+ int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
return viewSize;
}
- /*pp*/ Bounds getBounds() {
+ Bounds getBounds() {
return new Bounds();
}
}
private static final Alignment LEADING = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return 0;
}
};
private static final Alignment TRAILING = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return viewSize;
}
};
@@ -2343,7 +2417,7 @@
* LayoutParams#columnGroup columnGroups}.
*/
public static final Alignment CENTER = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return viewSize >> 1;
}
};
@@ -2356,7 +2430,7 @@
* @see View#getBaseline()
*/
public static final Alignment BASELINE = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
if (view == null) {
return UNDEFINED;
}
@@ -2378,7 +2452,7 @@
@Override
protected void reset() {
super.reset();
- size = 0;
+ size = Integer.MIN_VALUE;
}
@Override
@@ -2388,13 +2462,13 @@
}
@Override
- protected int size() {
- return max(super.size(), size);
+ protected int size(boolean min) {
+ return max(super.size(min), size);
}
@Override
- protected int getOffset(View c, Alignment alignment, int type, int size) {
- return max(0, super.getOffset(c, alignment, type, size));
+ protected int getOffset(View c, Alignment alignment, int size) {
+ return max(0, super.getOffset(c, alignment, size));
}
};
}
@@ -2406,7 +2480,7 @@
* {@link LayoutParams#columnGroup columnGroups}.
*/
public static final Alignment FILL = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
@@ -2415,4 +2489,41 @@
return cellSize;
}
};
+
+ /**
+ * Spec's tell GridLayout how to derive minimum and maximum size values for a
+ * component. Specifications are made with respect to a child's 'measured size'.
+ * A child's measured size is, in turn, controlled by its height and width
+ * layout parameters which either specify a size or, in the case of
+ * WRAP_CONTENT, defer to the computed size of the component.
+ */
+ public static abstract class Spec {
+ }
+
+ /**
+ * Indicates that a view requests precisely the size specified by its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec FIXED = new Spec() {
+ };
+
+ /**
+ * Indicates that a view's size should lie between its minimum and the size specified by
+ * its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec CAN_SHRINK = new Spec() {
+ };
+
+ /**
+ * Indicates that a view's size should be greater than or equal to the size specified by
+ * its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec CAN_STRETCH = new Spec() {
+ };
+
}
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 8ba08f6..30df91b 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -156,7 +156,7 @@
/>
<!-- Column 1 -->
- <Space android:layout_columnWeight="1" android:layout_rowSpan="11" />
+ <Space android:layout_widthSpec="canStretch" android:layout_rowSpan="11" />
<!-- Column 2 - password entry field and PIN keyboard -->
<LinearLayout
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 5588adc..c859720 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -169,7 +169,10 @@
</LinearLayout>
<!-- Column 1 -->
- <Space android:width="20dip" android:layout_columnWeight="1" android:layout_rowSpan="10" />
+ <Space
+ android:width="20dip"
+ android:layout_heightSpec="canStretch"
+ android:layout_rowSpan="10" />
<!-- Column 2 -->
<com.android.internal.widget.multiwaveview.MultiWaveView
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index d0538dd..0070ed0 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -100,9 +100,11 @@
<!-- TODO: remove hard coded height since layout_rowWeight doesn't seem to be working -->
<Space
- android:layout_height="43dip"
- android:layout_gravity="fill"
- android:layout_rowWeight="1" android:layout_columnWeight="1" />
+ android:layout_height="43dip"
+ android:layout_gravity="fill"
+ android:layout_heightSpec="canStretch"
+ android:layout_widthSpec="canStretch"
+ />
<TextView android:id="@+id/carrier"
android:layout_gravity="right"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 774f830..28c5302 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -125,7 +125,7 @@
android:layout_marginBottom="4dip"
android:layout_marginLeft="8dip"
android:layout_gravity="center|bottom"
- android:layout_rowWeight="1"
+ android:layout_heightSpec="canStretch"
/>
<TextView
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 475aa59..fee27eb 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -54,8 +54,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip"
android:orientation="horizontal">
@@ -87,7 +87,6 @@
android:layout_gravity="bottom"
android:paddingLeft="8dip"
android:paddingRight="6dip"
- android:drawablePadding="2dip"
android:singleLine="true"
android:ellipsize="end"
android:background="@null"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db33d1c..e3887fe 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3324,11 +3324,6 @@
The default is one.
See {@link android.widget.GridLayout.Group}. -->
<attr name="layout_rowSpan" format="integer" min="1" />
- <!-- A number indicating the relative proportion of available space that
- should be taken by this group of cells.
- The default is zero.
- See {@link android.widget.GridLayout.LayoutParams#columnWeight}. -->
- <attr name="layout_rowWeight" format="float" />
<!-- The column boundary delimiting the left of the group of cells
occupied by this view. -->
<attr name="layout_column" />
@@ -3337,15 +3332,38 @@
The default is one.
See {@link android.widget.GridLayout.Group}. -->
<attr name="layout_columnSpan" format="integer" min="1" />
- <!-- A number indicating the relative proportion of available space that
- should be taken by this group of cells.
- The default is zero.
- See {@link android.widget.GridLayout.LayoutParams#columnWeight}.-->
- <attr name="layout_columnWeight" format="float" />
<!-- Gravity specifies how a component should be placed in its group of cells.
The default is LEFT | BASELINE.
See {@link android.widget.GridLayout.LayoutParams#setGravity(int)}. -->
<attr name="layout_gravity" />
+ <!-- A value specifying how much deficit or excess width this component can accomodate.
+ The default is FIXED.
+ See {@link android.widget.GridLayout.LayoutParams#widthSpec}.-->
+ <attr name="layout_widthSpec" >
+ <!-- If possible, width should be exactly as specified.
+ See {@link android.widget.GridLayout#FIXED}. -->
+ <enum name="fixed" value="0" />
+ <!-- If possible, width should be less than or equal to the specified width.
+ See {@link android.widget.GridLayout#CAN_SHRINK}. -->
+ <enum name="canShrink" value="1" />
+ <!-- If possible, width should be greater than or equal to the specified width.
+ See {@link android.widget.GridLayout#CAN_STRETCH}. -->
+ <enum name="canStretch" value="2" />
+ </attr>
+ <!-- A value specifying how much deficit or excess height this component can accomodate.
+ The default is FIXED.
+ See {@link android.widget.GridLayout.LayoutParams#heightSpec}.-->
+ <attr name="layout_heightSpec" >
+ <!-- If possible, height should be exactly as specified.
+ See {@link android.widget.GridLayout#FIXED}. -->
+ <enum name="fixed" value="0" />
+ <!-- If possible, height should be less than or equal to the specified height.
+ See {@link android.widget.GridLayout#CAN_SHRINK}. -->
+ <enum name="canShrink" value="1" />
+ <!-- If possible, height should be greater than or equal to the specified height.
+ See {@link android.widget.GridLayout#CAN_STRETCH}. -->
+ <enum name="canStretch" value="2" />
+ </attr>
</declare-styleable>
<declare-styleable name="FrameLayout_Layout">
<attr name="layout_gravity" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index db6f98f..945e0c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1738,9 +1738,11 @@
<public type="attr" name="layout_row" />
<public type="attr" name="layout_rowSpan" />
- <public type="attr" name="layout_rowWeight" />
<public type="attr" name="layout_columnSpan" />
- <public type="attr" name="layout_columnWeight" />
+
+ <public type="attr" name="layout_widthSpec" />
+ <public type="attr" name="layout_heightSpec" />
+
<public type="attr" name="actionModeSelectAllDrawable" />
<public type="attr" name="isAuxiliary" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3b85702..c8b3b4f 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2073,6 +2073,18 @@
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_fax_re">fax<!-- fr-FR -->|télécopie|telecopie<!-- ja-JP -->|ファックス<!-- ru -->|факс<!-- zh-CN -->|传真<!-- zh-TW -->|傳真</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_country_code_re">country.*code|ccode|_cc</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_area_code_notext_re">^\($</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_prefix_separator_re">^-$|^\)$</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_suffix_separator_re">^-$</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index a31395e..37dbcd8 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -22,6 +22,7 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
+#include <utils/Vector.h>
namespace android {
@@ -99,6 +100,15 @@
return ERROR_UNSUPPORTED;
}
+ // The consumer of this media source requests that the given buffers
+ // are to be returned exclusively in response to read calls.
+ // This will be called after a successful start() and before the
+ // first read() call.
+ // Callee assumes ownership of the buffers if no error is returned.
+ virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) {
+ return ERROR_UNSUPPORTED;
+ }
+
protected:
virtual ~MediaSource();
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 99b72ad..57f678c 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -121,6 +121,8 @@
// To store the timed text format data
kKeyTextFormatData = 'text', // raw data
+
+ kKeyRequiresSecureBuffers = 'secu', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 92331a1..7f3c497 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -53,6 +53,9 @@
// Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
kEnableGrallocUsageProtected = 128,
+
+ // Secure decoding mode
+ kUseSecureInputBuffers = 256,
};
static sp<MediaSource> Create(
const sp<IOMX> &omx,
@@ -164,6 +167,10 @@
bool mOMXLivesLocally;
IOMX::node_id mNode;
uint32_t mQuirks;
+
+ // Flags specified in the creation of the codec.
+ uint32_t mFlags;
+
bool mIsEncoder;
char *mMIME;
char *mComponentName;
@@ -205,15 +212,12 @@
List<size_t> mFilledBuffers;
Condition mBufferFilled;
- bool mIsMetaDataStoredInVideoBuffers;
- 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,
+ OMXCodec(const sp<IOMX> &omx, IOMX::node_id node,
+ uint32_t quirks, uint32_t flags,
bool isEncoder, const char *mime, const char *componentName,
const sp<MediaSource> &source,
const sp<ANativeWindow> &nativeWindow);
@@ -287,6 +291,10 @@
void drainInputBuffers();
void fillOutputBuffers();
+ bool drainAnyInputBuffer();
+ BufferInfo *findInputBufferByDataPointer(void *ptr);
+ BufferInfo *findEmptyInputBuffer();
+
// Returns true iff a flush was initiated and a completion event is
// upcoming, false otherwise (A flush was not necessary as we own all
// the buffers on that port).
@@ -313,7 +321,7 @@
void dumpPortStatus(OMX_U32 portIndex);
- status_t configureCodec(const sp<MetaData> &meta, uint32_t flags);
+ status_t configureCodec(const sp<MetaData> &meta);
static uint32_t getComponentQuirks(
const char *componentName, bool isEncoder);
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index ffc3346..29dec63 100755
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -205,7 +205,7 @@
mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
}
- mNiNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ mNiNotification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_AUTO_CANCEL;
mNiNotification.tickerText = getNotifTicker(notif, mContext);
// if not to popup dialog immediately, pending intent will open the dialog
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index e36b01f..1ac2c1f 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -477,6 +477,15 @@
const char *matchComponentName,
uint32_t flags,
const sp<ANativeWindow> &nativeWindow) {
+ int32_t requiresSecureBuffers;
+ if (source->getFormat()->findInt32(
+ kKeyRequiresSecureBuffers,
+ &requiresSecureBuffers)
+ && requiresSecureBuffers) {
+ flags |= kIgnoreCodecSpecificData;
+ flags |= kUseSecureInputBuffers;
+ }
+
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
CHECK(success);
@@ -530,17 +539,17 @@
LOGV("Successfully allocated OMX node '%s'", componentName);
sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks,
+ omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);
observer->setCodec(codec);
- err = codec->configureCodec(meta, flags);
+ err = codec->configureCodec(meta);
if (err == OK) {
if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
- codec->mOnlySubmitOneBufferAtOneTime = true;
+ codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
}
return codec;
@@ -553,24 +562,11 @@
return NULL;
}
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
- mIsMetaDataStoredInVideoBuffers = false;
- if (flags & kStoreMetaDataInVideoBuffers) {
- mIsMetaDataStoredInVideoBuffers = true;
- }
+status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
+ LOGV("configureCodec protected=%d",
+ (mFlags & kEnableGrallocUsageProtected) ? 1 : 0);
- mOnlySubmitOneBufferAtOneTime = false;
- if (flags & kOnlySubmitOneInputBufferAtOneTime) {
- mOnlySubmitOneBufferAtOneTime = true;
- }
-
- mEnableGrallocUsageProtected = false;
- if (flags & kEnableGrallocUsageProtected) {
- mEnableGrallocUsageProtected = true;
- }
- LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
-
- if (!(flags & kIgnoreCodecSpecificData)) {
+ if (!(mFlags & kIgnoreCodecSpecificData)) {
uint32_t type;
const void *data;
size_t size;
@@ -745,7 +741,7 @@
initOutputFormat(meta);
- if ((flags & kClientNeedsFramebuffer)
+ if ((mFlags & kClientNeedsFramebuffer)
&& !strncmp(mComponentName, "OMX.SEC.", 8)) {
OMX_INDEXTYPE index;
@@ -1468,7 +1464,8 @@
}
OMXCodec::OMXCodec(
- const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ const sp<IOMX> &omx, IOMX::node_id node,
+ uint32_t quirks, uint32_t flags,
bool isEncoder,
const char *mime,
const char *componentName,
@@ -1478,6 +1475,7 @@
mOMXLivesLocally(omx->livesLocally(getpid())),
mNode(node),
mQuirks(quirks),
+ mFlags(flags),
mIsEncoder(isEncoder),
mMIME(strdup(mime)),
mComponentName(strdup(componentName)),
@@ -1645,13 +1643,14 @@
return allocateOutputBuffersFromNativeWindow();
}
- if (mEnableGrallocUsageProtected && portIndex == kPortIndexOutput) {
+ if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {
LOGE("protected output buffers must be stent to an ANativeWindow");
return PERMISSION_DENIED;
}
status_t err = OK;
- if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) {
+ if ((mFlags & kStoreMetaDataInVideoBuffers)
+ && portIndex == kPortIndexInput) {
err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
if (err != OK) {
LOGE("Storing meta data in video buffers is not supported");
@@ -1687,7 +1686,8 @@
IOMX::buffer_id buffer;
if (portIndex == kPortIndexInput
- && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+ && ((mQuirks & kRequiresAllocateBufferOnInputPorts)
+ || (mFlags & kUseSecureInputBuffers))) {
if (mOMXLivesLocally) {
mem.clear();
@@ -1748,6 +1748,31 @@
// dumpPortStatus(portIndex);
+ if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
+ Vector<MediaBuffer *> buffers;
+ for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+ const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);
+
+ MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);
+ buffers.push(mbuf);
+ }
+
+ status_t err = mSource->setBuffers(buffers);
+
+ if (err != OK) {
+ for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+ buffers.editItemAt(i)->release();
+ }
+ buffers.clear();
+
+ CODEC_LOGE(
+ "Codec requested to use secure input buffers but "
+ "upstream source didn't support that.");
+
+ return err;
+ }
+ }
+
return OK;
}
@@ -1815,7 +1840,7 @@
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
- if (mEnableGrallocUsageProtected) {
+ if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
}
@@ -2067,7 +2092,12 @@
} else if (mState != ERROR
&& mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED);
- drainInputBuffer(&buffers->editItemAt(i));
+
+ if (mFlags & kUseSecureInputBuffers) {
+ drainAnyInputBuffer();
+ } else {
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
}
break;
}
@@ -2804,32 +2834,81 @@
void OMXCodec::drainInputBuffers() {
CHECK(mState == EXECUTING || mState == RECONFIGURING);
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- BufferInfo *info = &buffers->editItemAt(i);
-
- if (info->mStatus != OWNED_BY_US) {
- continue;
+ if (mFlags & kUseSecureInputBuffers) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if (!drainAnyInputBuffer()
+ || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) {
+ break;
+ }
}
+ } else {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ BufferInfo *info = &buffers->editItemAt(i);
- if (!drainInputBuffer(info)) {
- break;
- }
+ if (info->mStatus != OWNED_BY_US) {
+ continue;
+ }
- if (mOnlySubmitOneBufferAtOneTime) {
- break;
+ if (!drainInputBuffer(info)) {
+ break;
+ }
+
+ if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
+ break;
+ }
}
}
}
+bool OMXCodec::drainAnyInputBuffer() {
+ return drainInputBuffer((BufferInfo *)NULL);
+}
+
+OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) {
+ Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < infos->size(); ++i) {
+ BufferInfo *info = &infos->editItemAt(i);
+
+ if (info->mData == ptr) {
+ CODEC_LOGV(
+ "input buffer data ptr = %p, buffer_id = %p",
+ ptr,
+ info->mBuffer);
+
+ return info;
+ }
+ }
+
+ TRESPASS();
+}
+
+OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() {
+ Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < infos->size(); ++i) {
+ BufferInfo *info = &infos->editItemAt(i);
+
+ if (info->mStatus == OWNED_BY_US) {
+ return info;
+ }
+ }
+
+ TRESPASS();
+}
+
bool OMXCodec::drainInputBuffer(BufferInfo *info) {
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+ if (info != NULL) {
+ CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+ }
if (mSignalledEOS) {
return false;
}
if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+ CHECK(!(mFlags & kUseSecureInputBuffers));
+
const CodecSpecificData *specific =
mCodecSpecificData[mCodecSpecificDataIndex];
@@ -2925,6 +3004,11 @@
break;
}
+ if (mFlags & kUseSecureInputBuffers) {
+ info = findInputBufferByDataPointer(srcBuffer->data());
+ CHECK(info != NULL);
+ }
+
size_t remainingBytes = info->mSize - offset;
if (srcBuffer->range_length() > remainingBytes) {
@@ -2960,14 +3044,24 @@
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
} else {
- if (mIsMetaDataStoredInVideoBuffers) {
+ if (mFlags & kStoreMetaDataInVideoBuffers) {
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
}
- memcpy((uint8_t *)info->mData + offset,
- (const uint8_t *)srcBuffer->data()
- + srcBuffer->range_offset(),
- srcBuffer->range_length());
+
+ if (mFlags & kUseSecureInputBuffers) {
+ // Data in "info" is already provided at this time.
+
+ releaseBuffer = false;
+
+ CHECK(info->mMediaBuffer == NULL);
+ info->mMediaBuffer = srcBuffer;
+ } else {
+ memcpy((uint8_t *)info->mData + offset,
+ (const uint8_t *)srcBuffer->data()
+ + srcBuffer->range_offset(),
+ srcBuffer->range_length());
+ }
}
int64_t lastBufferTimeUs;
@@ -3036,6 +3130,16 @@
info->mBuffer, offset,
timestampUs, timestampUs / 1E6);
+ if (info == NULL) {
+ CHECK(mFlags & kUseSecureInputBuffers);
+ CHECK(signalEOS);
+
+ // This is fishy, there's still a MediaBuffer corresponding to this
+ // info available to the source at this point even though we're going
+ // to use it to signal EOS to the codec.
+ info = findEmptyInputBuffer();
+ }
+
err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, offset,
flags, timestampUs);
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 7072d58..26eda0c 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -33,25 +33,26 @@
#include <utils/Errors.h>
+/* The extractor lifetime is short - just long enough to get
+ * the media sources constructed - so the shared lib needs to remain open
+ * beyond the lifetime of the extractor. So keep the handle as a global
+ * rather than a member of the extractor
+ */
+void *gVendorLibHandle = NULL;
+
namespace android {
-Mutex WVMExtractor::sMutex;
-uint32_t WVMExtractor::sActiveExtractors = 0;
-void *WVMExtractor::sVendorLibHandle = NULL;
+static Mutex gWVMutex;
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
: mDataSource(source) {
{
- Mutex::Autolock autoLock(sMutex);
-
- if (sVendorLibHandle == NULL) {
- CHECK(sActiveExtractors == 0);
- sVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
+ Mutex::Autolock autoLock(gWVMutex);
+ if (gVendorLibHandle == NULL) {
+ gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
}
- sActiveExtractors++;
-
- if (sVendorLibHandle == NULL) {
+ if (gVendorLibHandle == NULL) {
LOGE("Failed to open libwvm.so");
return;
}
@@ -59,7 +60,7 @@
typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
GetInstanceFunc getInstanceFunc =
- (GetInstanceFunc) dlsym(sVendorLibHandle,
+ (GetInstanceFunc) dlsym(gVendorLibHandle,
"_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
if (getInstanceFunc) {
@@ -71,17 +72,6 @@
}
WVMExtractor::~WVMExtractor() {
- Mutex::Autolock autoLock(sMutex);
-
- CHECK(sActiveExtractors > 0);
- sActiveExtractors--;
-
- // Close lib after last use
- if (sActiveExtractors == 0) {
- if (sVendorLibHandle != NULL)
- dlclose(sVendorLibHandle);
- sVendorLibHandle = NULL;
- }
}
size_t WVMExtractor::countTracks() {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 967f126..f4b3668 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -115,31 +115,31 @@
mUserAgent = ua.c_str();
- net_log_ = new SfNetLog;
+ set_net_log(new SfNetLog());
- host_resolver_ =
+ set_host_resolver(
net::CreateSystemHostResolver(
net::HostResolver::kDefaultParallelism,
NULL /* resolver_proc */,
- net_log_);
+ net_log()));
- ssl_config_service_ =
- net::SSLConfigService::CreateSystemSSLConfigService();
+ set_ssl_config_service(
+ net::SSLConfigService::CreateSystemSSLConfigService());
- proxy_service_ = net::ProxyService::CreateWithoutProxyResolver(
- new net::ProxyConfigServiceAndroid, net_log_);
+ set_proxy_service(net::ProxyService::CreateWithoutProxyResolver(
+ new net::ProxyConfigServiceAndroid, net_log()));
- http_transaction_factory_ = new net::HttpCache(
- host_resolver_,
+ set_http_transaction_factory(new net::HttpCache(
+ host_resolver(),
new net::CertVerifier(),
- dnsrr_resolver_,
- dns_cert_checker_.get(),
- proxy_service_.get(),
- ssl_config_service_.get(),
- net::HttpAuthHandlerFactory::CreateDefault(host_resolver_),
- network_delegate_,
- net_log_,
- NULL); // backend_factory
+ dnsrr_resolver(),
+ dns_cert_checker(),
+ proxy_service(),
+ ssl_config_service(),
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver()),
+ network_delegate(),
+ net_log(),
+ NULL)); // backend_factory
}
const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e3292e6..0096760 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -475,7 +475,9 @@
}
status_t err = mSource->read(&mInputBuffer, options);
if (err != OK) {
- LOGE("Failed to read input video frame: %d", err);
+ if (err != ERROR_END_OF_STREAM) {
+ LOGE("Failed to read input video frame: %d", err);
+ }
outputBuffer->release();
return err;
}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index 15ed219..d7249c1 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -398,10 +398,13 @@
}
// Ready for accepting an input video frame
- if (OK != mSource->read(&mInputBuffer, options)) {
- LOGE("Failed to read from data source");
+ status_t err = mSource->read(&mInputBuffer, options);
+ if (OK != err) {
+ if (err != ERROR_END_OF_STREAM) {
+ LOGE("Failed to read from data source");
+ }
outputBuffer->release();
- return UNKNOWN_ERROR;
+ return err;
}
if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) {
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 0817bab..deecd25 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -18,7 +18,6 @@
#define WVM_EXTRACTOR_H_
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaExtractor.h>
#include <utils/Errors.h>
@@ -68,10 +67,6 @@
WVMExtractor(const WVMExtractor &);
WVMExtractor &operator=(const WVMExtractor &);
-
- static Mutex sMutex;
- static uint32_t sActiveExtractors;
- static void *sVendorLibHandle;
};
} // namespace android
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6d8eab6..f42cbbf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,11 @@
android:exported="true"
/>
+ <!-- started from PhoneWindowManager
+ TODO: Should have an android:permission attribute -->
+ <service android:name=".screenshot.TakeScreenshotService"
+ android:exported="false" />
+
<activity android:name=".usb.UsbPreferenceActivity"
android:theme="@*android:style/Theme.Holo.Dialog.Alert"
android:excludeFromRecents="true">
diff --git a/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
new file mode 100644
index 0000000..e14111d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
new file mode 100644
index 0000000..e14111d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
new file mode 100644
index 0000000..6cb8799
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView android:id="@+id/global_screenshot_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#FF000000"
+ android:visibility="gone" />
+ <FrameLayout
+ android:id="@+id/global_screenshot_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/global_screenshot_background"
+ android:visibility="gone">
+ <ImageView android:id="@+id/global_screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true" />
+ </FrameLayout>
+ <ImageView android:id="@+id/global_screenshot_flash"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#FFFFFFFF"
+ android:visibility="gone" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86e0cd0..70f9b75 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -165,4 +165,9 @@
<string name="use_ptp_button_title">Mount as a camera (PTP)</string>
<!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
<string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
+
+ <!-- toast message displayed when a screenshot is saved to the Gallery. -->
+ <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
+ <!-- toast message displayed when we fail to take a screenshot. -->
+ <string name="screenshot_failed_toast">Could not save screenshot</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
new file mode 100644
index 0000000..83a5578
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -0,0 +1,384 @@
+/*
+ * 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.screenshot;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.ServiceManager;
+import android.provider.MediaStore;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.Thread;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * POD used in the AsyncTask which saves an image in the background.
+ */
+class SaveImageInBackgroundData {
+ Context context;
+ Bitmap image;
+ int result;
+}
+
+/**
+ * An AsyncTask that saves an image to the media store in the background.
+ */
+class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
+ SaveImageInBackgroundData> {
+ private static final String TAG = "SaveImageInBackgroundTask";
+ private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
+ private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/Screenshot_%s-%d.png";
+
+ @Override
+ protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
+ if (params.length != 1) return null;
+
+ Context context = params[0].context;
+ Bitmap image = params[0].image;
+
+ try{
+ long currentTime = System.currentTimeMillis();
+ String date = new SimpleDateFormat("MM-dd-yy-kk-mm-ss").format(new Date(currentTime));
+ String imageDir = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES).getAbsolutePath();
+ String imageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE,
+ imageDir, SCREENSHOTS_DIR_NAME,
+ date, currentTime % 1000);
+
+ // Save the screenshot to the MediaStore
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.ImageColumns.DATA, imageFilePath);
+ values.put(MediaStore.Images.ImageColumns.TITLE, "Screenshot");
+ values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "Screenshot");
+ values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, currentTime);
+ values.put(MediaStore.Images.ImageColumns.DATE_ADDED, currentTime);
+ values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, currentTime);
+ values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
+ Uri uri = context.getContentResolver().insert(
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+
+ OutputStream out = context.getContentResolver().openOutputStream(uri);
+ image.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+
+ params[0].result = 0;
+ }catch(IOException e){
+ params[0].result = 1;
+ }
+
+ return params[0];
+ };
+
+ @Override
+ protected void onPostExecute(SaveImageInBackgroundData params) {
+ if (params.result > 0) {
+ // Show a message that we've failed to save the image to disk
+ Toast.makeText(params.context, R.string.screenshot_failed_toast,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // Show a message that we've saved the screenshot to disk
+ Toast.makeText(params.context, R.string.screenshot_saving_toast,
+ Toast.LENGTH_SHORT).show();
+ }
+ };
+}
+
+/**
+ * TODO:
+ * - Performance when over gl surfaces? Ie. Gallery
+ * - what do we say in the Toast? Which icon do we get if the user uses another
+ * type of gallery?
+ */
+class GlobalScreenshot {
+ private static final String TAG = "GlobalScreenshot";
+ private static final int SCREENSHOT_FADE_IN_DURATION = 900;
+ private static final int SCREENSHOT_FADE_OUT_DELAY = 1000;
+ private static final int SCREENSHOT_FADE_OUT_DURATION = 450;
+ private static final int TOAST_FADE_IN_DURATION = 500;
+ private static final int TOAST_FADE_OUT_DELAY = 1000;
+ private static final int TOAST_FADE_OUT_DURATION = 500;
+ private static final float BACKGROUND_ALPHA = 0.65f;
+ private static final float SCREENSHOT_SCALE = 0.85f;
+ private static final float SCREENSHOT_MIN_SCALE = 0.7f;
+ private static final float SCREENSHOT_ROTATION = -6.75f; // -12.5f;
+
+ private Context mContext;
+ private LayoutInflater mLayoutInflater;
+ private IWindowManager mIWindowManager;
+ private WindowManager mWindowManager;
+ private WindowManager.LayoutParams mWindowLayoutParams;
+ private Display mDisplay;
+ private DisplayMetrics mDisplayMetrics;
+ private Matrix mDisplayMatrix;
+
+ private Bitmap mScreenBitmap;
+ private View mScreenshotLayout;
+ private ImageView mBackgroundView;
+ private FrameLayout mScreenshotContainerView;
+ private ImageView mScreenshotView;
+
+ private AnimatorSet mScreenshotAnimation;
+
+ // General use cubic interpolator
+ final TimeInterpolator mCubicInterpolator = new TimeInterpolator() {
+ public float getInterpolation(float t) {
+ return t*t*t;
+ }
+ };
+ // The interpolator used to control the background alpha at the start of the animation
+ final TimeInterpolator mBackgroundViewAlphaInterpolator = new TimeInterpolator() {
+ public float getInterpolation(float t) {
+ float tStep = 0.35f;
+ if (t < tStep) {
+ return t * (1f / tStep);
+ } else {
+ return 1f;
+ }
+ }
+ };
+
+ /**
+ * @param context everything needs a context :(
+ */
+ public GlobalScreenshot(Context context) {
+ mContext = context;
+ mLayoutInflater = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ // Inflate the screenshot layout
+ mDisplayMetrics = new DisplayMetrics();
+ mDisplayMatrix = new Matrix();
+ mScreenshotLayout = mLayoutInflater.inflate(R.layout.global_screenshot, null);
+ mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+ mScreenshotContainerView = (FrameLayout) mScreenshotLayout.findViewById(R.id.global_screenshot_container);
+ mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
+ mScreenshotLayout.setFocusable(true);
+ mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // Intercept and ignore all touch events
+ return true;
+ }
+ });
+
+ // Setup the window that we are going to use
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ mWindowLayoutParams = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
+ WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
+ | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+ PixelFormat.TRANSLUCENT);
+ mWindowLayoutParams.token = new Binder();
+ mWindowLayoutParams.setTitle("ScreenshotAnimation");
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mDisplay = mWindowManager.getDefaultDisplay();
+ }
+
+ /**
+ * Creates a new worker thread and saves the screenshot to the media store.
+ */
+ private void saveScreenshotInWorkerThread() {
+ SaveImageInBackgroundData data = new SaveImageInBackgroundData();
+ data.context = mContext;
+ data.image = mScreenBitmap;
+ new SaveImageInBackgroundTask().execute(data);
+ }
+
+ /**
+ * @return the current display rotation in degrees
+ */
+ private float getDegreesForRotation(int value) {
+ switch (value) {
+ case Surface.ROTATION_90:
+ return 90f;
+ case Surface.ROTATION_180:
+ return 180f;
+ case Surface.ROTATION_270:
+ return 270f;
+ }
+ return 0f;
+ }
+
+ /**
+ * Takes a screenshot of the current display and shows an animation.
+ */
+ void takeScreenshot() {
+ // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
+ // only in the natural orientation of the device :!)
+ mDisplay.getRealMetrics(mDisplayMetrics);
+ float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
+ float degrees = getDegreesForRotation(mDisplay.getRotation());
+ boolean requiresRotation = (degrees > 0);
+ if (requiresRotation) {
+ // Get the dimensions of the device in its native orientation
+ mDisplayMatrix.reset();
+ mDisplayMatrix.preRotate(-degrees);
+ mDisplayMatrix.mapPoints(dims);
+ dims[0] = Math.abs(dims[0]);
+ dims[1] = Math.abs(dims[1]);
+ }
+ mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
+ if (requiresRotation) {
+ // Rotate the screenshot to the current orientation
+ Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
+ mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(ss);
+ c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
+ c.rotate(360f - degrees);
+ c.translate(-dims[0] / 2, -dims[1] / 2);
+ c.drawBitmap(mScreenBitmap, 0, 0, null);
+ mScreenBitmap = ss;
+ }
+
+ // If we couldn't take the screenshot, notify the user
+ if (mScreenBitmap == null) {
+ Toast.makeText(mContext, R.string.screenshot_failed_toast,
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Start the post-screenshot animation
+ startAnimation();
+ }
+
+
+ /**
+ * Starts the animation after taking the screenshot
+ */
+ private void startAnimation() {
+ // Add the view for the animation
+ mScreenshotView.setImageBitmap(mScreenBitmap);
+ mScreenshotLayout.requestFocus();
+
+ // Setup the animation with the screenshot just taken
+ if (mScreenshotAnimation != null) {
+ mScreenshotAnimation.end();
+ }
+
+ mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ ValueAnimator screenshotFadeInAnim = createScreenshotFadeInAnimation();
+ ValueAnimator screenshotFadeOutAnim = createScreenshotFadeOutAnimation();
+ mScreenshotAnimation = new AnimatorSet();
+ mScreenshotAnimation.play(screenshotFadeInAnim).before(screenshotFadeOutAnim);
+ mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Save the screenshot once we have a bit of time now
+ saveScreenshotInWorkerThread();
+
+ mWindowManager.removeView(mScreenshotLayout);
+ }
+ });
+ mScreenshotAnimation.start();
+ }
+ private ValueAnimator createScreenshotFadeInAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setInterpolator(mCubicInterpolator);
+ anim.setDuration(SCREENSHOT_FADE_IN_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mBackgroundView.setVisibility(View.VISIBLE);
+ mScreenshotContainerView.setVisibility(View.VISIBLE);
+ }
+ });
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = ((Float) animation.getAnimatedValue()).floatValue();
+ mBackgroundView.setAlpha(mBackgroundViewAlphaInterpolator.getInterpolation(t) *
+ BACKGROUND_ALPHA);
+ float scaleT = SCREENSHOT_SCALE + (1f - t) * SCREENSHOT_SCALE;
+ mScreenshotContainerView.setAlpha(t*t*t*t);
+ mScreenshotContainerView.setScaleX(scaleT);
+ mScreenshotContainerView.setScaleY(scaleT);
+ mScreenshotContainerView.setRotation(t * SCREENSHOT_ROTATION);
+ }
+ });
+ return anim;
+ }
+ private ValueAnimator createScreenshotFadeOutAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
+ anim.setInterpolator(mCubicInterpolator);
+ anim.setStartDelay(SCREENSHOT_FADE_OUT_DELAY);
+ anim.setDuration(SCREENSHOT_FADE_OUT_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundView.setVisibility(View.GONE);
+ mScreenshotContainerView.setVisibility(View.GONE);
+ }
+ });
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = ((Float) animation.getAnimatedValue()).floatValue();
+ float scaleT = SCREENSHOT_MIN_SCALE +
+ t*(SCREENSHOT_SCALE - SCREENSHOT_MIN_SCALE);
+ mScreenshotContainerView.setAlpha(t);
+ mScreenshotContainerView.setScaleX(scaleT);
+ mScreenshotContainerView.setScaleY(scaleT);
+ mBackgroundView.setAlpha(t * t * BACKGROUND_ALPHA);
+ }
+ });
+ return anim;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
new file mode 100644
index 0000000..35eaedf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -0,0 +1,50 @@
+/*
+ * 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.screenshot;
+
+import android.app.Service;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class TakeScreenshotService extends Service {
+ private static final String TAG = "TakeScreenshotService";
+
+ private static GlobalScreenshot mScreenshot;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mScreenshot == null) {
+ mScreenshot = new GlobalScreenshot(this);
+ }
+ mScreenshot.takeScreenshot();
+ return null;
+ }
+}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b52e7e1..ad6cebb 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
@@ -372,6 +373,10 @@
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior = -1;
+ // Screenshot trigger states
+ private boolean mVolumeDownTriggered;
+ private boolean mPowerDownTriggered;
+
ShortcutManager mShortcutManager;
PowerManager.WakeLock mBroadcastWakeLock;
@@ -2339,6 +2344,26 @@
}
}
+ private void takeScreenshot() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ComponentName cn = new ComponentName("com.android.systemui",
+ "com.android.systemui.screenshot.TakeScreenshotService");
+ Intent intent = new Intent();
+ intent.setComponent(cn);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.unbindService(conn);
+ }
+ });
+ }
+
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
@@ -2398,6 +2423,24 @@
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
+ if (down) {
+ // If the power key down was already triggered, take the screenshot
+ if (mPowerDownTriggered) {
+ // Dismiss the power-key longpress
+ mHandler.removeCallbacks(mPowerLongPress);
+ mPowerKeyHandled = true;
+
+ // Take the screenshot
+ takeScreenshot();
+
+ // Prevent the event from being passed through to the current activity
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
+ mVolumeDownTriggered = true;
+ } else {
+ mVolumeDownTriggered = false;
+ }
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (down) {
@@ -2478,6 +2521,18 @@
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
+ // If the volume down key has been triggered, then just take the screenshot
+ if (mVolumeDownTriggered) {
+ // Take the screenshot
+ takeScreenshot();
+ mPowerKeyHandled = true;
+
+ // Prevent the event from being passed through to the current activity
+ break;
+ }
+ mPowerDownTriggered = true;
+
+
ITelephony telephonyService = getTelephonyService();
boolean hungUp = false;
if (telephonyService != null) {
@@ -2499,6 +2554,7 @@
}
interceptPowerKeyDown(!isScreenOn || hungUp);
} else {
+ mPowerDownTriggered = false;
if (interceptPowerKeyUp(canceled)) {
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index fce7cdc..2f010e5 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -473,8 +473,8 @@
+ " EmergOnly=" + mIsEmergencyOnly);
}
- public void setStateOutOfService() {
- mState = STATE_OUT_OF_SERVICE;
+ private void setNullState(int state) {
+ mState = state;
mRoaming = false;
mOperatorAlphaLong = null;
mOperatorAlphaShort = null;
@@ -491,23 +491,12 @@
mIsEmergencyOnly = false;
}
- // TODO - can't this be combined with the above method?
+ public void setStateOutOfService() {
+ setNullState(STATE_OUT_OF_SERVICE);
+ }
+
public void setStateOff() {
- mState = STATE_POWER_OFF;
- mRoaming = false;
- mOperatorAlphaLong = null;
- mOperatorAlphaShort = null;
- mOperatorNumeric = null;
- mIsManualNetworkSelection = false;
- mRadioTechnology = 0;
- mCssIndicator = false;
- mNetworkId = -1;
- mSystemId = -1;
- mCdmaRoamingIndicator = -1;
- mCdmaDefaultRoamingIndicator = -1;
- mCdmaEriIconIndex = -1;
- mCdmaEriIconMode = -1;
- mIsEmergencyOnly = false;
+ setNullState(STATE_POWER_OFF);
}
public void setState(int state) {
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 910905a..aa7568b 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -55,8 +56,13 @@
}
public void notifyServiceState(Phone sender) {
+ ServiceState ss = sender.getServiceState();
+ if (ss == null) {
+ ss = new ServiceState();
+ ss.setStateOutOfService();
+ }
try {
- mRegistry.notifyServiceState(sender.getServiceState());
+ mRegistry.notifyServiceState(ss);
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 67f5158..a6b131a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -788,13 +788,13 @@
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
apnContext.setState(State.DISCONNECTING);
- } else {
- // apn is connected but no reference to dcac.
- // Should not be happen, but reset the state in case.
- apnContext.setState(State.IDLE);
- mPhone.notifyDataConnection(apnContext.getReason(),
- apnContext.getApnType());
}
+ } else {
+ // apn is connected but no reference to dcac.
+ // Should not be happen, but reset the state in case.
+ apnContext.setState(State.IDLE);
+ mPhone.notifyDataConnection(apnContext.getReason(),
+ apnContext.getApnType());
}
}
} else {
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index ba911c2..536be7e 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -66,8 +66,8 @@
<Space
android:layout_row="4"
android:layout_column="2"
- android:layout_rowWeight="1"
- android:layout_columnWeight="1"
+ android:layout_heightSpec="canStretch"
+ android:layout_widthSpec="canStretch"
/>
<Button
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index e010a00..cba98c2 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -97,8 +97,8 @@
Space v = new Space(context);
{
LayoutParams lp = new LayoutParams(row5, col3);
- lp.rowWeight = 1;
- lp.columnWeight = 1;
+ lp.widthSpec = CAN_STRETCH;
+ lp.heightSpec = CAN_STRETCH;
vg.addView(v, lp);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
index aafd176..cc60396 100644
--- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
+++ b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
@@ -9,8 +9,7 @@
android:icon="@drawable/test_pattern">
<uses-library android:name="android.test.runner" />
<activity android:name="RsBench"
- android:label="RsBenchmark"
- android:theme="@android:style/Theme.Black.NoTitleBar">
+ android:label="RsBenchmark">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
new file mode 100644
index 0000000..8234677
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/benchmark_mode"
+ android:title="@string/benchmark_mode" />
+ <item android:id="@+id/debug_mode"
+ android:title="@string/debug_mode" />
+</menu>
diff --git a/tests/RenderScriptTests/PerfTest/res/values/strings.xml b/tests/RenderScriptTests/PerfTest/res/values/strings.xml
new file mode 100644
index 0000000..627ac21
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <skip />
+ <string name="benchmark_mode">Benchmark Mode</string>
+ <string name="debug_mode">Debug Mode</string>
+</resources>
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
index d7393f8..b336a4d 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
@@ -31,10 +31,14 @@
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuInflater;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ListView;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.widget.Toast;
import java.lang.Runtime;
@@ -77,4 +81,37 @@
super.onPause();
mView.pause();
}
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.loader_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ switch (item.getItemId()) {
+ case R.id.benchmark_mode:
+ mView.setBenchmarkMode();
+ return true;
+ case R.id.debug_mode:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Pick a Test");
+ builder.setItems(mView.getTestNames(),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ Toast.makeText(getApplicationContext(),
+ "Switching to: " + mView.getTestNames()[item],
+ Toast.LENGTH_SHORT).show();
+ mView.setDebugMode(item);
+ }
+ });
+ builder.show();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index c706286..c375be5 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -84,12 +84,6 @@
private Resources mRes;
private RenderScriptGL mRS;
- private Sampler mLinearClamp;
- private Sampler mLinearWrap;
- private Sampler mMipLinearWrap;
- private Sampler mNearestClamp;
- private Sampler mNearesWrap;
-
private ProgramStore mProgStoreBlendNoneDepth;
private ProgramStore mProgStoreBlendNone;
private ProgramStore mProgStoreBlendAlpha;
@@ -115,10 +109,6 @@
private ScriptField_FragentShaderConstants3_s mFSConstPixel;
- private ProgramRaster mCullBack;
- private ProgramRaster mCullFront;
- private ProgramRaster mCullNone;
-
private Allocation mTexTorus;
private Allocation mTexOpaque;
private Allocation mTexTransparent;
@@ -143,6 +133,8 @@
private ScriptC_rsbench mScript;
+ private ScriptC_text_test mTextScript;
+ private ScriptC_torus_test mTorusScript;
private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
@@ -310,6 +302,7 @@
mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS);
mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+
mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
@@ -330,22 +323,24 @@
texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
mProgFragmentTexture = texBuilder.create();
- mProgFragmentTexture.bindSampler(mLinearClamp, 0);
+ mProgFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
colBuilder.setVaryingColor(false);
mProgFragmentColor = colBuilder.create();
mScript.set_gProgFragmentColor(mProgFragmentColor);
+
mScript.set_gProgFragmentTexture(mProgFragmentTexture);
+
// For Galaxy live wallpaper drawing
ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
ProgramFragment pfb = builder.create();
- pfb.bindSampler(mNearesWrap, 0);
+ pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0);
mScript.set_gPFBackground(pfb);
builder = new ProgramFragmentFixedFunction.Builder(mRS);
@@ -354,7 +349,7 @@
ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
builder.setVaryingColor(true);
ProgramFragment pfs = builder.create();
- pfs.bindSampler(mMipLinearWrap, 0);
+ pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
mScript.set_gPFStars(pfs);
}
@@ -404,6 +399,7 @@
mScript.set_gProgVertex(mProgVertex);
+
// For galaxy live wallpaper
mPvStarAlloc = new ScriptField_VpConsts(mRS, 1);
mScript.bind_vpConstants(mPvStarAlloc);
@@ -447,13 +443,11 @@
private void initCustomShaders() {
mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
- mScript.bind_gVSConstants(mVSConst);
- mScript.bind_gFSConstants(mFSConst);
+
mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1);
mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1);
- mScript.bind_gVSConstPixel(mVSConstPixel);
- mScript.bind_gFSConstPixel(mFSConstPixel);
+
// Initialize the shader builder
ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
@@ -506,11 +500,7 @@
}
mProgFragmentMultitex = pfbCustom.create();
- mScript.set_gProgVertexCustom(mProgVertexCustom);
- mScript.set_gProgFragmentCustom(mProgFragmentCustom);
- mScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
- mScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
- mScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
+
mScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
}
@@ -587,39 +577,22 @@
Log.e("rs", "could not load model");
} else {
mTorus = (Mesh)entry.getObject();
- mScript.set_gTorusMesh(mTorus);
}
createParticlesMesh();
}
private void initSamplers() {
- Sampler.Builder bs = new Sampler.Builder(mRS);
- bs.setMinification(Sampler.Value.LINEAR);
- bs.setMagnification(Sampler.Value.LINEAR);
- bs.setWrapS(Sampler.Value.WRAP);
- bs.setWrapT(Sampler.Value.WRAP);
- mLinearWrap = bs.create();
-
- mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
- mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
- mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
- mNearesWrap = Sampler.WRAP_NEAREST(mRS);
-
- mScript.set_gLinearClamp(mLinearClamp);
- mScript.set_gLinearWrap(mLinearWrap);
- mScript.set_gMipLinearWrap(mMipLinearWrap);
- mScript.set_gNearestClamp(mNearestClamp);
+ mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
+ mScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS));
+ mScript.set_gMipLinearWrap(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS));
+ mScript.set_gNearestClamp(Sampler.CLAMP_NEAREST(mRS));
}
private void initProgramRaster() {
- mCullBack = ProgramRaster.CULL_BACK(mRS);
- mCullFront = ProgramRaster.CULL_FRONT(mRS);
- mCullNone = ProgramRaster.CULL_NONE(mRS);
-
- mScript.set_gCullBack(mCullBack);
- mScript.set_gCullFront(mCullFront);
- mScript.set_gCullNone(mCullNone);
+ mScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS));
+ mScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS));
+ mScript.set_gCullNone(ProgramRaster.CULL_NONE(mRS));
}
private int strlen(byte[] array) {
@@ -645,9 +618,47 @@
}
}
+ public void setDebugMode(int num) {
+ mScript.invoke_setDebugMode(num);
+ }
+
+ public void setBenchmarkMode() {
+ mScript.invoke_setBenchmarkMode();
+ }
+
+ void initTextScript() {
+ mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test);
+ mTextScript.set_gFontSans(mFontSans);
+ mTextScript.set_gFontSerif(mFontSerif);
+ }
+
+ void initTorusScript() {
+ mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test);
+ mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS));
+ mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS));
+ mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
+ mTorusScript.set_gTorusMesh(mTorus);
+ mTorusScript.set_gTexTorus(mTexTorus);
+ mTorusScript.set_gProgVertexCustom(mProgVertexCustom);
+ mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom);
+ mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
+ mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
+ mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
+ mTorusScript.bind_gVSConstPixel(mVSConstPixel);
+ mTorusScript.bind_gFSConstPixel(mFSConstPixel);
+ mTorusScript.bind_gVSConstants(mVSConst);
+ mTorusScript.bind_gFSConstants(mFSConst);
+ mTorusScript.set_gProgVertex(mProgVertex);
+ mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture);
+ mTorusScript.set_gProgFragmentColor(mProgFragmentColor);
+ mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+ }
+
private void initRS() {
mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
+
+
mRS.setMessageHandler(mRsMessage);
mMaxModes = mScript.get_gMaxModes();
@@ -709,6 +720,13 @@
mSampleListViewAllocs.copyAll();
mScript.bind_gListViewText(mSampleListViewAllocs);
+ initTextScript();
+ initTorusScript();
+
+ mScript.set_gFontScript(mTextScript);
+ mScript.set_gTorusScript(mTorusScript);
+ mScript.set_gDummyAlloc(Allocation.createSized(mRS, Element.I32(mRS), 1));
+
mRS.bindRootScript(mScript);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
index 2882b93..61aa3e1 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
@@ -105,4 +105,16 @@
public boolean testIsFinished() {
return mRender.testIsFinished();
}
+
+ void setBenchmarkMode() {
+ mRender.setBenchmarkMode();
+ }
+
+ void setDebugMode(int num) {
+ mRender.setDebugMode(num);
+ }
+
+ String[] getTestNames() {
+ return mRender.mTestNames;
+ }
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index bb81862..eaafe1d 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -18,6 +18,7 @@
#include "rs_graphics.rsh"
#include "shader_def.rsh"
+#include "subtest_def.rsh"
/* Message sent from script to renderscript */
const int RS_MSG_TEST_DONE = 100;
@@ -98,7 +99,6 @@
rs_mesh g10by10Mesh;
rs_mesh g100by100Mesh;
rs_mesh gWbyHMesh;
-rs_mesh gTorusMesh;
rs_mesh gSingleMesh;
rs_font gFontSans;
@@ -115,25 +115,15 @@
rs_program_raster gCullFront;
rs_program_raster gCullNone;
-// Custom vertex shader compunents
-VertexShaderConstants *gVSConstants;
-FragentShaderConstants *gFSConstants;
-VertexShaderConstants3 *gVSConstPixel;
-FragentShaderConstants3 *gFSConstPixel;
// Export these out to easily set the inputs to shader
VertexShaderInputs *gVSInputs;
-// Custom shaders we use for lighting
-rs_program_vertex gProgVertexCustom;
-rs_program_fragment gProgFragmentCustom;
-rs_program_vertex gProgVertexPixelLight;
-rs_program_vertex gProgVertexPixelLightMove;
-rs_program_fragment gProgFragmentPixelLight;
+
rs_program_fragment gProgFragmentMultitex;
rs_allocation gRenderBufferColor;
rs_allocation gRenderBufferDepth;
-float gDt = 0;
+static float gDt = 0;
void init() {
}
@@ -141,16 +131,6 @@
static int gRenderSurfaceW;
static int gRenderSurfaceH;
-static const char *sampleText = "This is a sample of small text for performace";
-// Offsets for multiple layer of text
-static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8};
-static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f,
- 0.5f, 0.7f, 0.5f, 1.0f,
- 0.7f, 0.5f, 0.5f, 1.0f,
- 0.5f, 0.5f, 0.7f, 1.0f,
- 0.5f, 0.6f, 0.7f, 1.0f,
-};
-
/**
* Methods to draw the galaxy live wall paper
*/
@@ -291,40 +271,16 @@
rsgBindDepthTarget(gRenderBufferDepth);
}
+rs_script gFontScript;
+rs_script gTorusScript;
+rs_allocation gDummyAlloc;
+
static void displayFontSamples(int fillNum) {
-
- rs_font fonts[5];
- fonts[0] = gFontSans;
- fonts[1] = gFontSerif;
- fonts[2] = gFontSans;
- fonts[3] = gFontSerif;
- fonts[4] = gFontSans;
-
- uint width = gRenderSurfaceW;
- uint height = gRenderSurfaceH;
- int left = 0, right = 0, top = 0, bottom = 0;
- rsgMeasureText(sampleText, &left, &right, &top, &bottom);
-
- int textHeight = top - bottom;
- int textWidth = right - left;
- int numVerticalLines = height / textHeight;
- int yPos = top;
-
- int xOffset = 0, yOffset = 0;
- for(int fillI = 0; fillI < fillNum; fillI ++) {
- rsgBindFont(fonts[fillI]);
- xOffset = textOffsets[fillI * 2];
- yOffset = textOffsets[fillI * 2 + 1];
- float *colPtr = textColors + fillI * 4;
- rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]);
- for (int h = 0; h < 4; h ++) {
- yPos = top + yOffset;
- for (int v = 0; v < numVerticalLines; v ++) {
- rsgDrawText(sampleText, xOffset + textWidth * h, yPos);
- yPos += textHeight;
- }
- }
- }
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.user = fillNum;
+ rsForEach(gFontScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void bindProgramVertexOrtho() {
@@ -555,212 +511,37 @@
drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
}
-static float gTorusRotation = 0;
-static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
- if (buffer == 0) {
- rsgProgramVertexLoadModelMatrix(matrix);
- } else {
- rsgAllocationSyncAll(rsGetAllocation(buffer));
- }
-}
-
-static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) {
-
- if (numMeshes == 1) {
- rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- return;
- }
-
- if (numMeshes == 2) {
- rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
-
- rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- return;
- }
-
- float startX = -5.0f;
- float startY = -1.5f;
- float startZ = -15.0f;
- float dist = 3.2f;
-
- for (int h = 0; h < 4; h ++) {
- for (int v = 0; v < 2; v ++) {
- // Position our model on the screen
- rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- }
- }
-}
-
// Quick hack to get some geometry numbers
static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
- rsgBindProgramVertex(gProgVertex);
- rsgBindProgramRaster(gCullBack);
- // Setup the projection matrix with 30 degree field of view
- rs_matrix4x4 proj;
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
- rsgProgramVertexLoadProjectionMatrix(&proj);
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- if (useTexture) {
- rsgBindProgramFragment(gProgFragmentTexture);
- } else {
- rsgBindProgramFragment(gProgFragmentColor);
- rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1);
- }
- rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
-
- // Apply a rotation to our mesh
- gTorusRotation += 50.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- rs_matrix4x4 matrix;
- drawToruses(numMeshes, &matrix, 0);
-}
-
-float gLight0Rotation = 0;
-float gLight1Rotation = 0;
-
-static void setupCustomShaderLights() {
- float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
- float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
- float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
- float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
- float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
- float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
-
- gLight0Rotation += 50.0f * gDt;
- if (gLight0Rotation > 360.0f) {
- gLight0Rotation -= 360.0f;
- }
- gLight1Rotation -= 50.0f * gDt;
- if (gLight1Rotation > 360.0f) {
- gLight1Rotation -= 360.0f;
- }
-
- rs_matrix4x4 l0Mat;
- rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
- light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
- rs_matrix4x4 l1Mat;
- rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
- light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
-
- // Set light 0 properties
- gVSConstants->light0_Posision = light0Pos;
- gVSConstants->light0_Diffuse = 1.0f;
- gVSConstants->light0_Specular = 0.5f;
- gVSConstants->light0_CosinePower = 10.0f;
- // Set light 1 properties
- gVSConstants->light1_Posision = light1Pos;
- gVSConstants->light1_Diffuse = 1.0f;
- gVSConstants->light1_Specular = 0.7f;
- gVSConstants->light1_CosinePower = 25.0f;
- rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
-
- // Update fragment shader constants
- // Set light 0 colors
- gFSConstants->light0_DiffuseColor = light0DiffCol;
- gFSConstants->light0_SpecularColor = light0SpecCol;
- // Set light 1 colors
- gFSConstants->light1_DiffuseColor = light1DiffCol;
- gFSConstants->light1_SpecularColor = light1SpecCol;
- rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
-
- // Set light 0 properties for per pixel lighting
- gFSConstPixel->light0_Posision = light0Pos;
- gFSConstPixel->light0_Diffuse = 1.0f;
- gFSConstPixel->light0_Specular = 0.5f;
- gFSConstPixel->light0_CosinePower = 10.0f;
- gFSConstPixel->light0_DiffuseColor = light0DiffCol;
- gFSConstPixel->light0_SpecularColor = light0SpecCol;
- // Set light 1 properties
- gFSConstPixel->light1_Posision = light1Pos;
- gFSConstPixel->light1_Diffuse = 1.0f;
- gFSConstPixel->light1_Specular = 0.7f;
- gFSConstPixel->light1_CosinePower = 25.0f;
- gFSConstPixel->light1_DiffuseColor = light1DiffCol;
- gFSConstPixel->light1_SpecularColor = light1SpecCol;
- rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel));
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 0;
+ testData.user1 = useTexture ? 1 : 0;
+ testData.user2 = numMeshes;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayCustomShaderSamples(int numMeshes) {
-
- // Update vertex shader constants
- // Load model matrix
- // Apply a rotation to our mesh
- gTorusRotation += 50.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- // Setup the projection matrix
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
- setupCustomShaderLights();
-
- rsgBindProgramVertex(gProgVertexCustom);
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- rsgBindProgramFragment(gProgFragmentCustom);
- rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
-
- // Use back face culling
- rsgBindProgramRaster(gCullBack);
-
- drawToruses(numMeshes, &gVSConstants->model, gVSConstants);
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 1;
+ testData.user1 = numMeshes;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
-
- // Update vertex shader constants
- // Load model matrix
- // Apply a rotation to our mesh
- gTorusRotation += 30.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- gVSConstPixel->time = rsUptimeMillis()*0.005;
-
- // Setup the projection matrix
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f);
- setupCustomShaderLights();
-
- if (heavyVertex) {
- rsgBindProgramVertex(gProgVertexPixelLightMove);
- } else {
- rsgBindProgramVertex(gProgVertexPixelLight);
- }
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- rsgBindProgramFragment(gProgFragmentPixelLight);
- rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus);
-
- // Use back face culling
- rsgBindProgramRaster(gCullBack);
-
- drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel);
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 2;
+ testData.user1 = numMeshes;
+ testData.user2 = heavyVertex ? 1 : 0;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayMultitextureSample(bool blend, int quadCount) {
@@ -862,6 +643,20 @@
"UI test with live wallpaper",
};
+static bool gIsDebugMode = false;
+void setDebugMode(int testNumber) {
+ gIsDebugMode = true;
+ benchMode = testNumber;
+ rsgClearAllRenderTargets();
+}
+
+void setBenchmarkMode() {
+ gIsDebugMode = false;
+ benchMode = 0;
+ runningLoops = 0;
+}
+
+
void getTestName(int testIndex) {
int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer));
if (testIndex >= gMaxModes) {
@@ -932,7 +727,7 @@
displaySingletexFill(true, 10);
break;
case 18:
- displayMultitextureSample(true, 8);
+ displayMultitextureSample(true, 10);
break;
case 19:
displayPixelLightSamples(1, false);
@@ -992,14 +787,7 @@
startX + width, startY, 0, 1, 1);
}
-int root(void) {
- gRenderSurfaceW = rsgGetWidth();
- gRenderSurfaceH = rsgGetHeight();
- rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
- rsgClearDepth(1.0f);
- if(!checkInit()) {
- return 1;
- }
+static void benchmark() {
gDt = 1.0f / 60.0f;
@@ -1045,8 +833,6 @@
benchMode ++;
- gTorusRotation = 0;
-
if (benchMode == gMaxModes) {
rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float));
benchMode = 0;
@@ -1058,5 +844,30 @@
sendMsgFlag = true;
}
}
+
+}
+
+static void debug() {
+ gDt = rsGetDt();
+
+ rsgFinish();
+ runTest(benchMode);
+}
+
+int root(void) {
+ gRenderSurfaceW = rsgGetWidth();
+ gRenderSurfaceH = rsgGetHeight();
+ rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ rsgClearDepth(1.0f);
+ if(!checkInit()) {
+ return 1;
+ }
+
+ if (gIsDebugMode) {
+ debug();
+ } else {
+ benchmark();
+ }
+
return 1;
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
new file mode 100644
index 0000000..b635373b
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
@@ -0,0 +1,28 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+typedef struct TestData_s {
+ int renderSurfaceW;
+ int renderSurfaceH;
+ float dt;
+ int user;
+ int user1;
+ int user2;
+ int user3;
+} TestData;
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
new file mode 100644
index 0000000..0df6b35
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
@@ -0,0 +1,82 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+#include "rs_graphics.rsh"
+#include "subtest_def.rsh"
+
+rs_font gFontSans;
+rs_font gFontSerif;
+
+void init() {
+}
+
+static int gRenderSurfaceW = 1280;
+static int gRenderSurfaceH = 720;
+
+static const char *sampleText = "This is a sample of small text for performace";
+// Offsets for multiple layer of text
+static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8};
+static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f,
+ 0.5f, 0.7f, 0.5f, 1.0f,
+ 0.7f, 0.5f, 0.5f, 1.0f,
+ 0.5f, 0.5f, 0.7f, 1.0f,
+ 0.5f, 0.6f, 0.7f, 1.0f,
+};
+
+static void displayFontSamples(int fillNum) {
+
+ rs_font fonts[5];
+ fonts[0] = gFontSans;
+ fonts[1] = gFontSerif;
+ fonts[2] = gFontSans;
+ fonts[3] = gFontSerif;
+ fonts[4] = gFontSans;
+
+ uint width = gRenderSurfaceW;
+ uint height = gRenderSurfaceH;
+ int left = 0, right = 0, top = 0, bottom = 0;
+ rsgMeasureText(sampleText, &left, &right, &top, &bottom);
+
+ int textHeight = top - bottom;
+ int textWidth = right - left;
+ int numVerticalLines = height / textHeight;
+ int yPos = top;
+
+ int xOffset = 0, yOffset = 0;
+ for(int fillI = 0; fillI < fillNum; fillI ++) {
+ rsgBindFont(fonts[fillI]);
+ xOffset = textOffsets[fillI * 2];
+ yOffset = textOffsets[fillI * 2 + 1];
+ float *colPtr = textColors + fillI * 4;
+ rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]);
+ for (int h = 0; h < 4; h ++) {
+ yPos = top + yOffset;
+ for (int v = 0; v < numVerticalLines; v ++) {
+ rsgDrawText(sampleText, xOffset + textWidth * h, yPos);
+ yPos += textHeight;
+ }
+ }
+ }
+}
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+ TestData *testData = (TestData*)usrData;
+ gRenderSurfaceW = testData->renderSurfaceW;
+ gRenderSurfaceH = testData->renderSurfaceH;
+ displayFontSamples(testData->user);
+}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
new file mode 100644
index 0000000..26d5680
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
@@ -0,0 +1,283 @@
+// 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.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+#include "rs_graphics.rsh"
+#include "subtest_def.rsh"
+#include "shader_def.rsh"
+
+rs_program_vertex gProgVertex;
+rs_program_fragment gProgFragmentColor;
+rs_program_fragment gProgFragmentTexture;
+
+rs_program_store gProgStoreBlendNoneDepth;
+rs_mesh gTorusMesh;
+
+rs_program_raster gCullBack;
+rs_program_raster gCullFront;
+
+// Custom vertex shader compunents
+VertexShaderConstants *gVSConstants;
+FragentShaderConstants *gFSConstants;
+VertexShaderConstants3 *gVSConstPixel;
+FragentShaderConstants3 *gFSConstPixel;
+
+// Custom shaders we use for lighting
+rs_program_vertex gProgVertexCustom;
+rs_program_fragment gProgFragmentCustom;
+
+rs_sampler gLinearClamp;
+rs_allocation gTexTorus;
+
+rs_program_vertex gProgVertexPixelLight;
+rs_program_vertex gProgVertexPixelLightMove;
+rs_program_fragment gProgFragmentPixelLight;
+
+static float gDt = 0.0f;
+
+static int gRenderSurfaceW;
+static int gRenderSurfaceH;
+
+
+static float gTorusRotation = 0;
+static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
+ if (buffer == 0) {
+ rsgProgramVertexLoadModelMatrix(matrix);
+ } else {
+ rsgAllocationSyncAll(rsGetAllocation(buffer));
+ }
+}
+
+static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) {
+
+ if (numMeshes == 1) {
+ rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ return;
+ }
+
+ if (numMeshes == 2) {
+ rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+
+ rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ return;
+ }
+
+ float startX = -5.0f;
+ float startY = -1.5f;
+ float startZ = -15.0f;
+ float dist = 3.2f;
+
+ for (int h = 0; h < 4; h ++) {
+ for (int v = 0; v < 2; v ++) {
+ // Position our model on the screen
+ rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ }
+ }
+}
+
+
+// Quick hack to get some geometry numbers
+static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
+ rsgBindProgramVertex(gProgVertex);
+ rsgBindProgramRaster(gCullBack);
+ // Setup the projection matrix with 30 degree field of view
+ rs_matrix4x4 proj;
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ if (useTexture) {
+ rsgBindProgramFragment(gProgFragmentTexture);
+ } else {
+ rsgBindProgramFragment(gProgFragmentColor);
+ rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1);
+ }
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
+
+ // Apply a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ rs_matrix4x4 matrix;
+ drawToruses(numMeshes, &matrix, 0);
+}
+
+float gLight0Rotation = 0;
+float gLight1Rotation = 0;
+
+static void setupCustomShaderLights() {
+ float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
+ float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
+ float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
+ float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
+ float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
+ float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
+
+ gLight0Rotation += 50.0f * gDt;
+ if (gLight0Rotation > 360.0f) {
+ gLight0Rotation -= 360.0f;
+ }
+ gLight1Rotation -= 50.0f * gDt;
+ if (gLight1Rotation > 360.0f) {
+ gLight1Rotation -= 360.0f;
+ }
+
+ rs_matrix4x4 l0Mat;
+ rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
+ light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
+ rs_matrix4x4 l1Mat;
+ rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
+ light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
+
+ // Set light 0 properties
+ gVSConstants->light0_Posision = light0Pos;
+ gVSConstants->light0_Diffuse = 1.0f;
+ gVSConstants->light0_Specular = 0.5f;
+ gVSConstants->light0_CosinePower = 10.0f;
+ // Set light 1 properties
+ gVSConstants->light1_Posision = light1Pos;
+ gVSConstants->light1_Diffuse = 1.0f;
+ gVSConstants->light1_Specular = 0.7f;
+ gVSConstants->light1_CosinePower = 25.0f;
+ rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
+
+ // Update fragment shader constants
+ // Set light 0 colors
+ gFSConstants->light0_DiffuseColor = light0DiffCol;
+ gFSConstants->light0_SpecularColor = light0SpecCol;
+ // Set light 1 colors
+ gFSConstants->light1_DiffuseColor = light1DiffCol;
+ gFSConstants->light1_SpecularColor = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+ // Set light 0 properties for per pixel lighting
+ gFSConstPixel->light0_Posision = light0Pos;
+ gFSConstPixel->light0_Diffuse = 1.0f;
+ gFSConstPixel->light0_Specular = 0.5f;
+ gFSConstPixel->light0_CosinePower = 10.0f;
+ gFSConstPixel->light0_DiffuseColor = light0DiffCol;
+ gFSConstPixel->light0_SpecularColor = light0SpecCol;
+ // Set light 1 properties
+ gFSConstPixel->light1_Posision = light1Pos;
+ gFSConstPixel->light1_Diffuse = 1.0f;
+ gFSConstPixel->light1_Specular = 0.7f;
+ gFSConstPixel->light1_CosinePower = 25.0f;
+ gFSConstPixel->light1_DiffuseColor = light1DiffCol;
+ gFSConstPixel->light1_SpecularColor = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel));
+}
+
+static void displayCustomShaderSamples(int numMeshes) {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Apply a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ // Setup the projection matrix
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ rsgBindProgramVertex(gProgVertexCustom);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentCustom);
+ rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+
+ drawToruses(numMeshes, &gVSConstants->model, gVSConstants);
+}
+
+static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Apply a rotation to our mesh
+ gTorusRotation += 30.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ gVSConstPixel->time = rsUptimeMillis()*0.005;
+
+ // Setup the projection matrix
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ if (heavyVertex) {
+ rsgBindProgramVertex(gProgVertexPixelLightMove);
+ } else {
+ rsgBindProgramVertex(gProgVertexPixelLight);
+ }
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentPixelLight);
+ rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+
+ drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel);
+}
+
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+ TestData *testData = (TestData*)usrData;
+ gRenderSurfaceW = testData->renderSurfaceW;
+ gRenderSurfaceH = testData->renderSurfaceH;
+ gDt = testData->dt;
+
+ switch(testData->user) {
+ case 0:
+ displaySimpleGeoSamples(testData->user1 == 1 ? true : false, testData->user2);
+ break;
+ case 1:
+ displayCustomShaderSamples(testData->user1);
+ break;
+ case 2:
+ displayPixelLightSamples(testData->user1, testData->user2 == 1 ? true : false);
+ break;
+ }
+}