summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/Sensor.java93
-rw-r--r--core/java/android/hardware/SensorEvent.java17
-rw-r--r--core/java/android/os/INetworkManagementService.aidl39
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/widget/HorizontalScrollView.java14
-rw-r--r--core/java/android/widget/ListView.java79
-rw-r--r--core/java/android/widget/ScrollView.java12
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp2
-rw-r--r--docs/html/tools/help/draw9patch.jd3
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java325
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java8
-rw-r--r--libs/hwui/Caches.cpp2
-rw-r--r--libs/hwui/DisplayList.cpp15
-rw-r--r--libs/hwui/Dither.cpp2
-rw-r--r--libs/hwui/Extensions.h4
-rw-r--r--libs/hwui/GradientCache.cpp2
-rw-r--r--libs/hwui/OpenGLRenderer.cpp61
-rw-r--r--libs/hwui/OpenGLRenderer.h36
-rw-r--r--libs/hwui/Query.h152
-rw-r--r--libs/hwui/Rect.h2
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java27
-rw-r--r--services/java/com/android/server/NetworkManagementService.java73
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 {