Merge "Dejank: also animate window moves due to requested size changes."
diff --git a/api/current.txt b/api/current.txt
index 1b04830..29f093a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8035,6 +8035,9 @@
ctor public Camera();
method public void applyToCanvas(android.graphics.Canvas);
method public float dotWithNormal(float, float, float);
+ method public float getLocationX();
+ method public float getLocationY();
+ method public float getLocationZ();
method public void getMatrix(android.graphics.Matrix);
method public void restore();
method public void rotate(float, float, float);
@@ -21639,6 +21642,10 @@
method public android.util.JsonWriter value(java.lang.Number) throws java.io.IOException;
}
+ public class LocaleUtil {
+ method public static int getLayoutDirectionFromLocale(java.util.Locale);
+ }
+
public final class Log {
method public static int d(java.lang.String, java.lang.String);
method public static int d(java.lang.String, java.lang.String, java.lang.Throwable);
@@ -23196,6 +23203,7 @@
method public final int getBottom();
method protected float getBottomFadingEdgeStrength();
method protected int getBottomPaddingOffset();
+ method public float getCameraDistance();
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 901f7c7..da38df1 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -61,6 +61,8 @@
private boolean mWaitOption = false;
private boolean mStopOption = false;
+ private boolean mOpenglTraceOption = false;
+
private int mRepeat = 0;
private String mProfileFile;
@@ -151,6 +153,7 @@
mDebugOption = false;
mWaitOption = false;
mStopOption = false;
+ mOpenglTraceOption = false;
mRepeat = 0;
mProfileFile = null;
Uri data = null;
@@ -307,6 +310,8 @@
mRepeat = Integer.parseInt(nextArgRequired());
} else if (opt.equals("-S")) {
mStopOption = true;
+ } else if (opt.equals("--opengl-trace")) {
+ mOpenglTraceOption = true;
} else {
System.err.println("Error: Unknown option: " + opt);
showUsage();
@@ -440,17 +445,19 @@
return;
}
}
-
+
IActivityManager.WaitResult result = null;
int res;
if (mWaitOption) {
result = mAm.startActivityAndWait(null, intent, mimeType,
- null, 0, null, null, 0, false, mDebugOption,
+ null, 0, null, null, 0, false,
+ mDebugOption, mOpenglTraceOption,
mProfileFile, fd, mProfileAutoStop);
res = result.result;
} else {
res = mAm.startActivity(null, intent, mimeType,
- null, 0, null, null, 0, false, mDebugOption,
+ null, 0, null, null, 0, false,
+ mDebugOption, mOpenglTraceOption,
mProfileFile, fd, mProfileAutoStop);
}
PrintStream out = mWaitOption ? System.out : System.err;
@@ -1277,7 +1284,7 @@
System.err.println(
"usage: am [subcommand] [options]\n" +
"usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
- " [--R COUNT] [-S] <INTENT>\n" +
+ " [--R COUNT] [-S] [--opengl-trace] <INTENT>\n" +
" am startservice <INTENT>\n" +
" am force-stop <PACKAGE>\n" +
" am kill <PACKAGE>\n" +
@@ -1304,6 +1311,7 @@
" -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" +
" the top activity will be finished.\n" +
" -S: force stop the target app before starting the activity\n" +
+ " --opengl-trace: enable tracing of OpenGL functions\n" +
"\n" +
"am startservice: start a Service.\n" +
"\n" +
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 599487dc..0f2aa46 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3388,17 +3388,16 @@
intent.setAllowFds(false);
result = ActivityManagerNative.getDefault()
.startActivity(mMainThread.getApplicationThread(),
- intent, intent.resolveTypeIfNeeded(
- getContentResolver()),
+ intent, intent.resolveTypeIfNeeded(getContentResolver()),
null, 0,
- mToken, mEmbeddedID, requestCode, true, false,
- null, null, false);
+ mToken, mEmbeddedID, requestCode, true /* onlyIfNeeded */,
+ false, false, null, null, false);
} catch (RemoteException e) {
// Empty
}
-
+
Instrumentation.checkStartActivityResult(result, intent);
-
+
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b952649..7daaf7d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -120,17 +120,19 @@
Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
int grantedMode = data.readInt();
IBinder resultTo = data.readStrongBinder();
- String resultWho = data.readString();
+ String resultWho = data.readString();
int requestCode = data.readInt();
boolean onlyIfNeeded = data.readInt() != 0;
boolean debug = data.readInt() != 0;
+ boolean openglTrace = data.readInt() != 0;
String profileFile = data.readString();
ParcelFileDescriptor profileFd = data.readInt() != 0
? data.readFileDescriptor() : null;
boolean autoStopProfiler = data.readInt() != 0;
int result = startActivity(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
- requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
+ requestCode, onlyIfNeeded, debug, openglTrace,
+ profileFile, profileFd, autoStopProfiler);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -146,17 +148,19 @@
Uri[] grantedUriPermissions = data.createTypedArray(Uri.CREATOR);
int grantedMode = data.readInt();
IBinder resultTo = data.readStrongBinder();
- String resultWho = data.readString();
+ String resultWho = data.readString();
int requestCode = data.readInt();
boolean onlyIfNeeded = data.readInt() != 0;
boolean debug = data.readInt() != 0;
+ boolean openglTrace = data.readInt() != 0;
String profileFile = data.readString();
ParcelFileDescriptor profileFd = data.readInt() != 0
? data.readFileDescriptor() : null;
boolean autoStopProfiler = data.readInt() != 0;
WaitResult result = startActivityAndWait(app, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
- requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
+ requestCode, onlyIfNeeded, debug, openglTrace,
+ profileFile, profileFd, autoStopProfiler);
reply.writeNoException();
result.writeToParcel(reply, 0);
return true;
@@ -1607,17 +1611,17 @@
{
mRemote = remote;
}
-
+
public IBinder asBinder()
{
return mRemote;
}
-
+
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
- boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+ boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -1632,6 +1636,7 @@
data.writeInt(requestCode);
data.writeInt(onlyIfNeeded ? 1 : 0);
data.writeInt(debug ? 1 : 0);
+ data.writeInt(openglTrace ? 1 : 0);
data.writeString(profileFile);
if (profileFd != null) {
data.writeInt(1);
@@ -1651,7 +1656,7 @@
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
- boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+ boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -1666,6 +1671,7 @@
data.writeInt(requestCode);
data.writeInt(onlyIfNeeded ? 1 : 0);
data.writeInt(debug ? 1 : 0);
+ data.writeInt(openglTrace ? 1 : 0);
data.writeString(profileFile);
if (profileFd != null) {
data.writeInt(1);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index aa15f39..2610d87 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -376,6 +376,7 @@
Bundle instrumentationArgs;
IInstrumentationWatcher instrumentationWatcher;
int debugMode;
+ boolean enableOpenGlTrace;
boolean restrictedBackupMode;
boolean persistent;
Configuration config;
@@ -676,8 +677,8 @@
ComponentName instrumentationName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
- int debugMode, boolean isRestrictedBackupMode, boolean persistent,
- Configuration config, CompatibilityInfo compatInfo,
+ int debugMode, boolean enableOpenGlTrace, boolean isRestrictedBackupMode,
+ boolean persistent, Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) {
if (services != null) {
@@ -695,6 +696,7 @@
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.debugMode = debugMode;
+ data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
@@ -3912,6 +3914,11 @@
}
}
+ // Enable OpenGL tracing if required
+ if (data.enableOpenGlTrace) {
+ GLUtils.enableTracing();
+ }
+
/**
* Initialize the default http proxy in this process for the reasons we set the time zone.
*/
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index e75d7b4..437362b 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -267,6 +267,7 @@
IBinder binder = data.readStrongBinder();
IInstrumentationWatcher testWatcher = IInstrumentationWatcher.Stub.asInterface(binder);
int testMode = data.readInt();
+ boolean openGlTrace = data.readInt() != 0;
boolean restrictedBackupMode = (data.readInt() != 0);
boolean persistent = (data.readInt() != 0);
Configuration config = Configuration.CREATOR.createFromParcel(data);
@@ -275,11 +276,11 @@
Bundle coreSettings = data.readBundle();
bindApplication(packageName, info,
providers, testName, profileName, profileFd, autoStopProfiler,
- testArgs, testWatcher, testMode, restrictedBackupMode, persistent,
- config, compatInfo, services, coreSettings);
+ testArgs, testWatcher, testMode, openGlTrace, restrictedBackupMode,
+ persistent, config, compatInfo, services, coreSettings);
return true;
}
-
+
case SCHEDULE_EXIT_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
@@ -849,8 +850,9 @@
public final void bindApplication(String packageName, ApplicationInfo info,
List<ProviderInfo> providers, ComponentName testName, String profileName,
ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle testArgs,
- IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode,
- boolean persistent, Configuration config, CompatibilityInfo compatInfo,
+ IInstrumentationWatcher testWatcher, int debugMode, boolean openGlTrace,
+ boolean restrictedBackupMode, boolean persistent,
+ Configuration config, CompatibilityInfo compatInfo,
Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -874,6 +876,7 @@
data.writeBundle(testArgs);
data.writeStrongInterface(testWatcher);
data.writeInt(debugMode);
+ data.writeInt(openGlTrace ? 1 : 0);
data.writeInt(restrictedBackupMode ? 1 : 0);
data.writeInt(persistent ? 1 : 0);
config.writeToParcel(data, 0);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ea2545f..acebf58 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -84,12 +84,12 @@
public int startActivity(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo, String resultWho, int requestCode,
- boolean onlyIfNeeded, boolean debug, String profileFile,
+ boolean onlyIfNeeded, boolean debug, boolean openglTrace, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException;
public WaitResult startActivityAndWait(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo, String resultWho, int requestCode,
- boolean onlyIfNeeded, boolean debug, String profileFile,
+ boolean onlyIfNeeded, boolean debug, boolean openglTrace, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler) throws RemoteException;
public int startActivityWithConfig(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 6ad1736a..70029d2 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -89,7 +89,7 @@
void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
ComponentName testName, String profileName, ParcelFileDescriptor profileFd,
boolean autoStopProfiler, Bundle testArguments, IInstrumentationWatcher testWatcher,
- int debugMode, boolean restrictedBackupMode, boolean persistent,
+ int debugMode, boolean openGlTrace, boolean restrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) throws RemoteException;
void scheduleExit() throws RemoteException;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index c037ffb..a34e1d3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1384,7 +1384,7 @@
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mEmbeddedID : null,
- requestCode, false, false, null, null, false);
+ requestCode, false, false, false, null, null, false);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
@@ -1482,7 +1482,8 @@
.startActivity(whoThread, intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
null, 0, token, target != null ? target.mWho : null,
- requestCode, false, false, null, null, false);
+ requestCode, false, false /* debug */, false /* openglTrace */,
+ null, null, false);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 12e3ccf..ec67d8c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -16,6 +16,8 @@
package android.content;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.content.pm.PackageManager;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
@@ -30,6 +32,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.UserId;
import android.util.Log;
import java.io.File;
@@ -267,90 +270,116 @@
return CancellationSignal.createTransport();
}
- private void enforceReadPermission(Uri uri) {
- final int uid = Binder.getCallingUid();
- if (uid == mMyUid) {
- return;
- }
-
+ private boolean hasReadPermission(Uri uri) {
final Context context = getContext();
- final String rperm = getReadPermission();
final int pid = Binder.getCallingPid();
- if (mExported && (rperm == null
- || context.checkPermission(rperm, pid, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- return;
- }
-
- PathPermission[] pps = getPathPermissions();
- if (pps != null) {
- final String path = uri.getPath();
- int i = pps.length;
- while (i > 0) {
- i--;
- final PathPermission pp = pps[i];
- final String pprperm = pp.getReadPermission();
- if (pprperm != null && pp.match(path)) {
- if (context.checkPermission(pprperm, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return;
+ final int uid = Binder.getCallingUid();
+
+ if (uid == mMyUid) {
+ return true;
+
+ } else if (mExported) {
+ final String componentPerm = getReadPermission();
+ if (componentPerm != null
+ && (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED)) {
+ return true;
+ }
+
+ // track if unprotected read is allowed; any denied
+ // <path-permission> below removes this ability
+ boolean allowDefaultRead = (componentPerm == null);
+
+ final PathPermission[] pps = getPathPermissions();
+ if (pps != null) {
+ final String path = uri.getPath();
+ for (PathPermission pp : pps) {
+ final String pathPerm = pp.getReadPermission();
+ if (pathPerm != null && pp.match(path)) {
+ if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+ return true;
+ } else {
+ // any denied <path-permission> means we lose
+ // default <provider> access.
+ allowDefaultRead = false;
+ }
}
}
}
+
+ // if we passed <path-permission> checks above, and no default
+ // <provider> permission, then allow access.
+ if (allowDefaultRead) return true;
}
-
- if (context.checkUriPermission(uri, pid, uid,
- Intent.FLAG_GRANT_READ_URI_PERMISSION)
- == PackageManager.PERMISSION_GRANTED) {
+
+ // last chance, check against any uri grants
+ if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ == PERMISSION_GRANTED) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void enforceReadPermission(Uri uri) {
+ if (hasReadPermission(uri)) {
return;
}
-
+
String msg = "Permission Denial: reading "
+ ContentProvider.this.getClass().getName()
+ " uri " + uri + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
- + " requires " + rperm;
+ + " requires " + getReadPermission();
throw new SecurityException(msg);
}
private boolean hasWritePermission(Uri uri) {
+ final Context context = getContext();
+ final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
+
if (uid == mMyUid) {
return true;
- }
-
- final Context context = getContext();
- final String wperm = getWritePermission();
- final int pid = Binder.getCallingPid();
- if (mExported && (wperm == null
- || context.checkPermission(wperm, pid, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- return true;
- }
-
- PathPermission[] pps = getPathPermissions();
- if (pps != null) {
- final String path = uri.getPath();
- int i = pps.length;
- while (i > 0) {
- i--;
- final PathPermission pp = pps[i];
- final String ppwperm = pp.getWritePermission();
- if (ppwperm != null && pp.match(path)) {
- if (context.checkPermission(ppwperm, pid, uid)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
+
+ } else if (mExported) {
+ final String componentPerm = getWritePermission();
+ if (componentPerm != null
+ && (context.checkPermission(componentPerm, pid, uid) == PERMISSION_GRANTED)) {
+ return true;
+ }
+
+ // track if unprotected write is allowed; any denied
+ // <path-permission> below removes this ability
+ boolean allowDefaultWrite = (componentPerm == null);
+
+ final PathPermission[] pps = getPathPermissions();
+ if (pps != null) {
+ final String path = uri.getPath();
+ for (PathPermission pp : pps) {
+ final String pathPerm = pp.getWritePermission();
+ if (pathPerm != null && pp.match(path)) {
+ if (context.checkPermission(pathPerm, pid, uid) == PERMISSION_GRANTED) {
+ return true;
+ } else {
+ // any denied <path-permission> means we lose
+ // default <provider> access.
+ allowDefaultWrite = false;
+ }
}
}
}
+
+ // if we passed <path-permission> checks above, and no default
+ // <provider> permission, then allow access.
+ if (allowDefaultWrite) return true;
}
-
- if (context.checkUriPermission(uri, pid, uid,
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
- == PackageManager.PERMISSION_GRANTED) {
+
+ // last chance, check against any uri grants
+ if (context.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+ == PERMISSION_GRANTED) {
return true;
}
-
+
return false;
}
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 94a23cb..e9b06c6 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -64,19 +64,19 @@
break;
}
- if (mNumParameters != 0) {
- mBindArgs = new Object[mNumParameters];
- } else {
- mBindArgs = null;
+ if (bindArgs != null && bindArgs.length > mNumParameters) {
+ throw new IllegalArgumentException("Too many bind arguments. "
+ + bindArgs.length + " arguments were provided but the statement needs "
+ + mNumParameters + " arguments.");
}
- if (bindArgs != null) {
- if (bindArgs.length > mNumParameters) {
- throw new IllegalArgumentException("Too many bind arguments. "
- + bindArgs.length + " arguments were provided but the statement needs "
- + mNumParameters + " arguments.");
+ if (mNumParameters != 0) {
+ mBindArgs = new Object[mNumParameters];
+ if (bindArgs != null) {
+ System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
}
- System.arraycopy(bindArgs, 0, mBindArgs, 0, bindArgs.length);
+ } else {
+ mBindArgs = null;
}
}
diff --git a/core/java/android/util/LocaleUtil.java b/core/java/android/util/LocaleUtil.java
index 9953252..60526e1 100644
--- a/core/java/android/util/LocaleUtil.java
+++ b/core/java/android/util/LocaleUtil.java
@@ -24,7 +24,6 @@
/**
* Various utilities for Locales
*
- * @hide
*/
public class LocaleUtil {
@@ -41,9 +40,7 @@
* {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
- * Be careful: this code will need to be changed when vertical scripts will be supported
- *
- * @hide
+ * Be careful: this code will need to be updated when vertical scripts will be supported
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
if (locale != null && !locale.equals(Locale.ROOT)) {
@@ -69,7 +66,7 @@
* {@link View#LAYOUT_DIRECTION_LTR} or
* {@link View#LAYOUT_DIRECTION_RTL}.
*
- * Be careful: this code will need to be changed when vertical scripts will be supported
+ * Be careful: this code will need to be updated when vertical scripts will be supported
*
* @hide
*/
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index f60c8f0..a50f09f 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -70,4 +70,204 @@
* @return The size of this display list in bytes
*/
public abstract int getSize();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // DisplayList Property Setters
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set the caching property on the DisplayList, which indicates whether the DisplayList
+ * holds a layer. Layer DisplayLists should avoid creating an alpha layer, since alpha is
+ * handled in the drawLayer operation directly (and more efficiently).
+ *
+ * @param caching true if the DisplayList represents a hardware layer, false otherwise.
+ */
+ public abstract void setCaching(boolean caching);
+
+ /**
+ * Set whether the DisplayList should clip itself to its bounds. This property is controlled by
+ * the view's parent.
+ *
+ * @param clipChildren true if the DisplayList should clip to its bounds
+ */
+ public abstract void setClipChildren(boolean clipChildren);
+
+ /**
+ * Set the application scale on the DisplayList. This scale is incurred by applications that
+ * are auto-scaled for compatibility reasons. By default, the value is 1 (unscaled).
+ *
+ * @param scale The scaling factor
+ */
+ public abstract void setApplicationScale(float scale);
+
+ /**
+ * Sets the alpha value for the DisplayList
+ *
+ * @param alpha The translucency of the DisplayList
+ * @see View#setAlpha(float)
+ */
+ public abstract void setAlpha(float alpha);
+
+ /**
+ * Sets the translationX value for the DisplayList
+ *
+ * @param translationX The translationX value of the DisplayList
+ * @see View#setTranslationX(float)
+ */
+ public abstract void setTranslationX(float translationX);
+
+ /**
+ * Sets the translationY value for the DisplayList
+ *
+ * @param translationY The translationY value of the DisplayList
+ * @see View#setTranslationY(float)
+ */
+ public abstract void setTranslationY(float translationY);
+
+ /**
+ * Sets the rotation value for the DisplayList
+ *
+ * @param rotation The rotation value of the DisplayList
+ * @see View#setRotation(float)
+ */
+ public abstract void setRotation(float rotation);
+
+ /**
+ * Sets the rotationX value for the DisplayList
+ *
+ * @param rotationX The rotationX value of the DisplayList
+ * @see View#setRotationX(float)
+ */
+ public abstract void setRotationX(float rotationX);
+
+ /**
+ * Sets the rotationY value for the DisplayList
+ *
+ * @param rotationY The rotationY value of the DisplayList
+ * @see View#setRotationY(float)
+ */
+ public abstract void setRotationY(float rotationY);
+
+ /**
+ * Sets the scaleX value for the DisplayList
+ *
+ * @param scaleX The scaleX value of the DisplayList
+ * @see View#setScaleX(float)
+ */
+ public abstract void setScaleX(float scaleX);
+
+ /**
+ * Sets the scaleY value for the DisplayList
+ *
+ * @param scaleY The scaleY value of the DisplayList
+ * @see View#setScaleY(float)
+ */
+ public abstract void setScaleY(float scaleY);
+
+ /**
+ * Sets all of the transform-related values of the View onto the DisplayList
+ *
+ * @param alpha The alpha value of the DisplayList
+ * @param translationX The translationX value of the DisplayList
+ * @param translationY The translationY value of the DisplayList
+ * @param rotation The rotation value of the DisplayList
+ * @param rotationX The rotationX value of the DisplayList
+ * @param rotationY The rotationY value of the DisplayList
+ * @param scaleX The scaleX value of the DisplayList
+ * @param scaleY The scaleY value of the DisplayList
+ */
+ public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
+
+ /**
+ * Sets the pivotX value for the DisplayList
+ *
+ * @param pivotX The pivotX value of the DisplayList
+ * @see View#setPivotX(float)
+ */
+ public abstract void setPivotX(float pivotX);
+
+ /**
+ * Sets the pivotY value for the DisplayList
+ *
+ * @param pivotY The pivotY value of the DisplayList
+ * @see View#setPivotY(float)
+ */
+ public abstract void setPivotY(float pivotY);
+
+ /**
+ * Sets the camera distance for the DisplayList
+ *
+ * @param distance The distance in z of the camera of the DisplayList
+ * @see View#setCameraDistance(float)
+ */
+ public abstract void setCameraDistance(float distance);
+
+ /**
+ * Sets the left value for the DisplayList
+ *
+ * @param left The left value of the DisplayList
+ * @see View#setLeft(int)
+ */
+ public abstract void setLeft(int left);
+
+ /**
+ * Sets the top value for the DisplayList
+ *
+ * @param top The top value of the DisplayList
+ * @see View#setTop(int)
+ */
+ public abstract void setTop(int top);
+
+ /**
+ * Sets the right value for the DisplayList
+ *
+ * @param right The right value of the DisplayList
+ * @see View#setRight(int)
+ */
+ public abstract void setRight(int right);
+
+ /**
+ * Sets the bottom value for the DisplayList
+ *
+ * @param bottom The bottom value of the DisplayList
+ * @see View#setBottom(int)
+ */
+ public abstract void setBottom(int bottom);
+
+ /**
+ * Sets the left and top values for the DisplayList
+ *
+ * @param left The left value of the DisplayList
+ * @param top The top value of the DisplayList
+ * @see View#setLeft(int)
+ * @see View#setTop(int)
+ */
+ public abstract void setLeftTop(int left, int top);
+
+ /**
+ * Sets the left and top values for the DisplayList
+ *
+ * @param left The left value of the DisplayList
+ * @param top The top value of the DisplayList
+ * @see View#setLeft(int)
+ * @see View#setTop(int)
+ */
+ public abstract void setLeftTopRightBottom(int left, int top, int right, int bottom);
+
+ /**
+ * Offsets the left and right values for the DisplayList
+ *
+ * @param offset The amount that the left and right values of the DisplayList are offset
+ * @see View#offsetLeftAndRight(int)
+ */
+ public abstract void offsetLeftRight(int offset);
+
+ /**
+ * Offsets the top and bottom values for the DisplayList
+ *
+ * @param offset The amount that the top and bottom values of the DisplayList are offset
+ * @see View#offsetTopAndBottom(int)
+ */
+ public abstract void offsetTopBottom(int offset);
}
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 969c9ab..9b4cf21 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -96,6 +96,251 @@
return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
}
+ ///////////////////////////////////////////////////////////////////////////
+ // Native View Properties
+ ///////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void setCaching(boolean caching) {
+ try {
+ nSetCaching(getNativeDisplayList(), caching);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setClipChildren(boolean clipChildren) {
+ try {
+ nSetClipChildren(getNativeDisplayList(), clipChildren);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setApplicationScale(float scale) {
+ try {
+ nSetApplicationScale(getNativeDisplayList(), scale);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ try {
+ nSetAlpha(getNativeDisplayList(), alpha);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setTranslationX(float translationX) {
+ try {
+ nSetTranslationX(getNativeDisplayList(), translationX);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setTranslationY(float translationY) {
+ try {
+ nSetTranslationY(getNativeDisplayList(), translationY);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setRotation(float rotation) {
+ try {
+ nSetRotation(getNativeDisplayList(), rotation);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setRotationX(float rotationX) {
+ try {
+ nSetRotationX(getNativeDisplayList(), rotationX);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setRotationY(float rotationY) {
+ try {
+ nSetRotationY(getNativeDisplayList(), rotationY);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setScaleX(float scaleX) {
+ try {
+ nSetScaleX(getNativeDisplayList(), scaleX);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setScaleY(float scaleY) {
+ try {
+ nSetScaleY(getNativeDisplayList(), scaleY);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setTransformationInfo(float alpha, float translationX, float translationY,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
+ try {
+ nSetTransformationInfo(getNativeDisplayList(), alpha, translationX, translationY,
+ rotation, rotationX, rotationY, scaleX, scaleY);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setPivotX(float pivotX) {
+ try {
+ nSetPivotX(getNativeDisplayList(), pivotX);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setPivotY(float pivotY) {
+ try {
+ nSetPivotY(getNativeDisplayList(), pivotY);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setCameraDistance(float distance) {
+ try {
+ nSetCameraDistance(getNativeDisplayList(), distance);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setLeft(int left) {
+ try {
+ nSetLeft(getNativeDisplayList(), left);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setTop(int top) {
+ try {
+ nSetTop(getNativeDisplayList(), top);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setRight(int right) {
+ try {
+ nSetRight(getNativeDisplayList(), right);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setBottom(int bottom) {
+ try {
+ nSetBottom(getNativeDisplayList(), bottom);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setLeftTop(int left, int top) {
+ try {
+ nSetLeftTop(getNativeDisplayList(), left, top);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+ try {
+ nSetLeftTopRightBottom(getNativeDisplayList(), left, top, right, bottom);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void offsetLeftRight(int offset) {
+ try {
+ nOffsetLeftRight(getNativeDisplayList(), offset);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ @Override
+ public void offsetTopBottom(int offset) {
+ try {
+ nOffsetTopBottom(getNativeDisplayList(), offset);
+ } catch (IllegalStateException e) {
+ // invalid DisplayList okay: we'll set current values the next time we render to it
+ }
+ }
+
+ private static native void nOffsetTopBottom(int displayList, int offset);
+ private static native void nOffsetLeftRight(int displayList, int offset);
+ private static native void nSetLeftTopRightBottom(int displayList, int left, int top,
+ int right, int bottom);
+ private static native void nSetLeftTop(int displayList, int left, int top);
+ private static native void nSetBottom(int displayList, int bottom);
+ private static native void nSetRight(int displayList, int right);
+ private static native void nSetTop(int displayList, int top);
+ private static native void nSetLeft(int displayList, int left);
+ private static native void nSetCameraDistance(int displayList, float distance);
+ private static native void nSetPivotY(int displayList, float pivotY);
+ private static native void nSetPivotX(int displayList, float pivotX);
+ private static native void nSetCaching(int displayList, boolean caching);
+ private static native void nSetClipChildren(int displayList, boolean clipChildren);
+ private static native void nSetApplicationScale(int displayList, float scale);
+ private static native void nSetAlpha(int displayList, float alpha);
+ private static native void nSetTranslationX(int displayList, float translationX);
+ private static native void nSetTranslationY(int displayList, float translationY);
+ private static native void nSetRotation(int displayList, float rotation);
+ private static native void nSetRotationX(int displayList, float rotationX);
+ private static native void nSetRotationY(int displayList, float rotationY);
+ private static native void nSetScaleX(int displayList, float scaleX);
+ private static native void nSetScaleY(int displayList, float scaleY);
+ private static native void nSetTransformationInfo(int displayList, float alpha,
+ float translationX, float translationY, float rotation, float rotationX,
+ float rotationY, float scaleX, float scaleY);
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Finalization
+ ///////////////////////////////////////////////////////////////////////////
+
private static class DisplayListFinalizer {
final int mNativeDisplayList;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a97167b..e73f7bf 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -36,6 +36,7 @@
int mWidth;
int mHeight;
+ DisplayList mDisplayList;
boolean mOpaque;
@@ -79,6 +80,24 @@
}
/**
+ * Returns the DisplayList for the layer.
+ *
+ * @return The DisplayList of the hardware layer
+ */
+ DisplayList getDisplayList() {
+ return mDisplayList;
+ }
+
+ /**
+ * Sets the DisplayList for the layer.
+ *
+ * @param displayList The new DisplayList for this layer
+ */
+ void setDisplayList(DisplayList displayList) {
+ mDisplayList = displayList;
+ }
+
+ /**
* Returns whether or not this layer is opaque.
*
* @return True if the layer is opaque, false otherwise
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 679a65a..bf48ff2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1498,6 +1498,14 @@
static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>();
/**
+ * Temporary flag, used to enable processing of View properties in the native DisplayList
+ * object instead of during draw(). Soon to be enabled by default for hardware-accelerated
+ * apps.
+ * @hide
+ */
+ protected static final boolean USE_DISPLAY_LIST_PROPERTIES = false;
+
+ /**
* Map used to store views' tags.
*/
private SparseArray<Object> mKeyedTags;
@@ -7284,6 +7292,24 @@
}
/**
+ * Gets the distance along the Z axis from the camera to this view.
+ *
+ * @see #setCameraDistance(float)
+ *
+ * @return The distance along the Z axis.
+ */
+ public float getCameraDistance() {
+ ensureTransformationInfo();
+ final float dpi = mResources.getDisplayMetrics().densityDpi;
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mCamera == null) {
+ info.mCamera = new Camera();
+ info.matrix3D = new Matrix();
+ }
+ return -(info.mCamera.getLocationZ() * dpi);
+ }
+
+ /**
* <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which
* views are drawn) from the camera to this view. The camera's distance
* affects 3D transformations, for instance rotations around the X and Y
@@ -7338,6 +7364,9 @@
info.mMatrixDirty = true;
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setCameraDistance(distance);
+ }
}
/**
@@ -7379,6 +7408,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setRotation(rotation);
+ }
}
}
@@ -7426,6 +7458,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setRotationY(rotationY);
+ }
}
}
@@ -7473,6 +7508,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setRotationX(rotationX);
+ }
}
}
@@ -7512,6 +7550,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setScaleX(scaleX);
+ }
}
}
@@ -7551,6 +7592,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setScaleY(scaleY);
+ }
}
}
@@ -7596,6 +7640,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setPivotX(pivotX);
+ }
}
}
@@ -7640,6 +7687,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setPivotY(pivotY);
+ }
}
}
@@ -7686,6 +7736,9 @@
} else {
mPrivateFlags &= ~ALPHA_SET;
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setAlpha(alpha);
+ }
}
}
}
@@ -7710,6 +7763,9 @@
return true;
} else {
mPrivateFlags &= ~ALPHA_SET;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setAlpha(alpha);
+ }
}
}
return false;
@@ -7759,6 +7815,9 @@
int oldHeight = mBottom - mTop;
mTop = top;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setTop(mTop);
+ }
onSizeChanged(width, mBottom - mTop, width, oldHeight);
@@ -7825,6 +7884,9 @@
int oldHeight = mBottom - mTop;
mBottom = bottom;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setBottom(mBottom);
+ }
onSizeChanged(width, mBottom - mTop, width, oldHeight);
@@ -7885,6 +7947,9 @@
int height = mBottom - mTop;
mLeft = left;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setLeft(left);
+ }
onSizeChanged(mRight - mLeft, height, oldWidth, height);
@@ -7898,6 +7963,9 @@
}
mBackgroundSizeChanged = true;
invalidateParentIfNeeded();
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+
+ }
}
}
@@ -7942,6 +8010,9 @@
int height = mBottom - mTop;
mRight = right;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setRight(mRight);
+ }
onSizeChanged(mRight - mLeft, height, oldWidth, height);
@@ -8038,6 +8109,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setTranslationX(translationX);
+ }
}
}
@@ -8075,6 +8149,9 @@
info.mMatrixDirty = true;
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
invalidate(false);
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setTranslationY(translationY);
+ }
}
}
@@ -8207,6 +8284,9 @@
mTop += offset;
mBottom += offset;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.offsetTopBottom(offset);
+ }
if (!matrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
@@ -8248,6 +8328,9 @@
mLeft += offset;
mRight += offset;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.offsetLeftRight(offset);
+ }
if (!matrixIsIdentity) {
mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
@@ -10384,7 +10467,7 @@
return null;
}
- mHardwareLayer.redraw(getDisplayList(), mLocalDirtyRect);
+ mHardwareLayer.redraw(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
mLocalDirtyRect.setEmpty();
}
@@ -10536,6 +10619,129 @@
}
/**
+ * Returns a DisplayList. If the incoming displayList is null, one will be created.
+ * Otherwise, the same display list will be returned (after having been rendered into
+ * along the way, depending on the invalidation state of the view).
+ *
+ * @param displayList The previous version of this displayList, could be null.
+ * @param isLayer Whether the requester of the display list is a layer. If so,
+ * the view will avoid creating a layer inside the resulting display list.
+ * @return A new or reused DisplayList object.
+ */
+ private DisplayList getDisplayList(DisplayList displayList, boolean isLayer) {
+ if (!canHaveDisplayList()) {
+ return null;
+ }
+
+ if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
+ displayList == null || !displayList.isValid() ||
+ (!isLayer && mRecreateDisplayList))) {
+ // Don't need to recreate the display list, just need to tell our
+ // children to restore/recreate theirs
+ if (displayList != null && displayList.isValid() &&
+ !isLayer && !mRecreateDisplayList) {
+ mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~DIRTY_MASK;
+ dispatchGetDisplayList();
+
+ return displayList;
+ }
+
+ if (!isLayer) {
+ // If we got here, we're recreating it. Mark it as such to ensure that
+ // we copy in child display lists into ours in drawChild()
+ mRecreateDisplayList = true;
+ }
+ if (displayList == null) {
+ final String name = getClass().getSimpleName();
+ displayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
+ // If we're creating a new display list, make sure our parent gets invalidated
+ // since they will need to recreate their display list to account for this
+ // new child display list.
+ invalidateParentCaches();
+ }
+
+ boolean caching = false;
+ final HardwareCanvas canvas = displayList.start();
+ int restoreCount = 0;
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
+
+ try {
+ canvas.setViewport(width, height);
+ // The dirty rect should always be null for a display list
+ canvas.onPreDraw(null);
+ int layerType = (
+ !(mParent instanceof ViewGroup) || ((ViewGroup)mParent).mDrawLayers) ?
+ getLayerType() : LAYER_TYPE_NONE;
+ if (!isLayer && layerType == LAYER_TYPE_HARDWARE && USE_DISPLAY_LIST_PROPERTIES) {
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ } else {
+ canvas.saveLayer(0, 0,
+ mRight - mLeft, mBottom - mTop, mLayerPaint,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ }
+ caching = true;
+ } else {
+
+ computeScroll();
+
+ if (!USE_DISPLAY_LIST_PROPERTIES) {
+ restoreCount = canvas.save();
+ }
+ canvas.translate(-mScrollX, -mScrollY);
+ if (!isLayer) {
+ mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~DIRTY_MASK;
+ }
+
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+ dispatchDraw(canvas);
+ } else {
+ draw(canvas);
+ }
+ }
+ } finally {
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ canvas.restoreToCount(restoreCount);
+ }
+ canvas.onPostDraw();
+
+ displayList.end();
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ displayList.setCaching(caching);
+ }
+ if (isLayer && USE_DISPLAY_LIST_PROPERTIES) {
+ displayList.setLeftTopRightBottom(0, 0, width, height);
+ } else {
+ setDisplayListProperties(displayList);
+ }
+ }
+ } else if (!isLayer) {
+ mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~DIRTY_MASK;
+ }
+
+ return displayList;
+ }
+
+ /**
+ * Get the DisplayList for the HardwareLayer
+ *
+ * @param layer The HardwareLayer whose DisplayList we want
+ * @return A DisplayList fopr the specified HardwareLayer
+ */
+ private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) {
+ DisplayList displayList = getDisplayList(layer.getDisplayList(), true);
+ layer.setDisplayList(displayList);
+ return displayList;
+ }
+
+
+ /**
* <p>Returns a display list that can be used to draw this view again
* without executing its draw method.</p>
*
@@ -10544,70 +10750,7 @@
* @hide
*/
public DisplayList getDisplayList() {
- if (!canHaveDisplayList()) {
- return null;
- }
-
- if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
- mDisplayList == null || !mDisplayList.isValid() ||
- mRecreateDisplayList)) {
- // Don't need to recreate the display list, just need to tell our
- // children to restore/recreate theirs
- if (mDisplayList != null && mDisplayList.isValid() &&
- !mRecreateDisplayList) {
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
- dispatchGetDisplayList();
-
- return mDisplayList;
- }
-
- // If we got here, we're recreating it. Mark it as such to ensure that
- // we copy in child display lists into ours in drawChild()
- mRecreateDisplayList = true;
- if (mDisplayList == null) {
- final String name = getClass().getSimpleName();
- mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
- // If we're creating a new display list, make sure our parent gets invalidated
- // since they will need to recreate their display list to account for this
- // new child display list.
- invalidateParentCaches();
- }
-
- final HardwareCanvas canvas = mDisplayList.start();
- int restoreCount = 0;
- try {
- int width = mRight - mLeft;
- int height = mBottom - mTop;
-
- canvas.setViewport(width, height);
- // The dirty rect should always be null for a display list
- canvas.onPreDraw(null);
-
- computeScroll();
-
- restoreCount = canvas.save();
- canvas.translate(-mScrollX, -mScrollY);
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
-
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- } finally {
- canvas.restoreToCount(restoreCount);
- canvas.onPostDraw();
-
- mDisplayList.end();
- }
- } else {
- mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
- mPrivateFlags &= ~DIRTY_MASK;
- }
-
+ mDisplayList = getDisplayList(mDisplayList, false);
return mDisplayList;
}
@@ -11152,19 +11295,57 @@
return more;
}
+ void setDisplayListProperties() {
+ setDisplayListProperties(mDisplayList);
+ }
+
+ /**
+ * This method is called by getDisplayList() when a display list is created or re-rendered.
+ * It sets or resets the current value of all properties on that display list (resetting is
+ * necessary when a display list is being re-created, because we need to make sure that
+ * previously-set transform values
+ */
+ void setDisplayListProperties(DisplayList displayList) {
+ if (USE_DISPLAY_LIST_PROPERTIES && displayList != null) {
+ displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+ if (mParent instanceof ViewGroup) {
+ displayList.setClipChildren(
+ (((ViewGroup)mParent).mGroupFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0);
+ }
+ if (mAttachInfo != null && mAttachInfo.mScalingRequired &&
+ mAttachInfo.mApplicationScale != 1.0f) {
+ displayList.setApplicationScale(1f / mAttachInfo.mApplicationScale);
+ }
+ if (mTransformationInfo != null) {
+ displayList.setTransformationInfo(mTransformationInfo.mAlpha,
+ mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
+ mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
+ mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
+ mTransformationInfo.mScaleY);
+ displayList.setCameraDistance(getCameraDistance());
+ if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == PIVOT_EXPLICITLY_SET) {
+ displayList.setPivotX(getPivotX());
+ displayList.setPivotY(getPivotY());
+ }
+ }
+ }
+ }
+
/**
* This method is called by ViewGroup.drawChild() to have each child view draw itself.
* This draw() method is an implementation detail and is not intended to be overridden or
* to be called from anywhere else other than ViewGroup.drawChild().
*/
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
+ boolean useDisplayListProperties = USE_DISPLAY_LIST_PROPERTIES && mAttachInfo != null &&
+ mAttachInfo.mHardwareAccelerated;
boolean more = false;
final boolean childHasIdentityMatrix = hasIdentityMatrix();
final int flags = parent.mGroupFlags;
- if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
+ if ((flags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) == ViewGroup.FLAG_CLEAR_TRANSFORMATION) {
parent.mChildTransformation.clear();
- parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
+ parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
Transformation transformToApply = null;
@@ -11175,8 +11356,8 @@
int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
- if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
- (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
+ if ((flags & ViewGroup.FLAG_CHILDREN_DRAWN_WITH_CACHE) != 0 ||
+ (flags & ViewGroup.FLAG_ALWAYS_DRAWN_WITH_CACHE) != 0) {
caching = true;
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
} else {
@@ -11188,8 +11369,7 @@
more = drawAnimation(parent, drawingTime, a, scalingRequired);
concatMatrix = a.willChangeTransformationMatrix();
transformToApply = parent.mChildTransformation;
- } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
- parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+ } else if ((flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
final boolean hasTransform =
parent.getChildStaticTransformation(this, parent.mChildTransformation);
if (hasTransform) {
@@ -11239,6 +11419,11 @@
buildDrawingCache(true);
cache = getDrawingCache(true);
break;
+ case LAYER_TYPE_HARDWARE:
+ if (useDisplayListProperties) {
+ hasDisplayList = canHaveDisplayList();
+ }
+ break;
case LAYER_TYPE_NONE:
// Delay getting the display list until animation-driven alpha values are
// set up and possibly passed on to the view
@@ -11247,24 +11432,33 @@
}
}
}
+ useDisplayListProperties &= hasDisplayList;
final boolean hasNoCache = cache == null || hasDisplayList;
final boolean offsetForScroll = cache == null && !hasDisplayList &&
layerType != LAYER_TYPE_HARDWARE;
- final int restoreTo = canvas.save();
+ int restoreTo = -1;
+ if (!useDisplayListProperties) {
+ restoreTo = canvas.save();
+ }
if (offsetForScroll) {
canvas.translate(mLeft - sx, mTop - sy);
} else {
- canvas.translate(mLeft, mTop);
+ if (!useDisplayListProperties) {
+ canvas.translate(mLeft, mTop);
+ }
if (scalingRequired) {
+ if (useDisplayListProperties) {
+ restoreTo = canvas.save();
+ }
// mAttachInfo cannot be null, otherwise scalingRequired == false
final float scale = 1.0f / mAttachInfo.mApplicationScale;
canvas.scale(scale, scale);
}
}
- float alpha = getAlpha();
+ float alpha = useDisplayListProperties ? 1 : getAlpha();
if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
if (transformToApply != null || !childHasIdentityMatrix) {
int transX = 0;
@@ -11279,20 +11473,22 @@
if (concatMatrix) {
// Undo the scroll translation, apply the transformation matrix,
// then redo the scroll translate to get the correct result.
- canvas.translate(-transX, -transY);
- canvas.concat(transformToApply.getMatrix());
- canvas.translate(transX, transY);
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ if (!hasDisplayList) {
+ canvas.translate(-transX, -transY);
+ canvas.concat(transformToApply.getMatrix());
+ canvas.translate(transX, transY);
+ }
+ parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
float transformAlpha = transformToApply.getAlpha();
if (transformAlpha < 1.0f) {
alpha *= transformToApply.getAlpha();
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
}
}
- if (!childHasIdentityMatrix) {
+ if (!childHasIdentityMatrix && !useDisplayListProperties) {
canvas.translate(-transX, -transY);
canvas.concat(getMatrix());
canvas.translate(transX, transY);
@@ -11300,20 +11496,22 @@
}
if (alpha < 1.0f) {
- parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
if (hasNoCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!onSetAlpha(multipliedAlpha)) {
int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
+ if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 ||
layerType != LAYER_TYPE_NONE) {
layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
}
if (layerType == LAYER_TYPE_NONE) {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
- scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+ if (!useDisplayListProperties) {
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+ scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+ }
}
} else {
// Alpha is handled by the child directly, clobber the layer's alpha
@@ -11326,7 +11524,8 @@
mPrivateFlags &= ~ALPHA_SET;
}
- if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
+ if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN &&
+ !useDisplayListProperties) {
if (offsetForScroll) {
canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
} else {
@@ -11351,7 +11550,7 @@
if (hasNoCache) {
boolean layerRendered = false;
- if (layerType == LAYER_TYPE_HARDWARE) {
+ if (layerType == LAYER_TYPE_HARDWARE && !useDisplayListProperties) {
final HardwareLayer layer = getHardwareLayer();
if (layer != null && layer.isValid()) {
mLayerPaint.setAlpha((int) (alpha * 255));
@@ -11397,11 +11596,10 @@
}
if (alpha < 1.0f) {
cachePaint.setAlpha((int) (alpha * 255));
- parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
- } else if ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
- parent.FLAG_ALPHA_LOWER_THAN_ONE) {
+ parent.mGroupFlags |= ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
+ } else if ((flags & ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE) != 0) {
cachePaint.setAlpha(255);
- parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
+ parent.mGroupFlags &= ~ViewGroup.FLAG_ALPHA_LOWER_THAN_ONE;
}
} else {
cachePaint = mLayerPaint;
@@ -11410,7 +11608,9 @@
canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
}
- canvas.restoreToCount(restoreTo);
+ if (restoreTo >= 0) {
+ canvas.restoreToCount(restoreTo);
+ }
if (a != null && !more) {
if (!hardwareAccelerated && !a.getFillAfter()) {
@@ -11868,6 +12068,9 @@
mTop = top;
mRight = right;
mBottom = bottom;
+ if (USE_DISPLAY_LIST_PROPERTIES && mDisplayList != null) {
+ mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+ }
mPrivateFlags |= HAS_BOUNDS;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c9e0242..1993ce6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2736,7 +2736,18 @@
* @attr ref android.R.styleable#ViewGroup_clipChildren
*/
public void setClipChildren(boolean clipChildren) {
- setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
+ boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
+ if (clipChildren != previousValue) {
+ setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ for (int i = 0; i < mChildrenCount; ++i) {
+ View child = getChildAt(i);
+ if (child.mDisplayList != null) {
+ child.mDisplayList.setClipChildren(clipChildren);
+ }
+ }
+ }
+ }
}
/**
@@ -3973,6 +3984,9 @@
final View v = children[i];
v.mTop += offset;
v.mBottom += offset;
+ if (USE_DISPLAY_LIST_PROPERTIES && v.mDisplayList != null) {
+ v.mDisplayList.offsetTopBottom(offset);
+ }
}
}
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 0fdcd0f..fe0e659 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -866,6 +866,8 @@
info.mAlpha = value;
break;
}
+ // TODO: optimize to set only the properties that have changed
+ mView.setDisplayListProperties();
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b8db848..e535170 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11703,8 +11703,10 @@
firstLine, lastLine);
if (mTextDisplayList == null || !mTextDisplayList.isValid()) {
+ boolean displayListCreated = false;
if (mTextDisplayList == null) {
mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
+ displayListCreated = true;
}
final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -11719,6 +11721,9 @@
} finally {
hardwareCanvas.onPostDraw();
mTextDisplayList.end();
+ if (displayListCreated && USE_DISPLAY_LIST_PROPERTIES) {
+ mTextDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
+ }
}
}
canvas.translate(mScrollX, mScrollY);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 543e32d..92b07b3 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -53,6 +53,7 @@
android_view_KeyEvent.cpp \
android_view_KeyCharacterMap.cpp \
android_view_HardwareRenderer.cpp \
+ android_view_GLES20DisplayList.cpp \
android_view_GLES20Canvas.cpp \
android_view_MotionEvent.cpp \
android_view_PointerIcon.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a512679..92ff8da 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -117,6 +117,7 @@
extern int register_android_graphics_PixelFormat(JNIEnv* env);
extern int register_android_view_Display(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
+extern int register_android_view_GLES20DisplayList(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
extern int register_android_view_HardwareRenderer(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
@@ -1102,6 +1103,7 @@
REG_JNI(register_android_nio_utils),
REG_JNI(register_android_graphics_PixelFormat),
REG_JNI(register_android_graphics_Graphics),
+ REG_JNI(register_android_view_GLES20DisplayList),
REG_JNI(register_android_view_GLES20Canvas),
REG_JNI(register_android_view_HardwareRenderer),
REG_JNI(register_android_view_Surface),
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 76d415a..5176d9a 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -57,6 +57,21 @@
v->setCameraLocation(SkFloatToScalar(x), SkFloatToScalar(y), SkFloatToScalar(z));
}
+static jfloat Camera_getLocationX(JNIEnv* env, jobject obj) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ return SkScalarToFloat(v->getCameraLocationX());
+}
+
+static jfloat Camera_getLocationY(JNIEnv* env, jobject obj) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ return SkScalarToFloat(v->getCameraLocationY());
+}
+
+static jfloat Camera_getLocationZ(JNIEnv* env, jobject obj) {
+ Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
+ return SkScalarToFloat(v->getCameraLocationZ());
+}
+
static void Camera_getMatrix(JNIEnv* env, jobject obj, int native_matrix) {
Sk3DView* v = (Sk3DView*)env->GetIntField(obj, gNativeInstanceFieldID);
v->getMatrix((SkMatrix*)native_matrix);
@@ -93,6 +108,9 @@
{ "rotateZ", "(F)V", (void*)Camera_rotateZ },
{ "rotate", "(FFF)V", (void*)Camera_rotate },
{ "setLocation", "(FFF)V", (void*)Camera_setLocation },
+ { "getLocationX", "()F", (void*)Camera_getLocationX },
+ { "getLocationY", "()F", (void*)Camera_getLocationY },
+ { "getLocationZ", "()F", (void*)Camera_getLocationZ },
{ "nativeGetMatrix", "(I)V", (void*)Camera_getMatrix },
{ "nativeApplyToCanvas", "(I)V", (void*)Camera_applyToCanvas },
{ "dotWithNormal", "(FFF)F", (void*)Camera_dotWithNormal }
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 929df540..634efa6 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -556,6 +556,12 @@
nativeBitmapID = env->GetFieldID(bitmapClass, "mNativeBitmap", "I");
}
+extern void setGLDebugLevel(int level);
+void nativeEnableTracing(JNIEnv *env, jclass clazz)
+{
+ setGLDebugLevel(1);
+}
+
static int checkFormat(SkBitmap::Config config, int format, int type)
{
switch(config) {
@@ -1026,6 +1032,7 @@
{ "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
{ "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
{ "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+ { "native_enableTracing", "()V", (void*)nativeEnableTracing },
};
static JNINativeMethod gEtc1Methods[] = {
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
new file mode 100644
index 0000000..407c196
--- /dev/null
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <EGL/egl.h>
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <DisplayListRenderer.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+/**
+ * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
+ * devices. This means all the logic must be compiled only when the
+ * preprocessor variable USE_OPENGL_RENDERER is defined.
+ */
+#ifdef USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// DisplayList view properties
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20DisplayList_setCaching(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, jboolean caching) {
+ displayList->setCaching(caching);
+}
+
+static void android_view_GLES20DisplayList_setApplicationScale(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float scale) {
+ displayList->setApplicationScale(scale);
+}
+
+static void android_view_GLES20DisplayList_setClipChildren(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, jboolean clipChildren) {
+ displayList->setClipChildren(clipChildren);
+}
+
+static void android_view_GLES20DisplayList_setAlpha(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float alpha) {
+ displayList->setAlpha(alpha);
+}
+
+static void android_view_GLES20DisplayList_setTranslationX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float tx) {
+ displayList->setTranslationX(tx);
+}
+
+static void android_view_GLES20DisplayList_setTranslationY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float ty) {
+ displayList->setTranslationY(ty);
+}
+
+static void android_view_GLES20DisplayList_setRotation(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float rotation) {
+ displayList->setRotation(rotation);
+}
+
+static void android_view_GLES20DisplayList_setRotationX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float rx) {
+ displayList->setRotationX(rx);
+}
+
+static void android_view_GLES20DisplayList_setRotationY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float ry) {
+ displayList->setRotationY(ry);
+}
+
+static void android_view_GLES20DisplayList_setScaleX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float sx) {
+ displayList->setScaleX(sx);
+}
+
+static void android_view_GLES20DisplayList_setScaleY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float sy) {
+ displayList->setScaleY(sy);
+}
+
+static void android_view_GLES20DisplayList_setTransformationInfo(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float alpha,
+ float translationX, float translationY, float rotation, float rotationX, float rotationY,
+ float scaleX, float scaleY) {
+ displayList->setAlpha(alpha);
+ displayList->setTranslationX(translationX);
+ displayList->setTranslationY(translationY);
+ displayList->setRotation(rotation);
+ displayList->setRotationX(rotationX);
+ displayList->setRotationY(rotationY);
+ displayList->setScaleX(scaleX);
+ displayList->setScaleY(scaleY);
+}
+
+static void android_view_GLES20DisplayList_setPivotX(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float px) {
+ displayList->setPivotX(px);
+}
+
+static void android_view_GLES20DisplayList_setPivotY(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float py) {
+ displayList->setPivotY(py);
+}
+
+static void android_view_GLES20DisplayList_setCameraDistance(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float distance) {
+ displayList->setCameraDistance(distance);
+}
+
+static void android_view_GLES20DisplayList_setLeft(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int left) {
+ displayList->setLeft(left);
+}
+
+static void android_view_GLES20DisplayList_setTop(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int top) {
+ displayList->setTop(top);
+}
+
+static void android_view_GLES20DisplayList_setRight(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int right) {
+ displayList->setRight(right);
+}
+
+static void android_view_GLES20DisplayList_setBottom(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int bottom) {
+ displayList->setBottom(bottom);
+}
+
+static void android_view_GLES20DisplayList_setLeftTop(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int left, int top) {
+ displayList->setLeftTop(left, top);
+}
+
+static void android_view_GLES20DisplayList_setLeftTopRightBottom(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int left, int top,
+ int right, int bottom) {
+ displayList->setLeftTopRightBottom(left, top, right, bottom);
+}
+
+static void android_view_GLES20DisplayList_offsetLeftRight(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int offset) {
+ displayList->offsetLeftRight(offset);
+}
+
+static void android_view_GLES20DisplayList_offsetTopBottom(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, int offset) {
+ displayList->offsetTopBottom(offset);
+}
+
+#endif // USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/GLES20DisplayList";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+ { "nSetCaching", "(IZ)V", (void*) android_view_GLES20DisplayList_setCaching },
+ { "nSetApplicationScale", "(IF)V",
+ (void*) android_view_GLES20DisplayList_setApplicationScale },
+ { "nSetClipChildren", "(IZ)V", (void*) android_view_GLES20DisplayList_setClipChildren },
+ { "nSetAlpha", "(IF)V", (void*) android_view_GLES20DisplayList_setAlpha },
+ { "nSetTranslationX", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationX },
+ { "nSetTranslationY", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationY },
+ { "nSetRotation", "(IF)V", (void*) android_view_GLES20DisplayList_setRotation },
+ { "nSetRotationX", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationX },
+ { "nSetRotationY", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationY },
+ { "nSetScaleX", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleX },
+ { "nSetScaleY", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleY },
+ { "nSetTransformationInfo", "(IFFFFFFFF)V",
+ (void*) android_view_GLES20DisplayList_setTransformationInfo },
+ { "nSetPivotX", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotX },
+ { "nSetPivotY", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotY },
+ { "nSetCameraDistance", "(IF)V",
+ (void*) android_view_GLES20DisplayList_setCameraDistance },
+ { "nSetLeft", "(II)V", (void*) android_view_GLES20DisplayList_setLeft },
+ { "nSetTop", "(II)V", (void*) android_view_GLES20DisplayList_setTop },
+ { "nSetRight", "(II)V", (void*) android_view_GLES20DisplayList_setRight },
+ { "nSetBottom", "(II)V", (void*) android_view_GLES20DisplayList_setBottom },
+ { "nSetLeftTop", "(III)V", (void*) android_view_GLES20DisplayList_setLeftTop },
+ { "nSetLeftTopRightBottom", "(IIIII)V",
+ (void*) android_view_GLES20DisplayList_setLeftTopRightBottom },
+ { "nOffsetLeftRight", "(II)V", (void*) android_view_GLES20DisplayList_offsetLeftRight },
+ { "nOffsetTopBottom", "(II)V", (void*) android_view_GLES20DisplayList_offsetTopBottom },
+
+#endif
+};
+
+#ifdef USE_OPENGL_RENDERER
+ #define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+ #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " methodName);
+#else
+ #define FIND_CLASS(var, className)
+ #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor)
+#endif
+
+int register_android_view_GLES20DisplayList(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
+
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index f46546f..649ec3e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -97,6 +97,11 @@
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
mAct.turnScreenOn();
+ if (mAct.mWifiManager.isWifiApEnabled()) {
+ // if soft AP is enabled, disable it
+ assertTrue(mAct.mWifiManager.setWifiApEnabled(null, false));
+ Log.v(TAG, "disable soft ap");
+ }
if (!mAct.mWifiManager.isWifiEnabled()) {
log("Enable wi-fi before stress tests.");
if (!mAct.enableWifi()) {
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index 7ef35a9..6f71a2b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -100,6 +100,27 @@
public native void rotate(float x, float y, float z);
/**
+ * Gets the x location of the camera.
+ *
+ * @see #setLocation(float, float, float)
+ */
+ public native float getLocationX();
+
+ /**
+ * Gets the y location of the camera.
+ *
+ * @see #setLocation(float, float, float)
+ */
+ public native float getLocationY();
+
+ /**
+ * Gets the z location of the camera.
+ *
+ * @see #setLocation(float, float, float)
+ */
+ public native float getLocationZ();
+
+ /**
* Sets the location of the camera. The default location is set at
* 0, 0, -8.
*
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 18d0a70..24f4f1c 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -20,13 +20,11 @@
#include "DisplayListLogBuffer.h"
#include "DisplayListRenderer.h"
#include "Caches.h"
-
-#include <utils/String8.h>
+#include "SkCamera.h"
namespace android {
namespace uirenderer {
-
///////////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////////
@@ -101,6 +99,37 @@
clearResources();
}
+void DisplayList::initProperties() {
+ mLeft = 0;
+ mTop = 0;
+ mTop = 0;
+ mBottom = 0;
+ mApplicationScale = -1;
+ mClipChildren = true;
+ mAlpha = 1;
+ mMultipliedAlpha = 255;
+ mTranslationX = 0;
+ mTranslationY = 0;
+ mRotation = 0;
+ mRotationX = 0;
+ mRotationY= 0;
+ mScaleX = 1;
+ mScaleY = 1;
+ mPivotX = 0;
+ mPivotY = 0;
+ mMatrixDirty = false;
+ mMatrixFlags = 0;
+ mPrevWidth = -1;
+ mPrevHeight = -1;
+ mWidth = 0;
+ mHeight = 0;
+ mPivotExplicitlySet = false;
+ mTransformMatrix = NULL;
+ mTransformCamera = NULL;
+ mTransformMatrix3D = NULL;
+ mCaching = false;
+}
+
void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
if (displayList) {
DISPLAY_LIST_LOGD("Deferring display list destruction");
@@ -111,6 +140,19 @@
void DisplayList::clearResources() {
sk_free((void*) mReader.base());
+ if (mTransformMatrix) {
+ delete mTransformMatrix;
+ mTransformMatrix = NULL;
+ }
+ if (mTransformCamera) {
+ delete mTransformCamera;
+ mTransformCamera = NULL;
+ }
+ if (mTransformMatrix3D) {
+ delete mTransformMatrix3D;
+ mTransformMatrix3D = NULL;
+ }
+
Caches& caches = Caches::getInstance();
for (size_t i = 0; i < mBitmapResources.size(); i++) {
@@ -159,6 +201,7 @@
// re-using display list - clear out previous allocations
clearResources();
}
+ initProperties();
mSize = writer.size();
void* buffer = sk_malloc_throw(mSize);
@@ -230,6 +273,7 @@
int saveCount = renderer.getSaveCount() - 1;
+ outputViewProperties(renderer, (char*) indent);
mReader.rewind();
while (!mReader.eof()) {
@@ -238,7 +282,7 @@
int skip = mReader.readInt();
ALOGD("%sSkip %d", (char*) indent, skip);
op &= ~OP_MAY_BE_SKIPPED_MASK;
- }
+ }
switch (op) {
case DrawGLFunction: {
@@ -268,7 +312,7 @@
SkPaint* paint = getPaint(renderer);
int flags = getInt();
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
- OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+ OP_NAMES[op], f1, f2, f3, f4, paint, flags);
}
break;
case SaveLayerAlpha: {
@@ -279,7 +323,7 @@
int alpha = getInt();
int flags = getInt();
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
- OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+ OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
}
break;
case Translate: {
@@ -312,7 +356,10 @@
break;
case ConcatMatrix: {
SkMatrix* matrix = getMatrix();
- ALOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+ ALOGD("%s%s new concat %p: [%f, %f, %f] [%f, %f, %f] [%f, %f, %f]",
+ (char*) indent, OP_NAMES[op], matrix, matrix->get(0), matrix->get(1),
+ matrix->get(2), matrix->get(3), matrix->get(4), matrix->get(5),
+ matrix->get(6), matrix->get(7), matrix->get(8));
}
break;
case ClipRect: {
@@ -322,7 +369,7 @@
float f4 = getFloat();
int regionOp = getInt();
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
- f1, f2, f3, f4, regionOp);
+ f1, f2, f3, f4, regionOp);
}
break;
case DrawDisplayList: {
@@ -331,7 +378,7 @@
uint32_t height = getUInt();
int32_t flags = getInt();
ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, flags, level + 1);
+ displayList, width, height, flags, level + 1);
renderer.outputDisplayList(displayList, level + 1);
}
break;
@@ -341,7 +388,7 @@
float y = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- layer, x, y, paint);
+ layer, x, y, paint);
}
break;
case DrawBitmap: {
@@ -350,7 +397,7 @@
float y = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- bitmap, x, y, paint);
+ bitmap, x, y, paint);
}
break;
case DrawBitmapMatrix: {
@@ -358,7 +405,7 @@
SkMatrix* matrix = getMatrix();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
- bitmap, matrix, paint);
+ bitmap, matrix, paint);
}
break;
case DrawBitmapRect: {
@@ -373,7 +420,7 @@
float f8 = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+ (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
break;
case DrawBitmapMesh: {
@@ -422,7 +469,7 @@
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- f1, f2, f3, f4, paint);
+ f1, f2, f3, f4, paint);
}
break;
case DrawRoundRect: {
@@ -434,7 +481,7 @@
float f6 = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
}
break;
case DrawCircle: {
@@ -443,7 +490,7 @@
float f3 = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
}
break;
case DrawOval: {
@@ -453,7 +500,7 @@
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
}
break;
case DrawArc: {
@@ -466,7 +513,7 @@
int i1 = getInt();
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
}
break;
case DrawPath: {
@@ -497,7 +544,7 @@
SkPaint* paint = getPaint(renderer);
float length = getFloat();
ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op],
- text.text(), text.length(), count, x, y, paint, length);
+ text.text(), text.length(), count, x, y, paint, length);
}
break;
case DrawTextOnPath: {
@@ -518,7 +565,7 @@
float* positions = getFloats(positionsCount);
SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
- text.text(), text.length(), count, paint);
+ text.text(), text.length(), count, paint);
}
case ResetShader: {
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -548,7 +595,7 @@
float dy = getFloat();
int color = getInt();
ALOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
- radius, dx, dy, color);
+ radius, dx, dy, color);
}
break;
case ResetPaintFilter: {
@@ -563,20 +610,193 @@
break;
default:
ALOGD("Display List error: op not handled: %s%s",
- (char*) indent, OP_NAMES[op]);
+ (char*) indent, OP_NAMES[op]);
break;
}
}
-
- ALOGD("%sDone", (char*) indent + 2);
+ ALOGD("%sDone (%p, %s)", (char*) indent + 2, this, mName.string());
}
+void DisplayList::updateMatrix() {
+ if (mMatrixDirty) {
+ if (!mTransformMatrix) {
+ mTransformMatrix = new SkMatrix();
+ }
+ if (mMatrixFlags == 0 || mMatrixFlags == TRANSLATION) {
+ mTransformMatrix->reset();
+ } else {
+ if (!mPivotExplicitlySet) {
+ if (mWidth != mPrevWidth || mHeight != mPrevHeight) {
+ mPrevWidth = mWidth;
+ mPrevHeight = mHeight;
+ mPivotX = mPrevWidth / 2;
+ mPivotY = mPrevHeight / 2;
+ }
+ }
+ if ((mMatrixFlags & ROTATION_3D) == 0) {
+ mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
+ mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
+ mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ } else {
+ if (!mTransformCamera) {
+ mTransformCamera = new Sk3DView();
+ mTransformMatrix3D = new SkMatrix();
+ }
+ mTransformMatrix->reset();
+ mTransformCamera->save();
+ mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ mTransformCamera->rotateX(mRotationX);
+ mTransformCamera->rotateY(mRotationY);
+ mTransformCamera->rotateZ(-mRotation);
+ mTransformCamera->getMatrix(mTransformMatrix3D);
+ mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
+ mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
+ mPivotY + mTranslationY);
+ mTransformMatrix->postConcat(*mTransformMatrix3D);
+ mTransformCamera->restore();
+ }
+ }
+ mMatrixDirty = false;
+ }
+}
+
+void DisplayList::outputViewProperties(OpenGLRenderer& renderer, char* indent) {
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ updateMatrix();
+ if (mApplicationScale >= 0) {
+ ALOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
+ mApplicationScale, mApplicationScale);
+ }
+ if (mLeft != 0 || mTop != 0) {
+ ALOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+ }
+ if (mAlpha < 1) {
+ // TODO: should be able to store the size of a DL at record time and not
+ // 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 flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (mClipChildren) {
+ flags |= SkCanvas::kClipToLayer_SaveFlag;
+ }
+ ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+ (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+ mMultipliedAlpha, flags);
+ }
+ if (mMatrixFlags != 0) {
+ if (mMatrixFlags == TRANSLATION) {
+ ALOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+ } else {
+ ALOGD("%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+ indent, "ConcatMatrix", mTransformMatrix,
+ mTransformMatrix->get(0), mTransformMatrix->get(1),
+ mTransformMatrix->get(2), mTransformMatrix->get(3),
+ mTransformMatrix->get(4), mTransformMatrix->get(5),
+ mTransformMatrix->get(6), mTransformMatrix->get(7),
+ mTransformMatrix->get(8));
+ }
+ }
+ if (mClipChildren) {
+ ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+ (float) mRight - mLeft, (float) mBottom - mTop);
+ }
+ }
+}
+
+void DisplayList::setViewProperties(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+ uint32_t level) {
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+#if DEBUG_DISPLAY_LIST
+ uint32_t count = (level + 1) * 2;
+ char indent[count + 1];
+ for (uint32_t i = 0; i < count; i++) {
+ indent[i] = ' ';
+ }
+ indent[count] = '\0';
+#endif
+ updateMatrix();
+ if (mLeft != 0 || mTop != 0) {
+ DISPLAY_LIST_LOGD("%s%s %d, %d", indent, "Translate", mLeft, mTop);
+ renderer.translate(mLeft, mTop);
+ }
+ if (mApplicationScale >= 0) {
+ DISPLAY_LIST_LOGD("%s%s %.2f, %.2f", (char*) indent, "Scale",
+ mApplicationScale, mApplicationScale);
+ renderer.scale(mApplicationScale, mApplicationScale);
+ }
+ if (mAlpha < 1 && !mCaching) {
+ // TODO: should be able to store the size of a DL at record time and not
+ // 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 flags = SkCanvas::kHasAlphaLayer_SaveFlag;
+ if (mClipChildren) {
+ flags |= SkCanvas::kClipToLayer_SaveFlag;
+ }
+ DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", indent, "SaveLayerAlpha",
+ (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
+ mMultipliedAlpha, flags);
+ renderer.saveLayerAlpha(0, 0, mRight - mLeft, mBottom - mTop,
+ mMultipliedAlpha, flags);
+ }
+ if (mMatrixFlags != 0) {
+ if (mMatrixFlags == TRANSLATION) {
+ DISPLAY_LIST_LOGD("%s%s %f, %f", indent, "Translate", mTranslationX, mTranslationY);
+ renderer.translate(mTranslationX, mTranslationY);
+ } else {
+ DISPLAY_LIST_LOGD(
+ "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+ indent, "ConcatMatrix", mTransformMatrix,
+ mTransformMatrix->get(0), mTransformMatrix->get(1),
+ mTransformMatrix->get(2), mTransformMatrix->get(3),
+ mTransformMatrix->get(4), mTransformMatrix->get(5),
+ mTransformMatrix->get(6), mTransformMatrix->get(7),
+ mTransformMatrix->get(8));
+ renderer.concatMatrix(mTransformMatrix);
+ }
+ }
+ if (mClipChildren) {
+ DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f", indent, "ClipRect", 0.0f, 0.0f,
+ (float) mRight - mLeft, (float) mBottom - mTop);
+ renderer.clipRect(0, 0, mRight - mLeft, mBottom - mTop,
+ SkRegion::kIntersect_Op);
+ }
+ }
+}
+
+void DisplayList::transformRect(float left, float top, float right, float bottom, Rect& result) {
+ result.left = left + mLeft;
+ result.top = top + mTop;
+ result.right = right + mLeft;
+ result.bottom = bottom + mTop;
+ if (mMatrixFlags != 0) {
+ if (mMatrixFlags == TRANSLATION) {
+ result.left += mTranslationX;
+ result.top += mTranslationY;
+ result.right += mTranslationX;
+ result.bottom += mTranslationY;
+ } else {
+ updateMatrix();
+ SkRect r;
+ r.fLeft = result.left;
+ r.fTop = result.top;
+ r.fRight = result.right;
+ r.fBottom = result.bottom;
+ mTransformMatrix->mapRect(&r);
+ result.left = r.fLeft;
+ result.top = r.fTop;
+ result.right = r.fRight;
+ result.bottom = r.fBottom;
+ }
+ }
+}
+
+
/**
* Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
* in the output() function, since that function processes the same list of opcodes for the
* purposes of logging display list info for a given view.
*/
-bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, uint32_t width,
+ uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
bool needsInvalidate = false;
TextContainer text;
mReader.rewind();
@@ -592,6 +812,13 @@
#endif
renderer.startMark(mName.string());
+ int restoreTo = 0;
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ DISPLAY_LIST_LOGD("%s%s %d", indent, "Save",
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ }
+ setViewProperties(renderer, width, height, level);
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
int saveCount = renderer.getSaveCount() - 1;
@@ -644,7 +871,7 @@
SkPaint* paint = getPaint(renderer);
int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
- OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+ OP_NAMES[op], f1, f2, f3, f4, paint, flags);
renderer.saveLayer(f1, f2, f3, f4, paint, flags);
}
break;
@@ -656,7 +883,7 @@
int32_t alpha = getInt();
int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
- OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+ OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
}
break;
@@ -695,7 +922,12 @@
break;
case ConcatMatrix: {
SkMatrix* matrix = getMatrix();
- DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+ DISPLAY_LIST_LOGD(
+ "%s%s %p: [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f] [%.2f, %.2f, %.2f]",
+ (char*) indent, OP_NAMES[op], matrix,
+ matrix->get(0), matrix->get(1), matrix->get(2),
+ matrix->get(3), matrix->get(4), matrix->get(5),
+ matrix->get(6), matrix->get(7), matrix->get(8));
renderer.concatMatrix(matrix);
}
break;
@@ -706,7 +938,7 @@
float f4 = getFloat();
int32_t regionOp = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
- f1, f2, f3, f4, regionOp);
+ f1, f2, f3, f4, regionOp);
renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
}
break;
@@ -716,9 +948,9 @@
uint32_t height = getUInt();
int32_t flags = getInt();
DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
- displayList, width, height, flags, level + 1);
- needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
- dirty, flags, level + 1);
+ displayList, width, height, flags, level + 1);
+ needsInvalidate |= renderer.drawDisplayList(displayList, width,
+ height, dirty, flags, level + 1);
}
break;
case DrawLayer: {
@@ -726,8 +958,11 @@
float x = getFloat();
float y = getFloat();
SkPaint* paint = getPaint(renderer);
+ if (mCaching && mMultipliedAlpha < 255) {
+ paint->setAlpha(mMultipliedAlpha);
+ }
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- layer, x, y, paint);
+ layer, x, y, paint);
renderer.drawLayer(layer, x, y, paint);
}
break;
@@ -737,7 +972,7 @@
float y = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- bitmap, x, y, paint);
+ bitmap, x, y, paint);
renderer.drawBitmap(bitmap, x, y, paint);
}
break;
@@ -746,7 +981,7 @@
SkMatrix* matrix = getMatrix();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
- bitmap, matrix, paint);
+ bitmap, matrix, paint);
renderer.drawBitmap(bitmap, matrix, paint);
}
break;
@@ -762,7 +997,8 @@
float f8 = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+ (char*) indent, OP_NAMES[op], bitmap,
+ f1, f2, f3, f4, f5, f6, f7, f8,paint);
renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
break;
@@ -821,7 +1057,7 @@
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
- f1, f2, f3, f4, paint);
+ f1, f2, f3, f4, paint);
renderer.drawRect(f1, f2, f3, f4, paint);
}
break;
@@ -834,7 +1070,7 @@
float f6 = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint);
}
break;
@@ -844,7 +1080,7 @@
float f3 = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
renderer.drawCircle(f1, f2, f3, paint);
}
break;
@@ -855,7 +1091,7 @@
float f4 = getFloat();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
renderer.drawOval(f1, f2, f3, f4, paint);
}
break;
@@ -869,7 +1105,7 @@
int32_t i1 = getInt();
SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
- (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+ (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint);
}
break;
@@ -965,7 +1201,7 @@
float dy = getFloat();
int32_t color = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
- radius, dx, dy, color);
+ radius, dx, dy, color);
renderer.setupShadow(radius, dx, dy, color);
}
break;
@@ -984,14 +1220,19 @@
break;
default:
DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s",
- (char*) indent, OP_NAMES[op]);
+ (char*) indent, OP_NAMES[op]);
break;
}
}
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, "RestoreToCount", restoreTo);
+ renderer.restoreToCount(restoreTo);
+ }
renderer.endMark();
- DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate);
+ DISPLAY_LIST_LOGD("%sDone (%p, %s), returning %d", (char*) indent + 2, this, mName.string(),
+ needsInvalidate);
return needsInvalidate;
}
@@ -999,7 +1240,7 @@
// Base structure
///////////////////////////////////////////////////////////////////////////////
-DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE),
+DisplayListRenderer::DisplayListRenderer() : mWriter(MIN_WRITER_SIZE),
mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
}
@@ -1177,7 +1418,19 @@
uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
// dirty is an out parameter and should not be recorded,
// it matters only when replaying the display list
- const bool reject = quickReject(0.0f, 0.0f, width, height);
+ float top = 0;
+ float left = 0;
+ float right = width;
+ float bottom = height;
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ Rect transformedRect;
+ displayList->transformRect(left, top, right, bottom, transformedRect);
+ left = transformedRect.left;
+ top = transformedRect.top;
+ right = transformedRect.right;
+ bottom = transformedRect.bottom;
+ }
+ const bool reject = quickReject(left, top, right, bottom);
uint32_t* location = addOp(DisplayList::DrawDisplayList, reject);
addDisplayList(displayList);
addSize(width, height);
@@ -1274,7 +1527,7 @@
}
void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, SkPaint* paint) {
+ float rx, float ry, SkPaint* paint) {
const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
quickReject(left, top, right, bottom);
uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 02f8438..abe8b82 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -20,6 +20,7 @@
#include <SkChunkAlloc.h>
#include <SkFlattenable.h>
#include <SkMatrix.h>
+#include <SkCamera.h>
#include <SkPaint.h>
#include <SkPath.h>
#include <SkRefCnt.h>
@@ -28,11 +29,8 @@
#include <cutils/compiler.h>
-#include <utils/String8.h>
-
#include "DisplayListLogBuffer.h"
#include "OpenGLRenderer.h"
-#include "utils/Functor.h"
namespace android {
namespace uirenderer {
@@ -51,6 +49,16 @@
#define DISPLAY_LIST_LOGD(...)
#endif
+// Set to 1 to enable native processing of View properties. 0 by default. Eventually this
+// will go away and we will always use this approach for accelerated apps.
+#define USE_DISPLAY_LIST_PROPERTIES 0
+
+#define TRANSLATION 0x0001
+#define ROTATION 0x0002
+#define ROTATION_3D 0x0004
+#define SCALE 0x0008
+#define PIVOT 0x0010
+
///////////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////////
@@ -119,13 +127,18 @@
static const char* OP_NAMES[];
+ void setViewProperties(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+ uint32_t level);
+ void outputViewProperties(OpenGLRenderer& renderer, char* indent);
+
ANDROID_API size_t getSize();
ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList);
ANDROID_API static void outputLogBuffer(int fd);
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
- bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
+ bool replay(OpenGLRenderer& renderer, uint32_t width, uint32_t height,
+ Rect& dirty, int32_t flags, uint32_t level = 0);
void output(OpenGLRenderer& renderer, uint32_t level = 0);
@@ -143,11 +156,240 @@
}
}
+ void setApplicationScale(float scale) {
+ mApplicationScale = scale;
+ }
+
+ void setClipChildren(bool clipChildren) {
+ mClipChildren = clipChildren;
+ }
+
+ void setAlpha(float alpha) {
+ if (alpha != mAlpha) {
+ mAlpha = alpha;
+ mMultipliedAlpha = (int)(255 * alpha);
+ }
+ }
+
+ void setTranslationX(float translationX) {
+ if (translationX != mTranslationX) {
+ mTranslationX = translationX;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+ mMatrixFlags &= ~TRANSLATION;
+ } else {
+ mMatrixFlags |= TRANSLATION;
+ }
+ }
+ }
+
+ void setTranslationY(float translationY) {
+ if (translationY != mTranslationY) {
+ mTranslationY = translationY;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mTranslationX, 0) && ALMOST_EQUAL(mTranslationY, 0)) {
+ mMatrixFlags &= ~TRANSLATION;
+ } else {
+ mMatrixFlags |= TRANSLATION;
+ }
+ }
+ }
+
+ void setRotation(float rotation) {
+ if (rotation != mRotation) {
+ mRotation = rotation;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mRotation, 0)) {
+ mMatrixFlags &= ~ROTATION;
+ } else {
+ mMatrixFlags |= ROTATION;
+ }
+ }
+ }
+
+ void setRotationX(float rotationX) {
+ if (rotationX != mRotationX) {
+ mRotationX = rotationX;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+ mMatrixFlags &= ~ROTATION_3D;
+ } else {
+ mMatrixFlags |= ROTATION_3D;
+ }
+ }
+ }
+
+ void setRotationY(float rotationY) {
+ if (rotationY != mRotationY) {
+ mRotationY = rotationY;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mRotationX, 0) && ALMOST_EQUAL(mRotationY, 0)) {
+ mMatrixFlags &= ~ROTATION_3D;
+ } else {
+ mMatrixFlags |= ROTATION_3D;
+ }
+ }
+ }
+
+ void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mScaleX, 1) && ALMOST_EQUAL(mScaleY, 1)) {
+ mMatrixFlags &= ~SCALE;
+ } else {
+ mMatrixFlags |= SCALE;
+ }
+ }
+ }
+
+ void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mScaleX, 1) && ALMOST_EQUAL(mScaleY, 1)) {
+ mMatrixFlags &= ~SCALE;
+ } else {
+ mMatrixFlags |= SCALE;
+ }
+ }
+ }
+
+ void setPivotX(float pivotX) {
+ mPivotX = pivotX;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+ mMatrixFlags &= ~PIVOT;
+ } else {
+ mMatrixFlags |= PIVOT;
+ }
+ mPivotExplicitlySet = true;
+ }
+
+ void setPivotY(float pivotY) {
+ mPivotY = pivotY;
+ mMatrixDirty = true;
+ if (ALMOST_EQUAL(mPivotX, 0) && ALMOST_EQUAL(mPivotY, 0)) {
+ mMatrixFlags &= ~PIVOT;
+ } else {
+ mMatrixFlags |= PIVOT;
+ }
+ mPivotExplicitlySet = true;
+ }
+
+ void setCameraDistance(float distance) {
+ if (distance != mCameraDistance) {
+ mCameraDistance = distance;
+ mMatrixDirty = true;
+ if (!mTransformCamera) {
+ mTransformCamera = new Sk3DView();
+ mTransformMatrix3D = new SkMatrix();
+ }
+ mTransformCamera->setCameraLocation(0, 0, distance);
+ }
+ }
+
+ void setLeft(int left) {
+ if (left != mLeft) {
+ mLeft = left;
+ mWidth = mRight - mLeft;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setTop(int top) {
+ if (top != mTop) {
+ mTop = top;
+ mHeight = mBottom - mTop;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setRight(int right) {
+ if (right != mRight) {
+ mRight = right;
+ mWidth = mRight - mLeft;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setBottom(int bottom) {
+ if (bottom != mBottom) {
+ mBottom = bottom;
+ mHeight = mBottom - mTop;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setLeftTop(int left, int top) {
+ if (left != mLeft || top != mTop) {
+ mLeft = left;
+ mTop = top;
+ mWidth = mRight - mLeft;
+ mHeight = mBottom - mTop;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setLeftTopRightBottom(int left, int top, int right, int bottom) {
+ if (left != mLeft || top != mTop || right != mRight || bottom != mBottom) {
+ mLeft = left;
+ mTop = top;
+ mRight = right;
+ mBottom = bottom;
+ mWidth = mRight - mLeft;
+ mHeight = mBottom - mTop;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void offsetLeftRight(int offset) {
+ if (offset != 0) {
+ mLeft += offset;
+ mRight += offset;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void offsetTopBottom(int offset) {
+ if (offset != 0) {
+ mTop += offset;
+ mBottom += offset;
+ if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) {
+ mMatrixDirty = true;
+ }
+ }
+ }
+
+ void setCaching(bool caching) {
+ mCaching = caching;
+ }
+
+ void transformRect(float left, float top, float right, float bottom, Rect& result);
+
private:
void init();
+ void initProperties();
+
void clearResources();
+ void updateMatrix();
+
class TextContainer {
public:
size_t length() const {
@@ -241,6 +483,28 @@
bool mIsRenderable;
String8 mName;
+
+ // View properties
+ float mApplicationScale;
+ bool mClipChildren;
+ float mAlpha;
+ int mMultipliedAlpha;
+ float mTranslationX, mTranslationY;
+ float mRotation, mRotationX, mRotationY;
+ float mScaleX, mScaleY;
+ float mPivotX, mPivotY;
+ float mCameraDistance;
+ int mLeft, mTop, mRight, mBottom;
+ int mWidth, mHeight;
+ int mPrevWidth, mPrevHeight;
+ bool mPivotExplicitlySet;
+ bool mMatrixDirty;
+ bool mMatrixIsIdentity;
+ uint32_t mMatrixFlags;
+ SkMatrix* mTransformMatrix;
+ Sk3DView* mTransformCamera;
+ SkMatrix* mTransformMatrix3D;
+ bool mCaching;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b4310ea..685fddc 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1323,14 +1323,26 @@
bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
Rect& dirty, int32_t flags, uint32_t level) {
- if (quickReject(0.0f, 0.0f, width, height)) {
+ float top = 0;
+ float left = 0;
+ float right = width;
+ float bottom = height;
+ if (USE_DISPLAY_LIST_PROPERTIES) {
+ Rect transformedRect;
+ displayList->transformRect(left, top, right, bottom, transformedRect);
+ left = transformedRect.left;
+ top = transformedRect.top;
+ right = transformedRect.right;
+ bottom = transformedRect.bottom;
+ }
+ if (quickReject(left, top, right, bottom)) {
return false;
}
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
- return displayList->replay(*this, dirty, flags, level);
+ return displayList->replay(*this, width, height, dirty, flags, level);
}
return false;
@@ -2174,13 +2186,12 @@
return;
}
+ if (length < 0.0f) length = paint->measureText(text, bytesCount);
switch (paint->getTextAlign()) {
case SkPaint::kCenter_Align:
- if (length < 0.0f) length = paint->measureText(text, bytesCount);
x -= length / 2.0f;
break;
case SkPaint::kRight_Align:
- if (length < 0.0f) length = paint->measureText(text, bytesCount);
x -= length;
break;
default:
@@ -2189,7 +2200,6 @@
SkPaint::FontMetrics metrics;
paint->getFontMetrics(&metrics, 0.0f);
- // If no length was specified, just perform the hit test on the Y axis
if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
return;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index e663e91..139ff01 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -813,6 +813,13 @@
*
* @param path the path of the file, or the http/rtsp URL of the stream you want to play
* @throws IllegalStateException if it is called in an invalid state
+ *
+ * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
+ * process other than the calling application. This implies that the pathname
+ * should be an absolute path (as any other process runs with unspecified current working
+ * directory), and that the pathname should reference a world-readable file.
+ * As an alternative, the application could first open the file for reading,
+ * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
*/
public native void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
diff --git a/media/jni/mediaeditor/Android.mk b/media/jni/mediaeditor/Android.mk
index b17ae45..6003608 100755
--- a/media/jni/mediaeditor/Android.mk
+++ b/media/jni/mediaeditor/Android.mk
@@ -42,7 +42,6 @@
$(TOP)/frameworks/media/libvideoeditor/vss/common/inc \
$(TOP)/frameworks/media/libvideoeditor/vss/mcs/inc \
$(TOP)/frameworks/media/libvideoeditor/vss/stagefrightshells/inc \
- $(TOP)/frameworks/media/libvideoeditor/include \
$(TOP)/frameworks/media/libvideoeditor/lvpp \
$(TOP)/frameworks/media/libvideoeditor/osal/inc
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index 125c56e..1527f22 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -227,9 +227,9 @@
/**
* Return a string for the EGL error code, or the hex representation
* if the error is unknown.
- *
+ *
* @param error The EGL error to convert into a String.
- *
+ *
* @return An error string corresponding to the EGL error code.
*/
public static String getEGLErrorString(int error) {
@@ -269,6 +269,14 @@
}
}
+ /**
+ * Enable tracing of OpenGL functions for this application.
+ * @hide
+ */
+ public static void enableTracing() {
+ native_enableTracing();
+ }
+
native private static void nativeClassInit();
native private static int native_getInternalFormat(Bitmap bitmap);
@@ -277,4 +285,5 @@
Bitmap bitmap, int type, int border);
native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset,
Bitmap bitmap, int format, int type);
+ native private static void native_enableTracing();
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1763674..e0a0d2d 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3832,7 +3832,8 @@
int result = ActivityManagerNative.getDefault()
.startActivity(null, dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
+ null, 0, null, null, 0, true /* onlyIfNeeded*/,
+ false /* debug */, false /* openglTrace */,
null, null, false);
if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
@@ -3842,7 +3843,8 @@
int result = ActivityManagerNative.getDefault()
.startActivity(null, mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
- null, 0, null, null, 0, true /* onlyIfNeeded*/, false,
+ null, 0, null, null, 0, true /* onlyIfNeeded*/,
+ false /* debug */, false /* openglTrace */,
null, null, false);
if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
return false;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index fd968e0..94b9e91 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.ProcessStats;
@@ -55,6 +57,7 @@
import android.content.ClipData;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
@@ -746,6 +749,7 @@
ParcelFileDescriptor mProfileFd;
int mProfileType = 0;
boolean mAutoStopProfiler = false;
+ String mOpenGlTraceApp = null;
final RemoteCallbackList<IProcessObserver> mProcessObservers
= new RemoteCallbackList<IProcessObserver>();
@@ -2263,7 +2267,8 @@
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
- String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+ boolean autoStopProfiler) {
enforceNotIsolatedCaller("startActivity");
int userId = 0;
if (intent.getCategories() != null && intent.getCategories().contains(Intent.CATEGORY_HOME)) {
@@ -2281,24 +2286,25 @@
}
return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded,
- debug, profileFile, profileFd, autoStopProfiler, null, null, userId);
+ debug, openglTrace, profileFile, profileFd, autoStopProfiler, null, null, userId);
}
public final WaitResult startActivityAndWait(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug,
- String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+ boolean autoStopProfiler) {
enforceNotIsolatedCaller("startActivityAndWait");
WaitResult res = new WaitResult();
int userId = Binder.getOrigCallingUser();
mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
- requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler,
+ requestCode, onlyIfNeeded, debug, openglTrace, profileFile, profileFd, autoStopProfiler,
res, null, userId);
return res;
}
-
+
public final int startActivityWithConfig(IApplicationThread caller,
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
@@ -2308,7 +2314,7 @@
int ret = mMainStack.startActivityMayWait(caller, -1, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded,
- debug, null, null, false, null, config, Binder.getOrigCallingUser());
+ debug, false, null, null, false, null, config, Binder.getOrigCallingUser());
return ret;
}
@@ -2451,7 +2457,7 @@
}
int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType,
- null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false,
+ null, 0, resultTo, resultWho, requestCode, onlyIfNeeded, false, false,
null, null, false, null, null, userId);
return ret;
}
@@ -3833,6 +3839,11 @@
profileFd = mProfileFd;
profileAutoStop = mAutoStopProfiler;
}
+ boolean enableOpenGlTrace = false;
+ if (mOpenGlTraceApp != null && mOpenGlTraceApp.equals(processName)) {
+ enableOpenGlTrace = true;
+ mOpenGlTraceApp = null;
+ }
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
@@ -3858,8 +3869,8 @@
}
thread.bindApplication(processName, appInfo, providers,
app.instrumentationClass, profileFile, profileFd, profileAutoStop,
- app.instrumentationArguments, app.instrumentationWatcher, testMode,
- isRestrictedBackupMode || !normalMode, app.persistent,
+ app.instrumentationArguments, app.instrumentationWatcher, testMode,
+ enableOpenGlTrace, isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, true);
@@ -4543,76 +4554,91 @@
throw new SecurityException(msg);
}
- private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
- ProviderInfo pi, Uri uri, int uid, int modeFlags) {
- boolean readPerm = (modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
- boolean writePerm = (modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
+ /**
+ * Determine if UID is holding permissions required to access {@link Uri} in
+ * the given {@link ProviderInfo}. Final permission checking is always done
+ * in {@link ContentProvider}.
+ */
+ private final boolean checkHoldingPermissionsLocked(
+ IPackageManager pm, ProviderInfo pi, Uri uri, int uid, int modeFlags) {
if (DEBUG_URI_PERMISSION) Slog.v(TAG,
"checkHoldingPermissionsLocked: uri=" + uri + " uid=" + uid);
+
+ if (pi.applicationInfo.uid == uid) {
+ return true;
+ } else if (!pi.exported) {
+ return false;
+ }
+
+ boolean readMet = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0;
+ boolean writeMet = (modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0;
try {
- // Is the component private from the target uid?
- final boolean prv = !pi.exported && pi.applicationInfo.uid != uid;
-
- // Acceptable if the there is no read permission needed from the
- // target or the target is holding the read permission.
- if (!readPerm) {
- if ((!prv && pi.readPermission == null) ||
- (pm.checkUidPermission(pi.readPermission, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- readPerm = true;
- }
+ // check if target holds top-level <provider> permissions
+ if (!readMet && pi.readPermission != null
+ && (pm.checkUidPermission(pi.readPermission, uid) == PERMISSION_GRANTED)) {
+ readMet = true;
+ }
+ if (!writeMet && pi.writePermission != null
+ && (pm.checkUidPermission(pi.writePermission, uid) == PERMISSION_GRANTED)) {
+ writeMet = true;
}
- // Acceptable if the there is no write permission needed from the
- // target or the target is holding the read permission.
- if (!writePerm) {
- if (!prv && (pi.writePermission == null) ||
- (pm.checkUidPermission(pi.writePermission, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- writePerm = true;
- }
- }
+ // track if unprotected read/write is allowed; any denied
+ // <path-permission> below removes this ability
+ boolean allowDefaultRead = pi.readPermission == null;
+ boolean allowDefaultWrite = pi.writePermission == null;
- // Acceptable if there is a path permission matching the URI that
- // the target holds the permission on.
- PathPermission[] pps = pi.pathPermissions;
- if (pps != null && (!readPerm || !writePerm)) {
+ // check if target holds any <path-permission> that match uri
+ final PathPermission[] pps = pi.pathPermissions;
+ if (pps != null) {
final String path = uri.getPath();
int i = pps.length;
- while (i > 0 && (!readPerm || !writePerm)) {
+ while (i > 0 && (!readMet || !writeMet)) {
i--;
PathPermission pp = pps[i];
- if (!readPerm) {
- final String pprperm = pp.getReadPermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
- + pprperm + " for " + pp.getPath()
- + ": match=" + pp.match(path)
- + " check=" + pm.checkUidPermission(pprperm, uid));
- if (pprperm != null && pp.match(path) &&
- (pm.checkUidPermission(pprperm, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- readPerm = true;
+ if (pp.match(path)) {
+ if (!readMet) {
+ final String pprperm = pp.getReadPermission();
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
+ + pprperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(pprperm, uid));
+ if (pprperm != null) {
+ if (pm.checkUidPermission(pprperm, uid) == PERMISSION_GRANTED) {
+ readMet = true;
+ } else {
+ allowDefaultRead = false;
+ }
+ }
}
- }
- if (!writePerm) {
- final String ppwperm = pp.getWritePermission();
- if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
- + ppwperm + " for " + pp.getPath()
- + ": match=" + pp.match(path)
- + " check=" + pm.checkUidPermission(ppwperm, uid));
- if (ppwperm != null && pp.match(path) &&
- (pm.checkUidPermission(ppwperm, uid)
- == PackageManager.PERMISSION_GRANTED)) {
- writePerm = true;
+ if (!writeMet) {
+ final String ppwperm = pp.getWritePermission();
+ if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
+ + ppwperm + " for " + pp.getPath()
+ + ": match=" + pp.match(path)
+ + " check=" + pm.checkUidPermission(ppwperm, uid));
+ if (ppwperm != null) {
+ if (pm.checkUidPermission(ppwperm, uid) == PERMISSION_GRANTED) {
+ writeMet = true;
+ } else {
+ allowDefaultWrite = false;
+ }
+ }
}
}
}
}
+
+ // grant unprotected <provider> read/write, if not blocked by
+ // <path-permission> above
+ if (allowDefaultRead) readMet = true;
+ if (allowDefaultWrite) writeMet = true;
+
} catch (RemoteException e) {
return false;
}
- return readPerm && writePerm;
+ return readMet && writeMet;
}
private final boolean checkUriPermissionLocked(Uri uri, int uid,
@@ -5819,6 +5845,11 @@
return providers;
}
+ /**
+ * Check if {@link ProcessRecord} has a possible chance at accessing the
+ * given {@link ProviderInfo}. Final permission checking is always done
+ * in {@link ContentProvider}.
+ */
private final String checkContentProviderPermissionLocked(
ProviderInfo cpi, ProcessRecord r) {
final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
@@ -6671,6 +6702,19 @@
}
}
+ void setOpenGlTraceApp(ApplicationInfo app, String processName) {
+ synchronized (this) {
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((app.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + app.packageName);
+ }
+ }
+
+ mOpenGlTraceApp = processName;
+ }
+ }
+
void setProfileApp(ApplicationInfo app, String processName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
synchronized (this) {
@@ -8625,6 +8669,9 @@
+ " mDebugTransient=" + mDebugTransient
+ " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
}
+ if (mOpenGlTraceApp != null) {
+ pw.println(" mOpenGlTraceApp=" + mOpenGlTraceApp);
+ }
if (mProfileApp != null || mProfileProc != null || mProfileFile != null
|| mProfileFd != null) {
pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a4e573d..64d52ed 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2828,7 +2828,8 @@
}
ActivityInfo resolveActivity(Intent intent, String resolvedType, boolean debug,
- String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
+ boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
+ boolean autoStopProfiler) {
// Collect information about the target of the Intent.
ActivityInfo aInfo;
try {
@@ -2857,6 +2858,12 @@
}
}
+ if (openglTrace) {
+ if (!aInfo.processName.equals("system")) {
+ mService.setOpenGlTraceApp(aInfo.applicationInfo, aInfo.processName);
+ }
+ }
+
if (profileFile != null) {
if (!aInfo.processName.equals("system")) {
mService.setProfileApp(aInfo.applicationInfo, aInfo.processName,
@@ -2871,7 +2878,7 @@
Intent intent, String resolvedType, Uri[] grantedUriPermissions,
int grantedMode, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded,
- boolean debug, String profileFile, ParcelFileDescriptor profileFd,
+ boolean debug, boolean openglTrace, String profileFile, ParcelFileDescriptor profileFd,
boolean autoStopProfiler,
WaitResult outResult, Configuration config, int userId) {
// Refuse possible leaked file descriptors
@@ -2884,7 +2891,7 @@
intent = new Intent(intent);
// Collect information about the target of the Intent.
- ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug,
+ ActivityInfo aInfo = resolveActivity(intent, resolvedType, debug, openglTrace,
profileFile, profileFd, autoStopProfiler);
aInfo = mService.getActivityInfoForUser(aInfo, userId);
@@ -3074,7 +3081,7 @@
intent = new Intent(intent);
// Collect information about the target of the Intent.
- ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false,
+ ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], false, false,
null, null, false);
// TODO: New, check if this is correct
aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 6e4dd58..5f1a014 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -231,7 +231,8 @@
internalDataEnabled &&
desiredPowerState &&
!mPendingRestartRadio &&
- !mCdmaPhone.needsOtaServiceProvisioning();
+ ((mPhone.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE) ||
+ !mCdmaPhone.needsOtaServiceProvisioning());
if (!allowed && DBG) {
String reason = "";
if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
index 517eb1e..cad37c5 100644
--- a/tests/SmokeTest/tests/AndroidManifest.xml
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -18,20 +18,30 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.smoketest.tests">
- <!-- We add an application tag here just so that we can indicate that
- this package needs to link against the android.test library,
- which is needed when building test cases. -->
+ <!--
+ We add an application tag here just so that we can indicate that this package needs to link
+ against the android.test library, which is needed when building test cases.
+ -->
<application>
<uses-library android:name="android.test.runner" />
</application>
<!--
- This declares that this app uses the instrumentation test runner targeting
- the package of com.android.smoketest. To run the tests use the command:
- "adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner"
+ This declares that this app uses the instrumentation test runner targeting the package of
+ com.android.smoketest. To run the tests use the command:
+ `adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner`
-->
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.smoketest"
android:label="System Smoke Tests"/>
+ <!--
+ This declares a method to run the instrumentation with a special runner, which will run each
+ app as a separate testcase. To do so, use the command:
+ `adb shell am instrument -w com.android.smoketest.tests/com.android.smoketest.SmokeTestRunner`
+ -->
+ <instrumentation android:name="com.android.smoketest.SmokeTestRunner"
+ android:targetPackage="com.android.smoketest"
+ android:label="System Smoke Tests"/>
+
</manifest>
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
index 1a2dcb9..3efd658 100644
--- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -16,8 +16,6 @@
package com.android.smoketest;
-import com.android.internal.os.RuntimeInit;
-
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
@@ -42,10 +40,18 @@
public class ProcessErrorsTest extends AndroidTestCase {
private static final String TAG = "ProcessErrorsTest";
-
+
+ private final Intent mHomeIntent;
+
protected ActivityManager mActivityManager;
protected PackageManager mPackageManager;
+ public ProcessErrorsTest() {
+ mHomeIntent = new Intent(Intent.ACTION_MAIN);
+ mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+ mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -59,7 +65,7 @@
assertNotNull(mPackageManager);
}
- public void testNoProcessErrors() throws Exception {
+ public void testNoProcessErrorsAfterBoot() throws Exception {
final String reportMsg = checkForProcessErrors();
if (reportMsg != null) {
Log.w(TAG, reportMsg);
@@ -72,16 +78,80 @@
private String checkForProcessErrors() throws Exception {
List<ProcessErrorStateInfo> errList;
errList = mActivityManager.getProcessesInErrorState();
-
+
// note: this contains information about each process that is currently in an error
- // condition. if the list is empty (null) then "we're good".
-
+ // condition. if the list is empty (null) then "we're good".
+
// if the list is non-empty, then it's useful to report the contents of the list
final String reportMsg = reportListContents(errList);
return reportMsg;
}
/**
+ * A helper function to query the provided {@link PackageManager} for a list of Activities that
+ * can be launched from Launcher.
+ */
+ static List<ResolveInfo> getLauncherActivities(PackageManager pm) {
+ final Intent launchable = new Intent(Intent.ACTION_MAIN);
+ launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List<ResolveInfo> activities = pm.queryIntentActivities(launchable, 0);
+ return activities;
+ }
+
+ /**
+ * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying
+ * an activity to be launched.
+ */
+ static Intent intentForActivity(ResolveInfo app) {
+ // build an Intent to launch the specified app
+ final ComponentName component = new ComponentName(app.activityInfo.packageName,
+ app.activityInfo.name);
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(component);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ return intent;
+ }
+
+ /**
+ * A method to run the specified Activity and return a {@link Collection} of the Activities that
+ * were in an error state, as listed by {@link ActivityManager.getProcessesInErrorState()}.
+ * <p />
+ * The method will launch the app, wait for 7 seconds, check for apps in the error state, send
+ * the Home intent, wait for 2 seconds, and then return.
+ */
+ public Collection<ProcessErrorStateInfo> runOneActivity(ResolveInfo app) {
+ final long appLaunchWait = 7000;
+ final long homeLaunchWait = 2000;
+
+ Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName,
+ app.activityInfo.name));
+
+ // launch app, and wait 7 seconds for it to start/settle
+ final Intent intent = intentForActivity(app);
+ getContext().startActivity(intent);
+ try {
+ Thread.sleep(appLaunchWait);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ // See if there are any errors
+ final Collection<ProcessErrorStateInfo> errProcs =
+ mActivityManager.getProcessesInErrorState();
+
+ // Send the "home" intent and wait 2 seconds for us to get there
+ getContext().startActivity(mHomeIntent);
+ try {
+ Thread.sleep(homeLaunchWait);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ return errProcs;
+ }
+
+ /**
* A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
* happened while doing so.
* <p />
@@ -89,46 +159,12 @@
* FIXME: first app doesn't go away.
*/
public void testRunAllActivities() throws Exception {
- final Intent home = new Intent(Intent.ACTION_MAIN);
- home.addCategory(Intent.CATEGORY_HOME);
- home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- final Intent launchable = new Intent(Intent.ACTION_MAIN);
- launchable.addCategory(Intent.CATEGORY_LAUNCHER);
- final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
final Set<ProcessError> errSet = new HashSet<ProcessError>();
- for (ResolveInfo info : activities) {
- Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
- info.activityInfo.name));
-
- // build an Intent to launch the app
- final ComponentName component = new ComponentName(info.activityInfo.packageName,
- info.activityInfo.name);
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(component);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- // launch app, and wait 7 seconds for it to start/settle
- getContext().startActivity(intent);
- try {
- Thread.sleep(7000);
- } catch (InterruptedException e) {
- // ignore
- }
-
- // See if there are any errors
- Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
- if (procs != null) {
- errSet.addAll(ProcessError.fromCollection(procs));
- }
-
- // Send the "home" intent and wait 2 seconds for us to get there
- getContext().startActivity(home);
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- // ignore
+ for (ResolveInfo app : getLauncherActivities(mPackageManager)) {
+ final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
+ if (errProcs != null) {
+ errSet.addAll(ProcessError.fromCollection(errProcs));
}
}
@@ -138,7 +174,7 @@
}
}
- private String reportWrappedListContents(Collection<ProcessError> errList) {
+ String reportWrappedListContents(Collection<ProcessError> errList) {
List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
for (ProcessError err : errList) {
newList.add(err.info);
@@ -186,7 +222,7 @@
* A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
* crashes are considered equal).
*/
- private static class ProcessError {
+ static class ProcessError {
public final ProcessErrorStateInfo info;
public ProcessError(ProcessErrorStateInfo newInfo) {
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
new file mode 100644
index 0000000..40b11c5
--- /dev/null
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.InstrumentationTestRunner;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A special test runner which does a test-start for each app in a separate testcase
+ */
+public class SmokeTestRunner extends InstrumentationTestRunner {
+
+ private static final String SUITE_NAME = "Smoke Test Suite";
+
+ /**
+ * Returns a single testcase for each app to launch
+ */
+ @Override
+ public TestSuite getAllTests() {
+ final TestSuite suite = new TestSuite(SUITE_NAME);
+
+ final PackageManager pm = getTargetContext().getPackageManager();
+ final List<ResolveInfo> apps = ProcessErrorsTest.getLauncherActivities(pm);
+
+ // FIXME: figure out some way to control the reported class names for these anonymous
+ // FIXME: class instances.
+
+ final TestCase setupTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ testSetUpConditions();
+ }
+ };
+ setupTest.setName("testSetUpConditions");
+ suite.addTest(setupTest);
+
+ final TestCase postBootTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ testNoProcessErrorsAfterBoot();
+ }
+ };
+ postBootTest.setName("testNoProcessErrorsAfterBoot");
+ suite.addTest(postBootTest);
+
+ for (final ResolveInfo app : apps) {
+ final TestCase appTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ final Set<ProcessError> errSet = new HashSet<ProcessError>();
+ final Collection<ProcessErrorStateInfo> errProcs = runOneActivity(app);
+ if (errProcs != null) {
+ errSet.addAll(ProcessError.fromCollection(errProcs));
+ }
+
+ if (!errSet.isEmpty()) {
+ fail(String.format("Got %d errors: %s", errSet.size(),
+ reportWrappedListContents(errSet)));
+ }
+ }
+ };
+ appTest.setName(app.activityInfo.name);
+ suite.addTest(appTest);
+ }
+
+ return suite;
+ }
+}
+