Merge "Don't assert on unexpected surface flinger dequeue/enqueueBuffer errors, log a warning and ignore them instead."
diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java
index 4dc88b3..d7a0412 100644
--- a/core/java/android/app/NativeActivity.java
+++ b/core/java/android/app/NativeActivity.java
@@ -3,8 +3,6 @@
import com.android.internal.view.IInputMethodCallback;
import com.android.internal.view.IInputMethodSession;
-import dalvik.system.PathClassLoader;
-
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -168,17 +166,14 @@
// If the application does not have (Java) code, then no ClassLoader
// has been set up for it. We will need to do our own search for
// the native code.
- path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname);
- if (!(new File(path)).exists()) {
- path = null;
+ File libraryFile = new File(ai.applicationInfo.nativeLibraryDir,
+ System.mapLibraryName(libname));
+ if (libraryFile.exists()) {
+ path = libraryFile.getPath();
}
}
if (path == null) {
- path = ((PathClassLoader)getClassLoader()).findLibrary(libname);
- }
-
- if (path == null) {
throw new IllegalArgumentException("Unable to find native library: " + libname);
}
diff --git a/core/java/android/app/backup/SharedPreferencesBackupHelper.java b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
index 23b1703..213bd31 100644
--- a/core/java/android/app/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/app/backup/SharedPreferencesBackupHelper.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.app.QueuedWork;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.ParcelFileDescriptor;
@@ -94,7 +95,11 @@
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
Context context = mContext;
-
+
+ // If a SharedPreference has an outstanding write in flight,
+ // wait for it to finish flushing to disk.
+ QueuedWork.waitToFinish();
+
// make filenames for the prefGroups
String[] prefGroups = mPrefGroups;
final int N = prefGroups.length;
@@ -123,4 +128,3 @@
}
}
}
-
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index aa0a57d..9541380 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -144,6 +144,22 @@
}
}
+ @Override public String toString() {
+ synchronized(this) {
+ StringBuilder buff = new StringBuilder();
+ buff.append(" nStatement=");
+ buff.append(nStatement);
+ buff.append(", db=");
+ buff.append(mDatabase.getPath());
+ buff.append(", db_connectionNum=");
+ buff.append(mDatabase.mConnectionNum);
+ buff.append(", sql=");
+ int len = mSqlStmt.length();
+ buff.append(mSqlStmt.substring(0, (len > 100) ? 100 : len));
+ return buff.toString();
+ }
+ }
+
/**
* Compiles SQL into a SQLite program.
*
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0137ea6..6937da0 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1066,7 +1066,7 @@
closePendingStatements();
releaseCustomFunctions();
// close this database instance - regardless of its reference count value
- dbclose();
+ closeDatabase();
if (mConnectionPool != null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
assert mConnectionPool != null;
@@ -1075,7 +1075,7 @@
mConnectionPool.close();
}
} finally {
- unlock();
+ unlock();
}
}
@@ -1100,6 +1100,47 @@
}
/**
+ * package level access for testing purposes
+ */
+ /* package */ void closeDatabase() throws SQLiteException {
+ try {
+ dbclose();
+ } catch (SQLiteUnfinalizedObjectsException e) {
+ String msg = e.getMessage();
+ String[] tokens = msg.split(",", 2);
+ int stmtId = Integer.parseInt(tokens[0]);
+ // get extra info about this statement, if it is still to be released by closeClosable()
+ Iterator<Map.Entry<SQLiteClosable, Object>> iter = mPrograms.entrySet().iterator();
+ boolean found = false;
+ while (iter.hasNext()) {
+ Map.Entry<SQLiteClosable, Object> entry = iter.next();
+ SQLiteClosable program = entry.getKey();
+ if (program != null && program instanceof SQLiteProgram) {
+ SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
+ if (compiledSql.nStatement == stmtId) {
+ msg = compiledSql.toString();
+ found = true;
+ }
+ }
+ }
+ if (!found) {
+ // the statement is already released by closeClosable(). is it waiting to be
+ // finalized?
+ if (mClosedStatementIds.contains(stmtId)) {
+ Log.w(TAG, "this shouldn't happen. finalizing the statement now: ");
+ closePendingStatements();
+ // try to close the database again
+ closeDatabase();
+ }
+ } else {
+ // the statement is not yet closed. most probably programming error in the app.
+ Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg);
+ throw e;
+ }
+ }
+ }
+
+ /**
* Native call to close the database.
*/
private native void dbclose();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 9b7d823..5e08aed 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -52,7 +52,7 @@
/**
* the SQLiteCompiledSql object for the given sql statement.
*/
- private SQLiteCompiledSql mCompiledSql;
+ /* package */ SQLiteCompiledSql mCompiledSql;
/**
* SQLiteCompiledSql statement id is populated with the corresponding object from the above
diff --git a/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
new file mode 100644
index 0000000..bcf95e2
--- /dev/null
+++ b/core/java/android/database/sqlite/SQLiteUnfinalizedObjectsException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+/**
+ * Thrown if the database can't be closed because of some un-closed
+ * Cursor or SQLiteStatement objects. Could happen when a thread is trying to close
+ * the database while another thread still hasn't closed a Cursor on that database.
+ * @hide
+ */
+public class SQLiteUnfinalizedObjectsException extends SQLiteException {
+ public SQLiteUnfinalizedObjectsException() {}
+
+ public SQLiteUnfinalizedObjectsException(String error) {
+ super(error);
+ }
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7355353..f8d79e5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7298,9 +7298,6 @@
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
- if (Config.DEBUG && ViewDebug.profileDrawing) {
- EventLog.writeEvent(60002, hashCode());
- }
int width = mRight - mLeft;
int height = mBottom - mTop;
@@ -7738,7 +7735,8 @@
saveCount = canvas.getSaveCount();
int solidColor = getSolidColor();
- if (solidColor == 0) {
+ // TODO: Temporarily disable fading edges with hardware acceleration
+ if (solidColor == 0 && !canvas.isHardwareAccelerated()) {
final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
if (drawTop) {
@@ -7946,6 +7944,7 @@
* @param r Right position, relative to parent
* @param b Bottom position, relative to parent
*/
+ @SuppressWarnings({"unchecked"})
public final void layout(int l, int t, int r, int b) {
int oldL = mLeft;
int oldT = mTop;
@@ -10129,11 +10128,6 @@
final RectF mTmpTransformRect = new RectF();
/**
- * Temporary for use in computing invalidation areas with transformed views
- */
- final float[] mTmpTransformBounds = new float[8];
-
- /**
* Temporary list for use in collecting focusable descendents of a view.
*/
final ArrayList<View> mFocusablesTempList = new ArrayList<View>(24);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 22cc3a8..b1d5272 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -119,24 +119,21 @@
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean profileDrawing = false;
+ public static final boolean DEBUG_PROFILE_DRAWING = false;
/**
* Profiles layout times in the events log.
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean profileLayout = false;
+ public static final boolean DEBUG_PROFILE_LAYOUT = false;
/**
* Profiles real fps (times between draws) and displays the result.
*
* @hide
*/
- @Debug.DebugProperty
- public static boolean showFps = false;
+ public static final boolean DEBUG_SHOW_FPS = false;
/**
* <p>Enables or disables views consistency check. Even when this property is enabled,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dee6e73..363ccd6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -32,8 +32,6 @@
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.AttributeSet;
-import android.util.Config;
-import android.util.EventLog;
import android.util.Log;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
@@ -2020,9 +2018,6 @@
cachePaint.setAlpha(255);
mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
}
- if (Config.DEBUG && ViewDebug.profileDrawing) {
- EventLog.writeEvent(60003, hashCode());
- }
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 5d4ac37..e61eaed 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1008,7 +1008,7 @@
TAG, "Laying out " + host + " to (" +
host.mMeasuredWidth + ", " + host.mMeasuredHeight + ")");
long startTime = 0L;
- if (ViewDebug.profileLayout) {
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
startTime = SystemClock.elapsedRealtime();
}
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
@@ -1021,7 +1021,7 @@
}
}
- if (ViewDebug.profileLayout) {
+ if (ViewDebug.DEBUG_PROFILE_LAYOUT) {
EventLog.writeEvent(60001, SystemClock.elapsedRealtime() - startTime);
}
@@ -1321,7 +1321,7 @@
//canvas.drawARGB(255, 255, 0, 0);
}
- if (ViewDebug.profileDrawing) {
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
startTime = SystemClock.elapsedRealtime();
}
@@ -1364,7 +1364,7 @@
mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
}
- if (SHOW_FPS || ViewDebug.showFps) {
+ if (SHOW_FPS || ViewDebug.DEBUG_SHOW_FPS) {
int now = (int)SystemClock.elapsedRealtime();
if (sDrawTime != 0) {
nativeShowFPS(canvas, now - sDrawTime);
@@ -1372,7 +1372,7 @@
sDrawTime = now;
}
- if (ViewDebug.profileDrawing) {
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
}
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 0ed5fc5..d81d7f2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -211,6 +211,7 @@
private boolean mNavDump = false;
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
+ private boolean mDisplayZoomControls = true;
private boolean mAllowFileAccess = true;
private boolean mLoadWithOverviewMode = false;
private boolean mEnableSmoothTransition = false;
@@ -508,6 +509,26 @@
}
/**
+ * Sets whether the on screen zoom buttons are used.
+ * A combination of built in zoom controls enabled
+ * and on screen zoom controls disabled allows for pinch to zoom
+ * to work without the on screen controls
+ * @hide
+ */
+ public void setDisplayZoomControls(boolean enabled) {
+ mDisplayZoomControls = enabled;
+ mWebView.updateMultiTouchSupport(mContext);
+ }
+
+ /**
+ * Returns true if the on screen zoom buttons are being used.
+ * @hide
+ */
+ public boolean getDisplayZoomControls() {
+ return mDisplayZoomControls;
+ }
+
+ /**
* Enable or disable file access within WebView. File access is enabled by
* default.
*/
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 33ebcf5..1323217 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -856,7 +856,8 @@
private ZoomControlBase getCurrentZoomControl() {
if (mWebView.getSettings() != null && mWebView.getSettings().supportZoom()) {
if (mWebView.getSettings().getBuiltInZoomControls()) {
- if (mEmbeddedZoomControl == null) {
+ if ((mEmbeddedZoomControl == null)
+ && mWebView.getSettings().getDisplayZoomControls()) {
mEmbeddedZoomControl = new ZoomControlEmbedded(this, mWebView);
}
return mEmbeddedZoomControl;
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 0636d72..830e899 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -31,6 +31,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -128,6 +129,13 @@
boolean mShouldLoop = true;
/**
+ * The width and height of some child, used as a size reference in-case our
+ * dimensions are unspecified by the parent.
+ */
+ int mReferenceChildWidth = -1;
+ int mReferenceChildHeight = -1;
+
+ /**
* TODO: Animation stuff is still in flux, waiting on the new framework to settle a bit.
*/
Animation mInAnimation;
@@ -414,7 +422,7 @@
FrameLayout fl = new FrameLayout(mContext);
fl.addView(newView);
mActiveViews[index] = fl;
- addViewInLayout(fl, -1, createOrReuseLayoutParams(fl));
+ addChild(fl);
applyTransformForChildAtIndex(fl, newRelativeIndex);
animateViewForTransition(-1, newRelativeIndex, fl);
}
@@ -451,6 +459,64 @@
}
}
+ private void addChild(View child) {
+ addViewInLayout(child, -1, createOrReuseLayoutParams(child));
+
+ // This code is used to obtain a reference width and height of a child in case we need
+ // to decide our own size. TODO: Do we want to update the size of the child that we're
+ // using for reference size? If so, when?
+ if (mReferenceChildWidth == -1 || mReferenceChildHeight == -1) {
+ int measureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ child.measure(measureSpec, measureSpec);
+ mReferenceChildWidth = child.getMeasuredWidth();
+ mReferenceChildHeight = child.getMeasuredHeight();
+ }
+ }
+
+ private void measureChildren() {
+ final int count = getChildCount();
+ final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+ final int childHeight = mMeasuredHeight - mPaddingTop - mPaddingBottom;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+ // We need to deal with the case where our parent hasn't told us how
+ // big we should be. In this case we try to use the desired size of the first
+ // child added.
+ if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+ heightSpecSize = haveChildRefSize ? mReferenceChildHeight + mPaddingTop +
+ mPaddingBottom : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ heightSpecSize = haveChildRefSize ? Math.min(mReferenceChildHeight + mPaddingTop +
+ mPaddingBottom, heightSpecSize) : 0;
+ }
+
+ if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+ widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight, widthSpecSize) : 0;
+ }
+
+ setMeasuredDimension(widthSpecSize, heightSpecSize);
+ measureChildren();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
boolean dataChanged = mDataChanged;
@@ -472,8 +538,7 @@
int childRight = mPaddingLeft + child.getMeasuredWidth();
int childBottom = mPaddingTop + child.getMeasuredHeight();
- child.layout(mPaddingLeft, mPaddingTop,
- childRight, childBottom);
+ child.layout(mPaddingLeft, mPaddingTop, childRight, childBottom);
}
mDataChanged = false;
}
@@ -538,31 +603,6 @@
setDisplayedChild(mWhichChild);
}
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- final int count = getChildCount();
-
- int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- lp.width = widthSpecSize - mPaddingLeft - mPaddingRight;
- lp.height = heightSpecSize - mPaddingTop - mPaddingBottom;
-
- int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width,
- MeasureSpec.EXACTLY);
- int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
- MeasureSpec.EXACTLY);
-
- child.measure(childWidthMeasureSpec, childheightMeasureSpec);
- }
- setMeasuredDimension(widthSpecSize, heightSpecSize);
- }
-
/**
* Shows only the specified child. The other displays Views exit the screen
* with the {@link #getOutAnimation() out animation} and the specified child
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 9816b39..9025b83 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -16,11 +16,11 @@
package android.widget;
-import java.util.WeakHashMap;
-
import android.animation.PropertyAnimator;
+import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
@@ -28,6 +28,7 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.TableMaskFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -35,6 +36,8 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
import android.view.animation.LinearInterpolator;
import android.widget.RemoteViews.RemoteView;
@@ -53,6 +56,19 @@
private final int MINIMUM_ANIMATION_DURATION = 50;
/**
+ * Parameters effecting the perspective visuals
+ */
+ private static float PERSPECTIVE_SHIFT_FACTOR = 0.12f;
+ private static float PERSPECTIVE_SCALE_FACTOR = 0.35f;
+
+ /**
+ * Represent the two possible stack modes, one where items slide up, and the other
+ * where items slide down. The perspective is also inverted between these two modes.
+ */
+ private static final int ITEMS_SLIDE_UP = 0;
+ private static final int ITEMS_SLIDE_DOWN = 1;
+
+ /**
* These specify the different gesture states
*/
private static final int GESTURE_NONE = 0;
@@ -66,8 +82,6 @@
private static final float SWIPE_THRESHOLD_RATIO = 0.35f;
private static final float SLIDE_UP_RATIO = 0.7f;
- private final WeakHashMap<View, Float> mRotations = new WeakHashMap<View, Float>();
-
/**
* Sentinel value for no current active pointer.
* Used by {@link #mActivePointerId}.
@@ -75,6 +89,12 @@
private static final int INVALID_POINTER = -1;
/**
+ * Number of active views in the stack. One fewer view is actually visible, as one is hidden.
+ */
+ private static final int NUM_ACTIVE_VIEWS = 5;
+
+
+ /**
* These variables are all related to the current state of touch interaction
* with the stack
*/
@@ -95,6 +115,7 @@
private boolean mFirstLayoutHappened = false;
private ViewGroup mAncestorContainingAllChildren = null;
private int mAncestorHeight = 0;
+ private int mStackMode;
public StackView(Context context) {
super(context);
@@ -107,7 +128,7 @@
}
private void initStackView() {
- configureViewAnimator(4, 2, false);
+ configureViewAnimator(NUM_ACTIVE_VIEWS, NUM_ACTIVE_VIEWS - 2, false);
setStaticTransformationsEnabled(true);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
@@ -125,6 +146,11 @@
setClipChildren(false);
setClipToPadding(false);
+ // This sets the form of the StackView, which is currently to have the perspective-shifted
+ // views above the active view, and have items slide down when sliding out. The opposite is
+ // available by using ITEMS_SLIDE_UP.
+ mStackMode = ITEMS_SLIDE_DOWN;
+
// This is a flag to indicate the the stack is loading for the first time
mWhichChild = -1;
}
@@ -140,7 +166,7 @@
}
view.setVisibility(VISIBLE);
- PropertyAnimator fadeIn = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
+ PropertyAnimator<Float> fadeIn = new PropertyAnimator<Float>(DEFAULT_ANIMATION_DURATION,
view, "alpha", view.getAlpha(), 1.0f);
fadeIn.start();
} else if (fromIndex == mNumActiveViews - 1 && toIndex == mNumActiveViews - 2) {
@@ -148,49 +174,32 @@
view.setVisibility(VISIBLE);
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- int largestDuration =
- Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
-
- int duration = largestDuration;
- if (mYVelocity != 0) {
- duration = 1000*(0 - lp.verticalOffset)/Math.abs(mYVelocity);
- }
-
- duration = Math.min(duration, largestDuration);
- duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+ int duration = Math.round(mStackSlider.getDurationForNeutralPosition(mYVelocity));
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator slideInY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 0);
- slideInY.setInterpolator(new LinearInterpolator());
- slideInY.start();
- PropertyAnimator slideInX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- slideInX.setInterpolator(new LinearInterpolator());
- slideInX.start();
+ PropertyValuesHolder<Float> slideInY =
+ new PropertyValuesHolder<Float>("YProgress", 0.0f);
+ PropertyValuesHolder<Float> slideInX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ slideInX, slideInY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (fromIndex == mNumActiveViews - 2 && toIndex == mNumActiveViews - 1) {
// Slide item out
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- int largestDuration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
- DEFAULT_ANIMATION_DURATION);
- int duration = largestDuration;
- if (mYVelocity != 0) {
- duration = 1000*(lp.verticalOffset + mViewHeight)/Math.abs(mYVelocity);
- }
-
- duration = Math.min(duration, largestDuration);
- duration = Math.max(duration, MINIMUM_ANIMATION_DURATION);
+ int duration = Math.round(mStackSlider.getDurationForOffscreenPosition(mYVelocity));
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator slideOutY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 1);
- slideOutY.setInterpolator(new LinearInterpolator());
- slideOutY.start();
- PropertyAnimator slideOutX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- slideOutX.setInterpolator(new LinearInterpolator());
- slideOutX.start();
+ PropertyValuesHolder<Float> slideOutY =
+ new PropertyValuesHolder<Float>("YProgress", 1.0f);
+ PropertyValuesHolder<Float> slideOutX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ slideOutX, slideOutY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (fromIndex == -1 && toIndex == mNumActiveViews - 1) {
// Make sure this view that is "waiting in the wings" is invisible
view.setAlpha(0.0f);
@@ -199,28 +208,41 @@
lp.setVerticalOffset(-mViewHeight);
} else if (toIndex == -1) {
// Fade item out
- PropertyAnimator fadeOut = new PropertyAnimator(DEFAULT_ANIMATION_DURATION,
- view, "alpha", view.getAlpha(), 0);
+ PropertyAnimator<Float> fadeOut = new PropertyAnimator<Float>
+ (DEFAULT_ANIMATION_DURATION, view, "alpha", view.getAlpha(), 0.0f);
fadeOut.start();
}
+
+ // Implement the faked perspective
+ if (toIndex != -1) {
+ float maxPerpectiveShift = mViewHeight * PERSPECTIVE_SHIFT_FACTOR;
+ int index = toIndex;
+
+ if (toIndex == mNumActiveViews -1) index--;
+
+ float r = (index * 1.0f) / (mNumActiveViews - 2);
+
+ float scale = 1 - PERSPECTIVE_SCALE_FACTOR * (1 - r);
+ PropertyValuesHolder<Float> scaleX = new PropertyValuesHolder<Float>("scaleX", scale);
+ PropertyValuesHolder<Float> scaleY = new PropertyValuesHolder<Float>("scaleY", scale);
+
+ r = (float) Math.pow(r, 2);
+
+ int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+ float transY = -stackDirection * r * maxPerpectiveShift +
+ stackDirection * (1 - scale) * (mViewHeight / 2.0f);
+
+ PropertyValuesHolder<Float> translationY =
+ new PropertyValuesHolder<Float>("translationY", transY);
+ PropertyAnimator pa = new PropertyAnimator(100, view, scaleX, scaleY, translationY);
+ pa.start();
+ }
}
/**
* Apply any necessary tranforms for the child that is being added.
*/
void applyTransformForChildAtIndex(View child, int relativeIndex) {
- if (!mRotations.containsKey(child)) {
- float rotation = (float) (Math.random()*26 - 13);
- mRotations.put(child, rotation);
- child.setRotation(rotation);
- }
-
- // Child has been removed
- if (relativeIndex == -1) {
- if (mRotations.containsKey(child)) {
- mRotations.remove(child);
- }
- }
}
@Override
@@ -248,8 +270,8 @@
private void onLayout() {
if (!mFirstLayoutHappened) {
- mViewHeight = Math.round(SLIDE_UP_RATIO*getMeasuredHeight());
- mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO*mViewHeight);
+ mViewHeight = Math.round(SLIDE_UP_RATIO * getMeasuredHeight());
+ mSwipeThreshold = Math.round(SWIPE_THRESHOLD_RATIO * mViewHeight);
mFirstLayoutHappened = true;
}
}
@@ -299,8 +321,14 @@
cancelLongPress();
requestDisallowInterceptTouchEvent(true);
- int activeIndex = swipeGestureType == GESTURE_SLIDE_DOWN ? mNumActiveViews - 1
- : mNumActiveViews - 2;
+ int activeIndex;
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+ mNumActiveViews - 1 : mNumActiveViews - 2;
+ } else {
+ activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ?
+ mNumActiveViews - 2 : mNumActiveViews - 1;
+ }
if (mAdapter == null) return;
@@ -317,6 +345,8 @@
if (v == null) return;
mHighlight.setImageBitmap(sHolographicHelper.createOutline(v));
+ mHighlight.setRotation(v.getRotation());
+ mHighlight.setTranslationY(v.getTranslationY());
mHighlight.bringToFront();
v.bringToFront();
mStackSlider.setView(v);
@@ -352,14 +382,16 @@
case MotionEvent.ACTION_MOVE: {
beginGestureIfNeeded(deltaY);
- float rx = deltaX/(mViewHeight*1.0f);
+ float rx = deltaX / (mViewHeight * 1.0f);
if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
- float r = (deltaY-mTouchSlop*1.0f)/mViewHeight*1.0f;
+ float r = (deltaY - mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+ if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
mStackSlider.setYProgress(1 - r);
mStackSlider.setXProgress(rx);
return true;
} else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
- float r = -(deltaY + mTouchSlop*1.0f)/mViewHeight*1.0f;
+ float r = -(deltaY + mTouchSlop * 1.0f) / mViewHeight * 1.0f;
+ if (mStackMode == ITEMS_SLIDE_DOWN) r = 1 - r;
mStackSlider.setYProgress(r);
mStackSlider.setXProgress(rx);
return true;
@@ -447,41 +479,59 @@
if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN
&& mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe down
- showNext();
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ showNext();
+ } else {
+ showPrevious();
+ }
mHighlight.bringToFront();
} else if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP
&& mStackSlider.mMode == StackSlider.NORMAL_MODE) {
// Swipe threshold exceeded, swipe up
- showPrevious();
+ if (mStackMode == ITEMS_SLIDE_UP) {
+ showPrevious();
+ } else {
+ showNext();
+ }
+
mHighlight.bringToFront();
- } else if (mSwipeGestureType == GESTURE_SLIDE_UP) {
+ } else if (mSwipeGestureType == GESTURE_SLIDE_UP ) {
// Didn't swipe up far enough, snap back down
- int duration =
- Math.round(mStackSlider.getDurationForNeutralPosition()*DEFAULT_ANIMATION_DURATION);
+ int duration;
+ float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 1 : 0;
+ if (mStackMode == ITEMS_SLIDE_UP || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+ duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+ } else {
+ duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+ }
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 0);
- snapBackY.setInterpolator(new LinearInterpolator());
- snapBackY.start();
- PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- snapBackX.setInterpolator(new LinearInterpolator());
- snapBackX.start();
+ PropertyValuesHolder<Float> snapBackY =
+ new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+ PropertyValuesHolder<Float> snapBackX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ snapBackX, snapBackY);
+ pa.setInterpolator(new LinearInterpolator());
+ pa.start();
} else if (mSwipeGestureType == GESTURE_SLIDE_DOWN) {
// Didn't swipe down far enough, snap back up
- int duration = Math.round(mStackSlider.getDurationForOffscreenPosition()*
- DEFAULT_ANIMATION_DURATION);
+ float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 0 : 1;
+ int duration;
+ if (mStackMode == ITEMS_SLIDE_DOWN || mStackSlider.mMode != StackSlider.NORMAL_MODE) {
+ duration = Math.round(mStackSlider.getDurationForNeutralPosition());
+ } else {
+ duration = Math.round(mStackSlider.getDurationForOffscreenPosition());
+ }
StackSlider animationSlider = new StackSlider(mStackSlider);
- PropertyAnimator snapBackY = new PropertyAnimator(duration, animationSlider,
- "YProgress", mStackSlider.getYProgress(), 1);
- snapBackY.setInterpolator(new LinearInterpolator());
- snapBackY.start();
- PropertyAnimator snapBackX = new PropertyAnimator(duration, animationSlider,
- "XProgress", mStackSlider.getXProgress(), 0);
- snapBackX.setInterpolator(new LinearInterpolator());
- snapBackX.start();
+ PropertyValuesHolder<Float> snapBackY =
+ new PropertyValuesHolder<Float>("YProgress", finalYProgress);
+ PropertyValuesHolder<Float> snapBackX =
+ new PropertyValuesHolder<Float>("XProgress", 0.0f);
+ PropertyAnimator pa = new PropertyAnimator(duration, animationSlider,
+ snapBackX, snapBackY);
+ pa.start();
}
mActivePointerId = INVALID_POINTER;
@@ -510,22 +560,22 @@
}
private float cubic(float r) {
- return (float) (Math.pow(2*r-1, 3) + 1)/2.0f;
+ return (float) (Math.pow(2 * r - 1, 3) + 1) / 2.0f;
}
private float highlightAlphaInterpolator(float r) {
float pivot = 0.4f;
if (r < pivot) {
- return 0.85f*cubic(r/pivot);
+ return 0.85f * cubic(r / pivot);
} else {
- return 0.85f*cubic(1 - (r-pivot)/(1-pivot));
+ return 0.85f * cubic(1 - (r - pivot) / (1 - pivot));
}
}
private float viewAlphaInterpolator(float r) {
float pivot = 0.3f;
if (r > pivot) {
- return (r - pivot)/(1 - pivot);
+ return (r - pivot) / (1 - pivot);
} else {
return 0;
}
@@ -536,7 +586,7 @@
if (r < pivot) {
return 0;
} else {
- return (r-pivot)/(1-pivot);
+ return (r - pivot) / (1 - pivot);
}
}
@@ -553,13 +603,15 @@
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
+ int stackDirection = (mStackMode == ITEMS_SLIDE_UP) ? 1 : -1;
+
switch (mMode) {
case NORMAL_MODE:
- viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ viewLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-r * stackDirection * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
- float alpha = viewAlphaInterpolator(1-r);
+ float alpha = viewAlphaInterpolator(1 - r);
// We make sure that views which can't be seen (have 0 alpha) are also invisible
// so that they don't interfere with click events.
@@ -571,19 +623,19 @@
}
mView.setAlpha(alpha);
- mView.setRotationX(90.0f*rotationInterpolator(r));
- mHighlight.setRotationX(90.0f*rotationInterpolator(r));
+ mView.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
+ mHighlight.setRotationX(stackDirection * 90.0f * rotationInterpolator(r));
break;
case BEGINNING_OF_STACK_MODE:
- r = r*0.2f;
- viewLp.setVerticalOffset(Math.round(-r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(-r*mViewHeight));
+ r = r * 0.2f;
+ viewLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(-stackDirection * r * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
break;
case END_OF_STACK_MODE:
- r = (1-r)*0.2f;
- viewLp.setVerticalOffset(Math.round(r*mViewHeight));
- highlightLp.setVerticalOffset(Math.round(r*mViewHeight));
+ r = (1-r) * 0.2f;
+ viewLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
+ highlightLp.setVerticalOffset(Math.round(stackDirection * r * mViewHeight));
mHighlight.setAlpha(highlightAlphaInterpolator(r));
break;
}
@@ -600,8 +652,8 @@
final LayoutParams highlightLp = (LayoutParams) mHighlight.getLayoutParams();
r *= 0.2f;
- viewLp.setHorizontalOffset(Math.round(r*mViewHeight));
- highlightLp.setHorizontalOffset(Math.round(r*mViewHeight));
+ viewLp.setHorizontalOffset(Math.round(r * mViewHeight));
+ highlightLp.setHorizontalOffset(Math.round(r * mViewHeight));
}
void setMode(int mode) {
@@ -609,31 +661,51 @@
}
float getDurationForNeutralPosition() {
- return getDuration(false);
+ return getDuration(false, 0);
}
float getDurationForOffscreenPosition() {
- return getDuration(mMode == END_OF_STACK_MODE ? false : true);
+ return getDuration(true, 0);
}
- private float getDuration(boolean invert) {
+ float getDurationForNeutralPosition(float velocity) {
+ return getDuration(false, velocity);
+ }
+
+ float getDurationForOffscreenPosition(float velocity) {
+ return getDuration(true, velocity);
+ }
+
+ private float getDuration(boolean invert, float velocity) {
if (mView != null) {
final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams();
- float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset,2) +
- Math.pow(viewLp.verticalOffset,2));
+ float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset, 2) +
+ Math.pow(viewLp.verticalOffset, 2));
float maxd = (float) Math.sqrt(Math.pow(mViewHeight, 2) +
- Math.pow(0.4f*mViewHeight, 2));
- return invert ? (1-d/maxd) : d/maxd;
+ Math.pow(0.4f * mViewHeight, 2));
+
+ if (velocity == 0) {
+ return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION;
+ } else {
+ float duration = invert ? d / Math.abs(velocity) :
+ (maxd - d) / Math.abs(velocity);
+ if (duration < MINIMUM_ANIMATION_DURATION ||
+ duration > DEFAULT_ANIMATION_DURATION) {
+ return getDuration(invert, 0);
+ } else {
+ return duration;
+ }
+ }
}
return 0;
}
- float getYProgress() {
+ public float getYProgress() {
return mYProgress;
}
- float getXProgress() {
+ public float getXProgress() {
return mXProgress;
}
}
@@ -654,6 +726,8 @@
LayoutParams lp = (LayoutParams) currentLp;
lp.setHorizontalOffset(0);
lp.setVerticalOffset(0);
+ lp.width = 0;
+ lp.width = 0;
return lp;
}
return new LayoutParams(v);
@@ -684,15 +758,59 @@
child.layout(mPaddingLeft + lp.horizontalOffset, mPaddingTop + lp.verticalOffset,
childRight + lp.horizontalOffset, childBottom + lp.verticalOffset);
- //TODO: temp until fix in View
- child.setPivotX(child.getMeasuredWidth()/2);
- child.setPivotY(child.getMeasuredHeight()/2);
}
mDataChanged = false;
onLayout();
}
+ private void measureChildren() {
+ final int count = getChildCount();
+ final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
+ final int childHeight = Math.round(mMeasuredHeight*(1-PERSPECTIVE_SHIFT_FACTOR))
+ - mPaddingTop - mPaddingBottom;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ child.measure(MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
+ final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ boolean haveChildRefSize = (mReferenceChildWidth != -1 && mReferenceChildHeight != -1);
+
+ // We need to deal with the case where our parent hasn't told us how
+ // big we should be. In this case we should
+ float factor = 1/(1 - PERSPECTIVE_SHIFT_FACTOR);
+ if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+ heightSpecSize = haveChildRefSize ?
+ Math.round(mReferenceChildHeight * (1 + factor)) +
+ mPaddingTop + mPaddingBottom : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ heightSpecSize = haveChildRefSize ? Math.min(
+ Math.round(mReferenceChildHeight * (1 + factor)) + mPaddingTop +
+ mPaddingBottom, heightSpecSize) : 0;
+ }
+
+ if (widthSpecMode == MeasureSpec.UNSPECIFIED) {
+ widthSpecSize = haveChildRefSize ? mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight : 0;
+ } else if (heightSpecMode == MeasureSpec.AT_MOST) {
+ widthSpecSize = haveChildRefSize ? Math.min(mReferenceChildWidth + mPaddingLeft +
+ mPaddingRight, widthSpecSize) : 0;
+ }
+
+ setMeasuredDimension(widthSpecSize, heightSpecSize);
+ measureChildren();
+ }
+
class LayoutParams extends ViewGroup.LayoutParams {
int horizontalOffset;
int verticalOffset;
@@ -700,6 +818,8 @@
LayoutParams(View view) {
super(0, 0);
+ width = 0;
+ height = 0;
horizontalOffset = 0;
verticalOffset = 0;
mView = view;
@@ -709,6 +829,8 @@
super(c, attrs);
horizontalOffset = 0;
verticalOffset = 0;
+ width = 0;
+ height = 0;
}
private Rect parentRect = new Rect();
@@ -731,6 +853,10 @@
gp = (View) p.getParent();
parentRect.set(p.getLeft() - gp.getScrollX(), p.getTop() - gp.getScrollY(),
p.getRight() - gp.getScrollX(), p.getBottom() - gp.getScrollY());
+
+ // TODO: we need to stop early here if we've hit the edge of the screen
+ // so as to prevent us from walking too high in the hierarchy. A lot of this
+ // code might become a lot more straightforward.
}
if (depth > mAncestorHeight) {
@@ -799,7 +925,7 @@
private static class HolographicHelper {
private final Paint mHolographicPaint = new Paint();
private final Paint mErasePaint = new Paint();
- private final float STROKE_WIDTH = 3.0f;
+ private final Paint mBlurPaint = new Paint();
HolographicHelper() {
initializePaints();
@@ -808,8 +934,10 @@
void initializePaints() {
mHolographicPaint.setColor(0xff6699ff);
mHolographicPaint.setFilterBitmap(true);
+ mHolographicPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mErasePaint.setFilterBitmap(true);
+ mBlurPaint.setMaskFilter(new BlurMaskFilter(2, BlurMaskFilter.Blur.NORMAL));
}
Bitmap createOutline(View v) {
@@ -822,31 +950,31 @@
Canvas canvas = new Canvas(bitmap);
float rotationX = v.getRotationX();
+ float rotation = v.getRotation();
+ float translationY = v.getTranslationY();
v.setRotationX(0);
+ v.setRotation(0);
+ v.setTranslationY(0);
canvas.concat(v.getMatrix());
v.draw(canvas);
-
v.setRotationX(rotationX);
+ v.setRotation(rotation);
+ v.setTranslationY(translationY);
+ canvas.setMatrix(id);
drawOutline(canvas, bitmap);
return bitmap;
}
final Matrix id = new Matrix();
- final Matrix scaleMatrix = new Matrix();
void drawOutline(Canvas dest, Bitmap src) {
- Bitmap mask = src.extractAlpha();
-
+ int[] xy = new int[2];
+ Bitmap mask = src.extractAlpha(mBlurPaint, xy);
+ Canvas maskCanvas = new Canvas(mask);
+ maskCanvas.drawBitmap(src, -xy[0], -xy[1], mErasePaint);
dest.drawColor(0, PorterDuff.Mode.CLEAR);
-
- float xScale = STROKE_WIDTH*2/(dest.getWidth());
- float yScale = STROKE_WIDTH*2/(dest.getHeight());
-
- scaleMatrix.reset();
- scaleMatrix.preScale(1+xScale, 1+yScale, dest.getWidth()/2, dest.getHeight()/2);
dest.setMatrix(id);
- dest.drawBitmap(mask, scaleMatrix, mHolographicPaint);
- dest.drawBitmap(mask, id, mErasePaint);
+ dest.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
mask.recycle();
}
}
diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp
index 4b3f1c0..36e9089 100644
--- a/core/jni/android_database_SQLiteDatabase.cpp
+++ b/core/jni/android_database_SQLiteDatabase.cpp
@@ -593,6 +593,9 @@
case SQLITE_MISMATCH:
exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
break;
+ case SQLITE_UNCLOSED:
+ exceptionClass = "android/database/sqlite/SQLiteUnfinalizedObjectsException";
+ break;
default:
exceptionClass = "android/database/sqlite/SQLiteException";
break;
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
new file mode 100644
index 0000000..cd2005d
--- /dev/null
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteUnfinalizedExceptionTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database.sqlite;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabaseTest.ClassToTestSqlCompilationAndCaching;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.File;
+
+public class SQLiteUnfinalizedExceptionTest extends AndroidTestCase {
+ private SQLiteDatabase mDatabase;
+ private File mDatabaseFile;
+ private static final String TABLE_NAME = "testCursor";
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
+ mDatabaseFile = new File(dbDir, "UnfinalizedExceptionTest.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+ assertNotNull(mDatabase);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ super.tearDown();
+ }
+
+ @SmallTest
+ public void testUnfinalizedExceptionNotExcpected() {
+ mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+ // the above statement should be in SQLiteDatabase.mPrograms
+ // and should automatically be finalized when database is closed
+ mDatabase.lock();
+ try {
+ mDatabase.closeDatabase();
+ } finally {
+ mDatabase.unlock();
+ }
+ }
+
+ @SmallTest
+ public void testUnfinalizedException() {
+ mDatabase.execSQL("CREATE TABLE " + TABLE_NAME + " (i int, j int);");
+ mDatabase.lock();
+ mDatabase.closePendingStatements(); // clears the above from finalizer queue in mdatabase
+ mDatabase.unlock();
+ ClassToTestSqlCompilationAndCaching.create(mDatabase, "select * from " + TABLE_NAME);
+ // since the above is NOT closed, closing database should fail
+ mDatabase.lock();
+ try {
+ mDatabase.closeDatabase();
+ fail("exception expected");
+ } catch (SQLiteUnfinalizedObjectsException e) {
+ // expected
+ } finally {
+ mDatabase.unlock();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 60c3c76..c8ad60d 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -285,6 +285,7 @@
assertEquals("d", uri.getQueryParameter("c"));
}
+ // http://b/2337042
@SmallTest
public void testHostWithTrailingDot() {
Uri uri = Uri.parse("http://google.com./b/c/g");
diff --git a/core/tests/coretests/src/android/net/WebAddressTest.java b/core/tests/coretests/src/android/net/WebAddressTest.java
index 7ca1e62..f0af35d 100644
--- a/core/tests/coretests/src/android/net/WebAddressTest.java
+++ b/core/tests/coretests/src/android/net/WebAddressTest.java
@@ -22,10 +22,19 @@
public class WebAddressTest extends TestCase {
+ // http://b/2337042
@SmallTest
public void testHostWithTrailingDot() {
WebAddress webAddress = new WebAddress("http://google.com./b/c/g");
assertEquals("google.com.", webAddress.mHost);
assertEquals("/b/c/g", webAddress.mPath);
}
+
+ // http://b/1011602
+ @SmallTest
+ public void testPathWithoutLeadingSlash() {
+ WebAddress webAddress = new WebAddress("http://www.myspace.com?si=1");
+ assertEquals("www.myspace.com", webAddress.mHost);
+ assertEquals("/?si=1", webAddress.mPath);
+ }
}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index ed09f89..05b2d60 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -27,6 +27,7 @@
int mSize;
Element[] mElements;
String[] mElementNames;
+ int[] mArraySizes;
DataType mType;
DataKind mKind;
@@ -313,11 +314,12 @@
return rs.mElement_MATRIX_2X2;
}
- Element(int id, RenderScript rs, Element[] e, String[] n) {
+ Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
super(id, rs);
mSize = 0;
mElements = e;
mElementNames = n;
+ mArraySizes = as;
for (int ct = 0; ct < mElements.length; ct++ ) {
mSize += mElements[ct].mSize;
}
@@ -441,6 +443,7 @@
RenderScript mRS;
Element[] mElements;
String[] mElementNames;
+ int[] mArraySizes;
int mCount;
public Builder(RenderScript rs) {
@@ -448,35 +451,49 @@
mCount = 0;
mElements = new Element[8];
mElementNames = new String[8];
+ mArraySizes = new int[8];
}
- public void add(Element element, String name) {
+ public void add(Element element, String name, int arraySize) {
+ if (arraySize < 1) {
+ throw new IllegalArgumentException("Array size cannot be less than 1.");
+ }
if(mCount == mElements.length) {
Element[] e = new Element[mCount + 8];
String[] s = new String[mCount + 8];
+ int[] as = new int[mCount + 8];
System.arraycopy(mElements, 0, e, 0, mCount);
System.arraycopy(mElementNames, 0, s, 0, mCount);
+ System.arraycopy(mArraySizes, 0, as, 0, mCount);
mElements = e;
mElementNames = s;
+ mArraySizes = as;
}
mElements[mCount] = element;
mElementNames[mCount] = name;
+ mArraySizes[mCount] = arraySize;
mCount++;
}
+ public void add(Element element, String name) {
+ add(element, name, 1);
+ }
+
public Element create() {
mRS.validate();
Element[] ein = new Element[mCount];
String[] sin = new String[mCount];
+ int[] asin = new int[mCount];
java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
+ java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
int[] ids = new int[ein.length];
for (int ct = 0; ct < ein.length; ct++ ) {
ids[ct] = ein[ct].mID;
}
- int id = mRS.nElementCreate2(ids, sin);
- return new Element(id, mRS, ein, sin);
+ int id = mRS.nElementCreate2(ids, sin, asin);
+ return new Element(id, mRS, ein, sin, asin);
}
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 62d70a7..1f3e159 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -152,9 +152,9 @@
synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) {
return rsnElementCreate(mContext, type, kind, norm, vecSize);
}
- native int rsnElementCreate2(int con, int[] elements, String[] names);
- synchronized int nElementCreate2(int[] elements, String[] names) {
- return rsnElementCreate2(mContext, elements, names);
+ native int rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes);
+ synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) {
+ return rsnElementCreate2(mContext, elements, names, arraySizes);
}
native void rsnElementGetNativeData(int con, int id, int[] elementData);
synchronized void nElementGetNativeData(int id, int[] elementData) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index c8e6656..f07dbfd8 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -253,12 +253,13 @@
}
static jint
-nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names)
+nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes)
{
int fieldCount = _env->GetArrayLength(_ids);
LOG_API("nElementCreate2, con(%p)", con);
jint *ids = _env->GetIntArrayElements(_ids, NULL);
+ jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
@@ -267,12 +268,13 @@
nameArray[ct] = _env->GetStringUTFChars(s, NULL);
sizeArray[ct] = _env->GetStringUTFLength(s);
}
- jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray);
+ jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray, (const uint32_t *)arraySizes);
for (int ct=0; ct < fieldCount; ct++) {
jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
_env->ReleaseStringUTFChars(s, nameArray[ct]);
}
_env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
+ _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
free(nameArray);
free(sizeArray);
return (jint)id;
@@ -1230,7 +1232,7 @@
{"rsnFontCreateFromFile", "(ILjava/lang/String;II)I", (void*)nFontCreateFromFile },
{"rsnElementCreate", "(IIIZI)I", (void*)nElementCreate },
-{"rsnElementCreate2", "(I[I[Ljava/lang/String;)I", (void*)nElementCreate2 },
+{"rsnElementCreate2", "(I[I[Ljava/lang/String;[I)I", (void*)nElementCreate2 },
{"rsnElementGetNativeData", "(II[I)V", (void*)nElementGetNativeData },
{"rsnElementGetSubElements", "(II[I[Ljava/lang/String;)V", (void*)nElementGetSubElements },
diff --git a/libs/rs/java/ModelViewer/res/raw/robot.a3d b/libs/rs/java/ModelViewer/res/raw/robot.a3d
index 2d7d32b..f48895c 100644
--- a/libs/rs/java/ModelViewer/res/raw/robot.a3d
+++ b/libs/rs/java/ModelViewer/res/raw/robot.a3d
Binary files differ
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
index 9672a6a..85c1d42 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
@@ -105,7 +105,7 @@
bs.setMin(Sampler.Value.LINEAR);
bs.setMag(Sampler.Value.LINEAR);
bs.setWrapS(Sampler.Value.CLAMP);
- bs.setWrapT(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.CLAMP);
mSampler = bs.create();
ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -123,7 +123,6 @@
mPVA = new ProgramVertex.MatrixAllocation(mRS);
mPVBackground.bindAllocation(mPVA);
- mPVA.setupProjectionNormalized(mWidth, mHeight);
mScript.set_gPVBackground(mPVBackground);
}
@@ -159,14 +158,14 @@
mGroup1.addChild(mRobot1);
mGroup1.addChild(mRobot2);
- mGroup1.setTransform(0, new Float4(0.0f, 0.0f, 5.0f, 0.0f), TransformType.TRANSLATE);
+ mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE);
mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE);
- mRobot1.setTransform(0, new Float4(-2.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
+ mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE);
mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE);
mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE);
- mRobot2.setTransform(0, new Float4(2.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
+ mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE);
mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE);
mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE);
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
index b8b0119..d8d1a6e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
@@ -79,7 +79,7 @@
mRotation += 360;
}
- mScript.set_gRotate(-(float)mRotation);
+ mScript.set_gRotate((float)mRotation);
mLastX = x;
mLastY = y;
@@ -101,7 +101,7 @@
bs.setMin(Sampler.Value.LINEAR);
bs.setMag(Sampler.Value.LINEAR);
bs.setWrapS(Sampler.Value.CLAMP);
- bs.setWrapT(Sampler.Value.WRAP);
+ bs.setWrapT(Sampler.Value.CLAMP);
mSampler = bs.create();
ProgramFragment.Builder b = new ProgramFragment.Builder(mRS);
@@ -119,7 +119,6 @@
mPVA = new ProgramVertex.MatrixAllocation(mRS);
mPVBackground.bindAllocation(mPVA);
- mPVA.setupProjectionNormalized(mWidth, mHeight);
mScript.set_gPVBackground(mPVBackground);
}
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
index c794438..ce6bb1e 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/scenegraph.rs
@@ -71,6 +71,10 @@
rsgClearDepth(1.0f);
rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
rsgBindProgramFragment(gPFBackground);
rsgBindProgramStore(gPFSBackground);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
index adb609c..43be266 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/simplemodel.rs
@@ -46,6 +46,10 @@
rsgClearDepth(1.0f);
rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
rsgBindProgramFragment(gPFBackground);
rsgBindProgramStore(gPFSBackground);
@@ -54,9 +58,9 @@
rs_matrix4x4 matrix;
rsMatrixLoadIdentity(&matrix);
// Position our model on the screen
- rsMatrixTranslate(&matrix, 0.0f, -0.3f, 1.2f);
+ rsMatrixTranslate(&matrix, 0.0f, -0.3f, -10.0f);
rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
- rsMatrixRotate(&matrix, -25.0f, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&matrix, 25.0f, 1.0f, 0.0f, 0.0f);
rsMatrixRotate(&matrix, gRotate, 0.0f, 1.0f, 0.0f);
rsgProgramVertexLoadModelMatrix(&matrix);
diff --git a/libs/rs/java/Samples/res/raw/torus.a3d b/libs/rs/java/Samples/res/raw/torus.a3d
index d09bc13..0322b01 100644
--- a/libs/rs/java/Samples/res/raw/torus.a3d
+++ b/libs/rs/java/Samples/res/raw/torus.a3d
Binary files differ
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ad162bb..c7fb2af 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -80,6 +80,7 @@
param const RsElement * elements
param const char ** names
param const size_t * nameLengths
+ param const uint32_t * arraySize
ret RsElement
}
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 2602dd4..0b7bb27 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -65,7 +65,7 @@
size_t total = 0;
for (size_t ct=0; ct < mFieldCount; ct++) {
- total += mFields[ct].e->mBits;
+ total += mFields[ct].e->mBits * mFields[ct].arraySize;;
}
return total;
}
@@ -95,6 +95,7 @@
stream->addU32(mFieldCount);
for(uint32_t ct = 0; ct < mFieldCount; ct++) {
stream->addString(&mFields[ct].name);
+ stream->addU32(mFields[ct].arraySize);
mFields[ct].e->serialize(stream);
}
}
@@ -122,6 +123,7 @@
elem->mFields = new ElementField_t [elem->mFieldCount];
for(uint32_t ct = 0; ct < elem->mFieldCount; ct ++) {
stream->loadString(&elem->mFields[ct].name);
+ elem->mFields[ct].arraySize = stream->loadU32();
Element *fieldElem = Element::createFromStream(rsc, stream);
elem->mFields[ct].e.set(fieldElem);
elem->mFields[ct].offsetBits = offset;
@@ -155,7 +157,8 @@
for (uint32_t i=0; i < elem->mFieldCount; i++) {
if ((ee->mFields[i].e.get() != elem->mFields[i].e.get()) ||
(ee->mFields[i].name.length() != elem->mFields[i].name.length()) ||
- (ee->mFields[i].name != elem->mFields[i].name)) {
+ (ee->mFields[i].name != elem->mFields[i].name) ||
+ (ee->mFields[i].arraySize != elem->mFields[i].arraySize)) {
match = false;
break;
}
@@ -200,7 +203,7 @@
}
const Element * Element::create(Context *rsc, size_t count, const Element **ein,
- const char **nin, const size_t * lengths)
+ const char **nin, const size_t * lengths, const uint32_t *asin)
{
// Look for an existing match.
for (uint32_t ct=0; ct < rsc->mStateElement.mElements.size(); ct++) {
@@ -210,7 +213,8 @@
for (uint32_t i=0; i < count; i++) {
if ((ee->mFields[i].e.get() != ein[i]) ||
(ee->mFields[i].name.length() != lengths[i]) ||
- (ee->mFields[i].name != nin[i])) {
+ (ee->mFields[i].name != nin[i]) ||
+ (ee->mFields[i].arraySize != asin[i])) {
match = false;
break;
}
@@ -230,6 +234,7 @@
e->mFields[ct].e.set(ein[ct]);
e->mFields[ct].name.setTo(nin[ct], lengths[ct]);
e->mFields[ct].offsetBits = bits;
+ e->mFields[ct].arraySize = asin[ct];
bits += ein[ct]->getSizeBits();
if (ein[ct]->mHasReference) {
@@ -274,7 +279,11 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- mFields[i].e->incRefs(&p[mFields[i].offsetBits >> 3]);
+ p = &p[mFields[i].offsetBits >> 3];
+ for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+ mFields[i].e->incRefs(p);
+ p += mFields[i].e->getSizeBytes();
+ }
}
}
}
@@ -293,7 +302,11 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- mFields[i].e->decRefs(&p[mFields[i].offsetBits >> 3]);
+ p = &p[mFields[i].offsetBits >> 3];
+ for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
+ mFields[i].e->decRefs(p);
+ p += mFields[i].e->getSizeBytes();
+ }
}
}
}
@@ -331,10 +344,11 @@
size_t count,
const RsElement * ein,
const char ** names,
- const size_t * nameLengths)
+ const size_t * nameLengths,
+ const uint32_t * arraySizes)
{
//LOGE("rsi_ElementCreate2 %i", count);
- const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
+ const Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths, arraySizes);
e->incUserRef();
return (RsElement)e;
}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index b5dad7a2..42eef4a 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -66,7 +66,7 @@
static const Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
bool isNorm, uint32_t vecSize);
static const Element * create(Context *rsc, size_t count, const Element **,
- const char **, const size_t * lengths);
+ const char **, const size_t * lengths, const uint32_t *asin);
void incRefs(const void *) const;
void decRefs(const void *) const;
@@ -80,6 +80,7 @@
String8 name;
ObjectBaseRef<const Element> e;
uint32_t offsetBits;
+ uint32_t arraySize;
} ElementField_t;
ElementField_t *mFields;
size_t mFieldCount;
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 7661d499..5889bfb 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -488,8 +488,9 @@
size_t lengths[2];
lengths[0] = posName.size();
lengths[1] = texName.size();
+ uint32_t arraySizes[2] = {1, 1};
- const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths);
+ const Element *vertexDataElem = Element::create(mRSC, 2, elemArray, nameArray, lengths, arraySizes);
Type *vertexDataType = new Type(mRSC);
vertexDataType->setDimX(mMaxNumberOfQuads * 4);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
index 33acecb..48243ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PhoneStatusBarService.java
@@ -39,6 +39,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.Log;
import android.view.Display;
@@ -468,7 +469,11 @@
}
// Restart the ticker if it's still running
- tick(notification);
+ if (notification.notification.tickerText != null
+ && !TextUtils.equals(notification.notification.tickerText,
+ oldEntry.notification.notification.tickerText)) {
+ tick(notification);
+ }
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();