diff options
22 files changed, 740 insertions, 232 deletions
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index 71a538268a73..5cc11505d6b9 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -31,23 +31,23 @@ import android.os.Build; public final class Sensor { /** - * A constant describing an accelerometer sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing an accelerometer sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_ACCELEROMETER = 1; /** - * A constant describing a magnetic field sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing a magnetic field sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_MAGNETIC_FIELD = 2; /** - * A constant describing an orientation sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing an orientation sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. * * @deprecated use {@link android.hardware.SensorManager#getOrientation * SensorManager.getOrientation()} instead. @@ -55,17 +55,21 @@ public final class Sensor { @Deprecated public static final int TYPE_ORIENTATION = 3; - /** A constant describing a gyroscope sensor type */ + /** A constant describing a gyroscope sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_GYROSCOPE = 4; /** - * A constant describing a light sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing a light sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_LIGHT = 5; - /** A constant describing a pressure sensor type */ + /** A constant describing a pressure sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_PRESSURE = 6; /** @@ -79,60 +83,66 @@ public final class Sensor { public static final int TYPE_TEMPERATURE = 7; /** - * A constant describing a proximity sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing a proximity sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_PROXIMITY = 8; /** * A constant describing a gravity sensor type. - * See {@link android.hardware.SensorEvent SensorEvent} + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} * for more details. */ public static final int TYPE_GRAVITY = 9; /** * A constant describing a linear acceleration sensor type. - * See {@link android.hardware.SensorEvent SensorEvent} + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} * for more details. */ public static final int TYPE_LINEAR_ACCELERATION = 10; /** * A constant describing a rotation vector sensor type. - * See {@link android.hardware.SensorEvent SensorEvent} + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} * for more details. */ public static final int TYPE_ROTATION_VECTOR = 11; /** * A constant describing a relative humidity sensor type. - * See {@link android.hardware.SensorEvent SensorEvent} + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} * for more details. */ public static final int TYPE_RELATIVE_HUMIDITY = 12; - /** A constant describing an ambient temperature sensor type */ + /** A constant describing an ambient temperature sensor type. + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} + * for more details. */ public static final int TYPE_AMBIENT_TEMPERATURE = 13; /** - * A constant describing a magnetic field uncalibrated sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. + * A constant describing an uncalibrated magnetic field sensor type. * <p> - * Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (calibration - * due to distortions that arise from magnetized iron, steel or permanenet magnets - * on the device) is reported separately. No periodic calibration is performed - * (i.e. there are no discontinuities in the data stream while using this sensor). - * Assumptions that the magnetic field is due to the Earth's poles is avoided. - * Factory calibration and temperature compensation are still performed. + * Similar to {@link #TYPE_MAGNETIC_FIELD} but the hard iron calibration (device calibration + * due to distortions that arise from magnetized iron, steel or permanent magnets on the + * device) is not considered in the given sensor values. However, such hard iron bias values + * are returned to you separately in the result {@link android.hardware.SensorEvent#values} + * so you may use them for custom calibrations. + * <p>Also, no periodic calibration is performed + * (i.e. there are no discontinuities in the data stream while using this sensor) and + * assumptions that the magnetic field is due to the Earth's poles is avoided, but + * factory calibration and temperature compensation have been performed. * </p> + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more + * details. */ public static final int TYPE_MAGNETIC_FIELD_UNCALIBRATED = 14; /** - * Identical to {@link #TYPE_ROTATION_VECTOR} except that it doesn't + * A constant describing an uncalibrated rotation vector sensor type. + * <p>Identical to {@link #TYPE_ROTATION_VECTOR} except that it doesn't * use the geomagnetic field. Therefore the Y axis doesn't * point north, but instead to some other reference, that reference is * allowed to drift by the same order of magnitude as the gyroscope @@ -143,32 +153,35 @@ public final class Sensor { * (without using the earth's geomagnetic field). However, the orientation * may drift somewhat over time. * </p> + * <p>See {@link android.hardware.SensorEvent#values SensorEvent.values} for more + * details. */ public static final int TYPE_GAME_ROTATION_VECTOR = 15; /** - * A constant describing a gyroscope uncalibrated sensor type. See - * {@link android.hardware.SensorEvent#values SensorEvent.values} for more - * details. - * <p> - * No gyro-drift compensation is performed. - * Factory calibration and temperature compensation is still applied + * A constant describing an uncalibrated gyroscope sensor type. + * <p>Similar to {@link #TYPE_GYROSCOPE} but no gyro-drift compensation has been performed + * to adjust the given sensor values. However, such gyro-drift bias values + * are returned to you separately in the result {@link android.hardware.SensorEvent#values} + * so you may use them for custom calibrations. + * <p>Factory calibration and temperature compensation is still applied * to the rate of rotation (angular speeds). * </p> + * <p> See {@link android.hardware.SensorEvent#values SensorEvent.values} for more + * details. */ public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; /** * A constant describing the significant motion trigger sensor. - * See {@link android.hardware.SensorEvent#values} for more details. * <p> * It triggers when an event occurs and then automatically disables * itself. The sensor continues to operate while the device is asleep * and will automatically wake the device to notify when significant * motion is detected. The application does not need to hold any wake * locks for this sensor to trigger. - * </p> + * <p>See {@link TriggerEvent} for more details. */ public static final int TYPE_SIGNIFICANT_MOTION = 17; diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 97b0cef0d0ec..2bc0f9bbde66 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -402,10 +402,9 @@ public class SensorEvent { * <li> values[0]: ambient (room) temperature in degree Celsius.</li> * </ul> * - * @see SensorEvent - * @see GeomagneticField * - * <h4>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED} </h4> + * <h4>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED + * Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED}:</h4> * Similar to {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD}, * but the hard iron calibration is reported separately instead of being included * in the measurement. Factory calibration and temperature compensation will still @@ -437,7 +436,7 @@ public class SensorEvent { * Soft iron - These distortions arise due to the interaction with the earth's magentic * field. * </p> - * <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR} </h4> + * <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4> * Identical to {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR} except that it * doesn't use the geomagnetic field. Therefore the Y axis doesn't * point north, but instead to some other reference, that reference is @@ -452,7 +451,8 @@ public class SensorEvent { * the estimated heading accuracy value. * </p> * - * <h4> {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED} </h4> + * <h4> {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED + * Sensor.TYPE_GYROSCOPE_UNCALIBRATED}:</h4> * All values are in radians/second and measure the rate of rotation * around the X, Y and Z axis. An estimation of the drift on each axis is * reported as well. @@ -477,9 +477,10 @@ public class SensorEvent { * <li> values[5] : estimated drift around Z axis in rad/s </li> * </ul> * </p> - * <h4></h4> - * <h4> Pro Tip: Always use the length of the values array while performing operations - * on it. In earlier versions, this used to be always 3 which has changed now. </h4> + * <p><b>Pro Tip:</b> Always use the length of the values array while performing operations + * on it. In earlier versions, this used to be always 3 which has changed now. </p> + * + * @see GeomagneticField */ public final float[] values; diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 45524c82c9e2..3088585674e1 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -344,6 +344,30 @@ interface INetworkManagementService void setFirewallUidRule(int uid, boolean allow); /** + * Set all packets from users [uid_start,uid_end] to go through interface iface + * iface must already be set for marked forwarding by {@link setMarkedForwarding} + */ + void setUidRangeRoute(String iface, int uid_start, int uid_end); + + /** + * Clears the special routing rules for users [uid_start,uid_end] + */ + void clearUidRangeRoute(String iface, int uid_start, int uid_end); + + /** + * Setup an interface for routing packets marked by {@link setUidRangeRoute} + * + * This sets up a dedicated routing table for packets marked for {@code iface} and adds + * source-NAT rules so that the marked packets have the correct source address. + */ + void setMarkedForwarding(String iface); + + /** + * Removes marked forwarding for an interface + */ + void clearMarkedForwarding(String iface); + + /** * Set a process (pid) to use the name servers associated with the specified interface. */ void setDnsInterfaceForPid(String iface, int pid); @@ -354,6 +378,21 @@ interface INetworkManagementService void clearDnsInterfaceForPid(int pid); /** + * Set a range of user ids to use the name servers associated with the specified interface. + */ + void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end); + + /** + * Clear a user range from being associated with an interface. + */ + void clearDnsInterfaceForUidRange(int uid_start, int uid_end); + + /** + * Clear the mappings from pid to Dns interface and from uid range to Dns interface. + */ + void clearDnsInterfaceMaps(); + + /** * Start the clatd (464xlat) service */ void startClatd(String interfaceName); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 3447494ca338..1b7fd1ebc1e8 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2805,7 +2805,9 @@ public final class ViewRootImpl implements ViewParent, setAccessibilityFocus(null, null); - mView.assignParent(null); + if (mView != null) { + mView.assignParent(null); + } mView = null; mAttachInfo.mRootView = null; mAttachInfo.mSurface = null; diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index c89c91ee82fa..f0d80e6b2d0a 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -1467,7 +1468,7 @@ public class HorizontalScrollView extends FrameLayout { mIsLayoutDirty = false; // Give a child focus if it needs it if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) { - scrollToChild(mChildToScrollTo); + scrollToChild(mChildToScrollTo); } mChildToScrollTo = null; @@ -1641,6 +1642,12 @@ public class HorizontalScrollView extends FrameLayout { @Override protected void onRestoreInstanceState(Parcelable state) { + if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) { + // Some old apps reused IDs in ways they shouldn't have. + // Don't break them, but they don't get scroll state restoration. + super.onRestoreInstanceState(state); + return; + } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mSavedState = ss; @@ -1649,6 +1656,11 @@ public class HorizontalScrollView extends FrameLayout { @Override protected Parcelable onSaveInstanceState() { + if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) { + // Some old apps reused IDs in ways they shouldn't have. + // Don't break them, but they don't get scroll state restoration. + return super.onSaveInstanceState(); + } Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.scrollPosition = mScrollX; diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index ee22811ffce6..d990a20d4785 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -2073,17 +2073,61 @@ public class ListView extends AbsListView { position--; } } + } + + if (position < 0 || position >= count) { + return INVALID_POSITION; + } + + return position; + } - if (position < 0 || position >= count) { + /** + * Find a position that can be selected (i.e., is not a separator). If there + * are no selectable positions in the specified direction from the starting + * position, searches in the opposite direction from the starting position + * to the current position. + * + * @param current the current position + * @param position the starting position + * @param lookDown whether to look down for other positions + * @return the next selectable position, or {@link #INVALID_POSITION} if + * nothing can be found + */ + int lookForSelectablePositionAfter(int current, int position, boolean lookDown) { + final ListAdapter adapter = mAdapter; + if (adapter == null || isInTouchMode()) { + return INVALID_POSITION; + } + + // First check after the starting position in the specified direction. + final int after = lookForSelectablePosition(position, lookDown); + if (after != INVALID_POSITION) { + return after; + } + + // Then check between the starting position and the current position. + final int count = adapter.getCount(); + current = MathUtils.constrain(current, -1, count - 1); + if (lookDown) { + position = Math.min(position - 1, count - 1); + while ((position > current) && !adapter.isEnabled(position)) { + position--; + } + if (position <= current) { return INVALID_POSITION; } - return position; } else { - if (position < 0 || position >= count) { + position = Math.max(0, position + 1); + while ((position < current) && !adapter.isEnabled(position)) { + position++; + } + if (position >= current) { return INVALID_POSITION; } - return position; } + + return position; } /** @@ -2296,27 +2340,30 @@ public class ListView extends AbsListView { * @return whether selection was moved */ boolean pageScroll(int direction) { - int nextPage = -1; - boolean down = false; + final int nextPage; + final boolean down; if (direction == FOCUS_UP) { nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1); + down = false; } else if (direction == FOCUS_DOWN) { nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1); down = true; + } else { + return false; } if (nextPage >= 0) { - int position = lookForSelectablePosition(nextPage, down); + final int position = lookForSelectablePositionAfter(mSelectedPosition, nextPage, down); if (position >= 0) { mLayoutMode = LAYOUT_SPECIFIC; mSpecificTop = mPaddingTop + getVerticalFadingEdgeLength(); - if (down && position > mItemCount - getChildCount()) { + if (down && (position > (mItemCount - getChildCount()))) { mLayoutMode = LAYOUT_FORCE_BOTTOM; } - if (!down && position < getChildCount()) { + if (!down && (position < getChildCount())) { mLayoutMode = LAYOUT_FORCE_TOP; } @@ -2334,18 +2381,18 @@ public class ListView extends AbsListView { } /** - * Go to the last or first item if possible (not worrying about panning across or navigating - * within the internal focus of the currently selected item.) + * Go to the last or first item if possible (not worrying about panning + * across or navigating within the internal focus of the currently selected + * item.) * * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} - * * @return whether selection was moved */ boolean fullScroll(int direction) { boolean moved = false; if (direction == FOCUS_UP) { if (mSelectedPosition != 0) { - int position = lookForSelectablePosition(0, true); + final int position = lookForSelectablePositionAfter(mSelectedPosition, 0, true); if (position >= 0) { mLayoutMode = LAYOUT_FORCE_TOP; setSelectionInt(position); @@ -2354,8 +2401,10 @@ public class ListView extends AbsListView { moved = true; } } else if (direction == FOCUS_DOWN) { - if (mSelectedPosition < mItemCount - 1) { - int position = lookForSelectablePosition(mItemCount - 1, true); + final int lastItem = (mItemCount - 1); + if (mSelectedPosition < lastItem) { + final int position = lookForSelectablePositionAfter( + mSelectedPosition, lastItem, false); if (position >= 0) { mLayoutMode = LAYOUT_FORCE_BOTTOM; setSelectionInt(position); diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index b764c98843fb..b32cfbc04604 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -16,6 +16,7 @@ package android.widget; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import com.android.internal.R; @@ -1662,6 +1663,12 @@ public class ScrollView extends FrameLayout { @Override protected void onRestoreInstanceState(Parcelable state) { + if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) { + // Some old apps reused IDs in ways they shouldn't have. + // Don't break them, but they don't get scroll state restoration. + super.onRestoreInstanceState(state); + return; + } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); mSavedState = ss; @@ -1670,6 +1677,11 @@ public class ScrollView extends FrameLayout { @Override protected Parcelable onSaveInstanceState() { + if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR2) { + // Some old apps reused IDs in ways they shouldn't have. + // Don't break them, but they don't get scroll state restoration. + return super.onSaveInstanceState(); + } Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.scrollPosition = mScrollY; diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 58664049657b..f3592a31b642 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -298,7 +298,7 @@ static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject cl static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) { - return renderer->quickReject(left, top, right, bottom); + return renderer->quickRejectNoScissor(left, top, right, bottom); } static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz, diff --git a/docs/html/tools/help/draw9patch.jd b/docs/html/tools/help/draw9patch.jd index 7cf0e4b1d861..ebf2c6c681a3 100644 --- a/docs/html/tools/help/draw9patch.jd +++ b/docs/html/tools/help/draw9patch.jd @@ -1,6 +1,5 @@ page.title=Draw 9-patch -parent.title=Tools -parent.link=index.html +page.tags="NinePatch" @jd:body <p>The Draw 9-patch tool allows you to easily create a diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index e75ec753062a..f9cd4e261170 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -23,6 +23,7 @@ import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.SystemClock; +import android.util.SparseArray; /** * A helper class that contains several {@link Drawable}s and selects which one to use. @@ -76,7 +77,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { | mDrawableContainerState.mChangingConfigurations | mDrawableContainerState.mChildrenChangingConfigurations; } - + @Override public boolean getPadding(Rect padding) { final Rect r = mDrawableContainerState.getConstantPadding(); @@ -137,7 +138,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } } - + /** * Change the global fade duration when a new drawable is entering * the scene. @@ -146,7 +147,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { public void setEnterFadeDuration(int ms) { mDrawableContainerState.mEnterFadeDuration = ms; } - + /** * Change the global fade duration when a new drawable is leaving * the scene. @@ -155,7 +156,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { public void setExitFadeDuration(int ms) { mDrawableContainerState.mExitFadeDuration = ms; } - + @Override protected void onBoundsChange(Rect bounds) { if (mLastDrawable != null) { @@ -165,12 +166,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mCurrDrawable.setBounds(bounds); } } - + @Override public boolean isStateful() { return mDrawableContainerState.isStateful(); } - + @Override public void jumpToCurrentState() { boolean changed = false; @@ -233,7 +234,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1; } - + @Override public int getMinimumWidth() { if (mDrawableContainerState.isConstantSize()) { @@ -316,7 +317,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { - Drawable d = mDrawableContainerState.mDrawables[idx]; + final Drawable d = mDrawableContainerState.getChild(idx); mCurrDrawable = d; mCurIndex = idx; if (d != null) { @@ -358,7 +359,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return true; } - + void animate(boolean schedule) { final long now = SystemClock.uptimeMillis(); boolean animating = false; @@ -432,90 +433,105 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { */ public abstract static class DrawableContainerState extends ConstantState { final DrawableContainer mOwner; + final Resources mRes; + + SparseArray<ConstantStateFuture> mDrawableFutures; - int mChangingConfigurations; - int mChildrenChangingConfigurations; - - Drawable[] mDrawables; - int mNumChildren; + int mChangingConfigurations; + int mChildrenChangingConfigurations; - boolean mVariablePadding = false; - Rect mConstantPadding = null; + Drawable[] mDrawables; + int mNumChildren; - boolean mConstantSize = false; - boolean mComputedConstantSize = false; - int mConstantWidth; - int mConstantHeight; - int mConstantMinimumWidth; - int mConstantMinimumHeight; + boolean mVariablePadding; + boolean mPaddingChecked; + Rect mConstantPadding; - int mOpacity; + boolean mConstantSize; + boolean mComputedConstantSize; + int mConstantWidth; + int mConstantHeight; + int mConstantMinimumWidth; + int mConstantMinimumHeight; - boolean mHaveStateful = false; - boolean mStateful; + boolean mCheckedOpacity; + int mOpacity; - boolean mCheckedConstantState; - boolean mCanConstantState; + boolean mCheckedStateful; + boolean mStateful; - boolean mPaddingChecked = false; - - boolean mDither = DEFAULT_DITHER; + boolean mCheckedConstantState; + boolean mCanConstantState; - int mEnterFadeDuration; - int mExitFadeDuration; + boolean mDither = DEFAULT_DITHER; + + boolean mMutated; + int mLayoutDirection; + + int mEnterFadeDuration; + int mExitFadeDuration; DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; + mRes = res; if (orig != null) { mChangingConfigurations = orig.mChangingConfigurations; mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations; - - final Drawable[] origDr = orig.mDrawables; - mDrawables = new Drawable[origDr.length]; - mNumChildren = orig.mNumChildren; - - final int N = mNumChildren; - for (int i=0; i<N; i++) { - if (res != null) { - mDrawables[i] = origDr[i].getConstantState().newDrawable(res); - } else { - mDrawables[i] = origDr[i].getConstantState().newDrawable(); - } - mDrawables[i].setCallback(owner); - mDrawables[i].setLayoutDirection(origDr[i].getLayoutDirection()); - } + mCheckedConstantState = true; + mCanConstantState = true; - mCheckedConstantState = mCanConstantState = true; mVariablePadding = orig.mVariablePadding; - if (orig.mConstantPadding != null) { - mConstantPadding = new Rect(orig.mConstantPadding); - } mConstantSize = orig.mConstantSize; - mComputedConstantSize = orig.mComputedConstantSize; - mConstantWidth = orig.mConstantWidth; - mConstantHeight = orig.mConstantHeight; - mConstantMinimumWidth = orig.mConstantMinimumWidth; - mConstantMinimumHeight = orig.mConstantMinimumHeight; - - mOpacity = orig.mOpacity; - mHaveStateful = orig.mHaveStateful; - mStateful = orig.mStateful; - mDither = orig.mDither; - + mMutated = orig.mMutated; + mLayoutDirection = orig.mLayoutDirection; mEnterFadeDuration = orig.mEnterFadeDuration; mExitFadeDuration = orig.mExitFadeDuration; + // Cloning the following values may require creating futures. + mConstantPadding = orig.getConstantPadding(); + mPaddingChecked = true; + + mConstantWidth = orig.getConstantWidth(); + mConstantHeight = orig.getConstantHeight(); + mConstantMinimumWidth = orig.getConstantMinimumWidth(); + mConstantMinimumHeight = orig.getConstantMinimumHeight(); + mComputedConstantSize = true; + + mOpacity = orig.getOpacity(); + mCheckedOpacity = true; + + mStateful = orig.isStateful(); + mCheckedStateful = true; + + // Postpone cloning children and futures until we're absolutely + // sure that we're done computing values for the original state. + final Drawable[] origDr = orig.mDrawables; + mDrawables = new Drawable[origDr.length]; + mNumChildren = orig.mNumChildren; + + final SparseArray<ConstantStateFuture> origDf = orig.mDrawableFutures; + if (origDf != null) { + mDrawableFutures = origDf.clone(); + } else { + mDrawableFutures = new SparseArray<ConstantStateFuture>(mNumChildren); + } + + final int N = mNumChildren; + for (int i = 0; i < N; i++) { + if (origDr[i] != null) { + mDrawableFutures.put(i, new ConstantStateFuture(origDr[i])); + } + } } else { mDrawables = new Drawable[10]; mNumChildren = 0; - mCheckedConstantState = mCanConstantState = false; } } - + @Override public int getChangingConfigurations() { return mChangingConfigurations | mChildrenChangingConfigurations; @@ -534,7 +550,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDrawables[pos] = dr; mNumChildren++; mChildrenChangingConfigurations |= dr.getChangingConfigurations(); - mHaveStateful = false; + mCheckedStateful = false; + mCheckedOpacity = false; mConstantPadding = null; mPaddingChecked = false; @@ -547,6 +564,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mDrawables.length; } + private final void createAllFutures() { + if (mDrawableFutures != null) { + final int futureCount = mDrawableFutures.size(); + for (int keyIndex = 0; keyIndex < futureCount; keyIndex++) { + final int index = mDrawableFutures.keyAt(keyIndex); + mDrawables[index] = mDrawableFutures.valueAt(keyIndex).get(this); + } + + mDrawableFutures = null; + } + } + public final int getChildCount() { return mNumChildren; } @@ -555,25 +584,65 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { * @deprecated Use {@link #getChild} instead. */ public final Drawable[] getChildren() { + // Create all futures for backwards compatibility. + createAllFutures(); + return mDrawables; } public final Drawable getChild(int index) { - return mDrawables[index]; + final Drawable result = mDrawables[index]; + if (result != null) { + return result; + } + + // Prepare future drawable if necessary. + if (mDrawableFutures != null) { + final int keyIndex = mDrawableFutures.indexOfKey(index); + if (keyIndex >= 0) { + final Drawable prepared = mDrawableFutures.valueAt(keyIndex).get(this); + mDrawables[index] = prepared; + mDrawableFutures.removeAt(keyIndex); + return prepared; + } + } + + return null; + } + + final void setLayoutDirection(int layoutDirection) { + // No need to call createAllFutures, since future drawables will + // change layout direction when they are prepared. + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; + for (int i = 0; i < N; i++) { + if (drawables[i] != null) { + drawables[i].setLayoutDirection(layoutDirection); + } + } + + mLayoutDirection = layoutDirection; } final void mutate() { - final int N = getChildCount(); + // No need to call createAllFutures, since future drawables will + // mutate when they are prepared. + final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - if (drawables[i] != null) drawables[i].mutate(); + if (drawables[i] != null) { + drawables[i].mutate(); + } } + + mMutated = true; } - /** A boolean value indicating whether to use the maximum padding value of - * all frames in the set (false), or to use the padding value of the frame - * being shown (true). Default value is false. - */ + /** + * A boolean value indicating whether to use the maximum padding value + * of all frames in the set (false), or to use the padding value of the + * frame being shown (true). Default value is false. + */ public final void setVariablePadding(boolean variable) { mVariablePadding = variable; } @@ -582,13 +651,16 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mVariablePadding) { return null; } - if (mConstantPadding != null || mPaddingChecked) { + + if ((mConstantPadding != null) || mPaddingChecked) { return mConstantPadding; } + createAllFutures(); + Rect r = null; final Rect t = new Rect(); - final int N = getChildCount(); + final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { if (drawables[i].getPadding(t)) { @@ -599,6 +671,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (t.bottom > r.bottom) r.bottom = t.bottom; } } + mPaddingChecked = true; return (mConstantPadding = r); } @@ -646,12 +719,14 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { protected void computeConstantSize() { mComputedConstantSize = true; - final int N = getChildCount(); + createAllFutures(); + + final int N = mNumChildren; final Drawable[] drawables = mDrawables; mConstantWidth = mConstantHeight = -1; mConstantMinimumWidth = mConstantMinimumHeight = 0; for (int i = 0; i < N; i++) { - Drawable dr = drawables[i]; + final Drawable dr = drawables[i]; int s = dr.getIntrinsicWidth(); if (s > mConstantWidth) mConstantWidth = s; s = dr.getIntrinsicHeight(); @@ -680,33 +755,45 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } public final int getOpacity() { - final int N = getChildCount(); + if (mCheckedOpacity) { + return mOpacity; + } + + createAllFutures(); + + mCheckedOpacity = true; + + final int N = mNumChildren; final Drawable[] drawables = mDrawables; - int op = N > 0 ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; + int op = (N > 0) ? drawables[0].getOpacity() : PixelFormat.TRANSPARENT; for (int i = 1; i < N; i++) { op = Drawable.resolveOpacity(op, drawables[i].getOpacity()); } + mOpacity = op; return op; } public final boolean isStateful() { - if (mHaveStateful) { + if (mCheckedStateful) { return mStateful; } - - boolean stateful = false; - final int N = getChildCount(); + + createAllFutures(); + + mCheckedStateful = true; + + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - if (mDrawables[i].isStateful()) { - stateful = true; - break; + if (drawables[i].isStateful()) { + mStateful = true; + return true; } } - - mStateful = stateful; - mHaveStateful = true; - return stateful; + + mStateful = false; + return false; } public void growArray(int oldSize, int newSize) { @@ -716,24 +803,60 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } public synchronized boolean canConstantState() { - if (!mCheckedConstantState) { - mCanConstantState = true; - final int N = mNumChildren; - for (int i=0; i<N; i++) { - if (mDrawables[i].getConstantState() == null) { - mCanConstantState = false; - break; - } + if (mCheckedConstantState) { + return mCanConstantState; + } + + createAllFutures(); + + mCheckedConstantState = true; + + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; + for (int i = 0; i < N; i++) { + if (drawables[i].getConstantState() == null) { + mCanConstantState = false; + return false; } - mCheckedConstantState = true; } - return mCanConstantState; + mCanConstantState = true; + return true; + } + + /** + * Class capable of cloning a Drawable from another Drawable's + * ConstantState. + */ + private static class ConstantStateFuture { + private final ConstantState mConstantState; + + private ConstantStateFuture(Drawable source) { + mConstantState = source.getConstantState(); + } + + /** + * Obtains and prepares the Drawable represented by this future. + * + * @param state the container into which this future will be placed + * @return a prepared Drawable + */ + public Drawable get(DrawableContainerState state) { + final Drawable result = (state.mRes == null) ? + mConstantState.newDrawable() : mConstantState.newDrawable(state.mRes); + result.setLayoutDirection(state.mLayoutDirection); + result.setCallback(state.mOwner); + + if (state.mMutated) { + result.mutate(); + } + + return result; + } } } - protected void setConstantState(DrawableContainerState state) - { + protected void setConstantState(DrawableContainerState state) { mDrawableContainerState = state; } } diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 5ecd296e92b5..e3c7bc586288 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -264,11 +264,11 @@ public class StateListDrawable extends DrawableContainer { /** @hide */ @Override public void setLayoutDirection(int layoutDirection) { - final int numStates = getStateCount(); - for (int i = 0; i < numStates; i++) { - getStateDrawable(i).setLayoutDirection(layoutDirection); - } super.setLayoutDirection(layoutDirection); + + // Let the container handle setting its own layout direction. Otherwise, + // we're accessing potentially unused states. + mStateListState.setLayoutDirection(layoutDirection); } static final class StateListState extends DrawableContainerState { diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 74aeddba1e7d..31b0f6aed649 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -145,7 +145,7 @@ void Caches::initStaticProperties() { gpuPixelBuffersEnabled = false; // OpenGL ES 3.0+ specific features - if (mExtensions.getMajorGlVersion() >= 3) { + if (mExtensions.hasPixelBufferObjects()) { char property[PROPERTY_VALUE_MAX]; if (property_get(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, property, "true") > 0) { gpuPixelBuffersEnabled = !strcmp(property, "true"); diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index f25ec2d8fc41..0d4dd1a9b66a 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -356,22 +356,26 @@ void DisplayList::outputViewProperties(const int level) { level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix)); } } + + bool clipToBoundsNeeded = mClipToBounds; if (mAlpha < 1) { if (mCaching) { ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); + clipToBoundsNeeded = false; // clipping done by layer } else if (!mHasOverlappingRendering) { ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); } else { int flags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (mClipToBounds) { + if (clipToBoundsNeeded) { flags |= SkCanvas::kClipToLayer_SaveFlag; + clipToBoundsNeeded = false; // clipping done by save layer } ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "", (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, (int)(mAlpha * 255), flags); } } - if (mClipToBounds && !mCaching) { + if (clipToBoundsNeeded) { ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f, (float) mRight - mLeft, (float) mBottom - mTop); } @@ -406,9 +410,11 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, renderer.concatMatrix(mTransformMatrix); } } + bool clipToBoundsNeeded = mClipToBounds; if (mAlpha < 1) { if (mCaching) { renderer.setOverrideLayerAlpha(mAlpha); + clipToBoundsNeeded = false; // clipping done by layer } else if (!mHasOverlappingRendering) { renderer.scaleAlpha(mAlpha); } else { @@ -416,15 +422,16 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, // have to pass it into this call. In fact, this information might be in the // location/size info that we store with the new native transform data. int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag; - if (mClipToBounds) { + if (clipToBoundsNeeded) { saveFlags |= SkCanvas::kClipToLayer_SaveFlag; + clipToBoundsNeeded = false; // clipping done by saveLayer } handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT, mClipToBounds); } } - if (mClipToBounds && !mCaching) { + if (clipToBoundsNeeded) { handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op), PROPERTY_SAVECOUNT, mClipToBounds); } diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index 649a7bc5d0b6..77006a43913d 100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp @@ -29,7 +29,7 @@ Dither::Dither(): mCaches(NULL), mInitialized(false), mDitherTexture(0) { void Dither::bindDitherTexture() { if (!mInitialized) { - bool useFloatTexture = Extensions::getInstance().getMajorGlVersion() >= 3; + bool useFloatTexture = Extensions::getInstance().hasFloatTextures(); glGenTextures(1, &mDitherTexture); mCaches->bindTexture(mDitherTexture); diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h index 3112244bfd38..5e574a6cbddf 100644 --- a/libs/hwui/Extensions.h +++ b/libs/hwui/Extensions.h @@ -42,6 +42,10 @@ public: inline bool has4BitStencil() const { return mHas4BitStencil; } inline bool hasNvSystemTime() const { return mHasNvSystemTime; } + inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; } + inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; } + inline bool hasFloatTextures() const { return mVersionMajor >= 3; } + inline int getMajorGlVersion() const { return mVersionMajor; } inline int getMinorGlVersion() const { return mVersionMinor; } diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp index 1815bffcc3fb..09169420a6d9 100644 --- a/libs/hwui/GradientCache.cpp +++ b/libs/hwui/GradientCache.cpp @@ -78,7 +78,7 @@ GradientCache::GradientCache(): mCache.setOnEntryRemovedListener(this); const Extensions& extensions = Extensions::getInstance(); - mUseFloatTexture = extensions.getMajorGlVersion() >= 3; + mUseFloatTexture = extensions.hasFloatTextures(); mHasNpot = extensions.hasNPot(); } diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index c68cc06f61c3..05f43a9f74a5 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -993,6 +993,10 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) { const Rect& rect = layer->layer; const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer; + bool clipRequired = false; + quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected + mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); + if (fboLayer) { endTiling(); @@ -1568,8 +1572,9 @@ const Rect& OpenGLRenderer::getClipBounds() { return mSnapshot->getLocalClip(); } -bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) { - if (mSnapshot->isIgnored()) { +bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom, + bool* clipRequired) { + if (mSnapshot->isIgnored() || bottom <= top || right <= left) { return true; } @@ -1580,23 +1585,10 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl Rect clipRect(*mSnapshot->clipRect); clipRect.snapToPixelBoundaries(); - return !clipRect.intersects(r); -} - -bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom, - Rect& transformed, Rect& clip) { - if (mSnapshot->isIgnored()) { - return true; - } - - transformed.set(left, top, right, bottom); - currentTransform().mapRect(transformed); - transformed.snapToPixelBoundaries(); - - clip.set(*mSnapshot->clipRect); - clip.snapToPixelBoundaries(); + if (!clipRect.intersects(r)) return true; - return !clip.intersects(transformed); + if (clipRequired) *clipRequired = !clipRect.contains(r); + return false; } bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom, @@ -1610,23 +1602,15 @@ bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, fl } bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) { - if (mSnapshot->isIgnored() || bottom <= top || right <= left) { + bool clipRequired = false; + if (quickRejectNoScissor(left, top, right, bottom, &clipRequired)) { return true; } - Rect r(left, top, right, bottom); - currentTransform().mapRect(r); - r.snapToPixelBoundaries(); - - Rect clipRect(*mSnapshot->clipRect); - clipRect.snapToPixelBoundaries(); - - bool rejected = !clipRect.intersects(r); - if (!isDeferred() && !rejected) { - mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r)); + if (!isDeferred()) { + mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); } - - return rejected; + return false; } void OpenGLRenderer::debugClip() { @@ -2163,6 +2147,9 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes return DrawGlInfo::kStatusDone; } + // TODO: use quickReject on bounds from vertices + mCaches.enableScissor(); + float left = FLT_MAX; float top = FLT_MAX; float right = FLT_MIN; @@ -2829,6 +2816,8 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count return DrawGlInfo::kStatusDone; } + mCaches.enableScissor(); + float x = 0.0f; float y = 0.0f; const bool pureTranslate = currentTransform().isPureTranslate(); @@ -2984,6 +2973,9 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co return DrawGlInfo::kStatusDone; } + // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics + mCaches.enableScissor(); + FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint); fontRenderer.setFont(paint, mat4::identity()); fontRenderer.setTextureFiltering(true); @@ -3059,10 +3051,9 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { } } - Rect transformed; - Rect clip; + bool clipRequired = false; const bool rejected = quickRejectNoScissor(x, y, - x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip); + x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired); if (rejected) { if (transform && !transform->isIdentity()) { @@ -3073,7 +3064,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) { updateLayer(layer, true); - mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed)); + mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired); mCaches.activeTexture(0); if (CC_LIKELY(!layer->region.isEmpty())) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index ad9b1b9cdd71..5b7f90dfc204 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -252,11 +252,31 @@ public: virtual void concatMatrix(SkMatrix* matrix); ANDROID_API const Rect& getClipBounds(); - ANDROID_API bool quickReject(float left, float top, float right, float bottom); + + /** + * Performs a quick reject but adjust the bounds to account for stroke width if necessary + */ + bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint); + + /** + * Returns false and sets scissor based upon bounds if drawing won't be clipped out + */ + bool quickReject(float left, float top, float right, float bottom); bool quickReject(const Rect& bounds) { return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom); } - bool quickRejectNoScissor(float left, float top, float right, float bottom); + + /** + * Same as quickReject, without the scissor, instead returning clipRequired through pointer. + * clipRequired will be only set if not rejected + */ + ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom, + bool* clipRequired = NULL); + bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) { + return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom, + clipRequired); + } + virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); virtual bool clipPath(SkPath* path, SkRegion::Op op); virtual bool clipRegion(SkRegion* region, SkRegion::Op op); @@ -604,18 +624,6 @@ private: void setStencilFromClip(); /** - * Performs a quick reject but does not affect the scissor. Returns - * the transformed rect to test and the current clip. - */ - bool quickRejectNoScissor(float left, float top, float right, float bottom, - Rect& transformed, Rect& clip); - - /** - * Performs a quick reject but adjust the bounds to account for stroke width if necessary - */ - bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint); - - /** * Given the local bounds of the layer, calculates ... */ void calculateLayerBoundsAndClip(Rect& bounds, Rect& clip, bool fboLayer); diff --git a/libs/hwui/Query.h b/libs/hwui/Query.h new file mode 100644 index 000000000000..e25b16b9206a --- /dev/null +++ b/libs/hwui/Query.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HWUI_QUERY_H +#define ANDROID_HWUI_QUERY_H + +#include <GLES3/gl3.h> + +#include "Extensions.h" + +namespace android { +namespace uirenderer { + +/** + * A Query instance can be used to perform occlusion queries. If the device + * does not support occlusion queries, the result of a query will always be + * 0 and the result will always be marked available. + * + * To run an occlusion query successfully, you must start end end the query: + * + * Query query; + * query.begin(); + * // execute OpenGL calls + * query.end(); + * GLuint result = query.getResult(); + */ +class Query { +public: + /** + * Possible query targets. + */ + enum Target { + /** + * Indicates if any sample passed the depth & stencil tests. + */ + kTargetSamples = GL_ANY_SAMPLES_PASSED, + /** + * Indicates if any sample passed the depth & stencil tests. + * The implementation may choose to use a less precise version + * of the test, potentially resulting in false positives. + */ + kTargetConservativeSamples = GL_ANY_SAMPLES_PASSED_CONSERVATIVE, + }; + + /** + * Creates a new query with the specified target. The default + * target is kTargetSamples (of GL_ANY_SAMPLES_PASSED in OpenGL.) + */ + Query(Target target = kTargetSamples): mActive(false), mTarget(target), + mCanQuery(Extensions::getInstance().hasOcclusionQueries()), + mQuery(0) { + } + + ~Query() { + if (mQuery) { + glDeleteQueries(1, &mQuery); + } + } + + /** + * Begins the query. If the query has already begun or if the device + * does not support occlusion queries, calling this method as no effect. + * After calling this method successfully, the query is marked active. + */ + void begin() { + if (!mActive && mCanQuery) { + if (!mQuery) { + glGenQueries(1, &mQuery); + } + + glBeginQuery(mTarget, mQuery); + mActive = true; + } + } + + /** + * Ends the query. If the query has already begun or if the device + * does not support occlusion queries, calling this method as no effect. + * After calling this method successfully, the query is marked inactive. + */ + void end() { + if (mQuery && mActive) { + glEndQuery(mTarget); + mActive = false; + } + } + + /** + * Returns true if the query is active, false otherwise. + */ + bool isActive() { + return mActive; + } + + /** + * Returns true if the result of the query is available, + * false otherwise. Calling getResult() before the result + * is available may result in the calling thread being blocked. + * If the device does not support queries, this method always + * returns true. + */ + bool isResultAvailable() { + if (!mQuery) return true; + + GLuint result; + glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT_AVAILABLE, &result); + return result == GL_TRUE; + } + + /** + * Returns the result of the query. If the device does not + * support queries this method will return 0. + * + * Calling this method implicitely calls end() if the query + * is currently active. + */ + GLuint getResult() { + if (!mQuery) return 0; + + end(); + + GLuint result; + glGetQueryObjectuiv(mQuery, GL_QUERY_RESULT, &result); + return result; + } + + +private: + bool mActive; + GLenum mTarget; + bool mCanQuery; + GLuint mQuery; + +}; // class Query + +}; // namespace uirenderer +}; // namespace android + +#endif // ANDROID_HWUI_QUERY_H diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 87c6c1051fc8..7531769081b0 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -24,7 +24,7 @@ namespace android { namespace uirenderer { -#define RECT_STRING "%4.2f %4.2f %4.2f %4.2f" +#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f" #define RECT_ARGS(r) \ (r).left, (r).top, (r).right, (r).bottom diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 085134d412ef..a21b0895eff9 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -139,8 +139,18 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ActionMenuPresenterCallback mActionMenuPresenterCallback; private PanelMenuPresenterCallback mPanelMenuPresenterCallback; + // The icon resource has been explicitly set elsewhere + // and should not be overwritten with a default. static final int FLAG_RESOURCE_SET_ICON = 1 << 0; + + // The logo resource has been explicitly set elsewhere + // and should not be overwritten with a default. static final int FLAG_RESOURCE_SET_LOGO = 1 << 1; + + // The icon resource is currently configured to use the system fallback + // as no default was previously specified. Anything can override this. + static final int FLAG_RESOURCE_SET_ICON_FALLBACK = 1 << 2; + int mResourcesSetFlags; int mIconRes; int mLogoRes; @@ -1403,6 +1413,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { public void setIcon(int resId) { mIconRes = resId; mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON; + mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK; if (mActionBar != null) { mActionBar.setIcon(resId); } @@ -1414,8 +1425,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return; } mIconRes = resId; - if (mActionBar != null && !mActionBar.hasIcon()) { - mActionBar.setIcon(resId); + if (mActionBar != null && (!mActionBar.hasIcon() || + (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) { + if (resId != 0) { + mActionBar.setIcon(resId); + mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK; + } else { + mActionBar.setIcon(getContext().getPackageManager().getDefaultActivityIcon()); + mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; + } } } @@ -2995,6 +3013,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 || (mIconRes != 0 && !mActionBar.hasIcon())) { mActionBar.setIcon(mIconRes); + } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 && + mIconRes == 0 && !mActionBar.hasIcon()) { + mActionBar.setIcon( + getContext().getPackageManager().getDefaultActivityIcon()); + mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK; } if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 || (mLogoRes != 0 && !mActionBar.hasLogo())) { diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 769b97f99f15..ce952d1dabd5 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -1378,6 +1378,79 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override + public void setUidRangeRoute(String iface, int uid_start, int uid_end) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("interface", "route", + "uid", "add", iface, uid_start, uid_end); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void clearUidRangeRoute(String iface, int uid_start, int uid_end) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("interface", "route", + "uid", "remove", iface, uid_start, uid_end); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void setMarkedForwarding(String iface) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("interface", "route", "fwmark", "add", iface); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void clearMarkedForwarding(String iface) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("interface", "route", "fwmark", "remove", iface); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void clearDnsInterfaceMaps() { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { + mConnector.execute("resolver", "clearifacemapping"); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + + @Override public void flushDefaultDnsCache() { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { |