diff options
56 files changed, 1085 insertions, 900 deletions
diff --git a/api/current.txt b/api/current.txt index 6519008..eb6de96 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6772,6 +6772,7 @@ package android.content { field public static final java.lang.String CATEGORY_HOME = "android.intent.category.HOME"; field public static final java.lang.String CATEGORY_INFO = "android.intent.category.INFO"; field public static final java.lang.String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; + field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER"; field public static final java.lang.String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK"; field public static final java.lang.String CATEGORY_MONKEY = "android.intent.category.MONKEY"; field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE"; @@ -38593,6 +38594,11 @@ package java.net { method public abstract java.net.SocketImpl createSocketImpl(); } + public abstract interface SocketOption { + method public abstract java.lang.String name(); + method public abstract java.lang.Class<T> type(); + } + public abstract interface SocketOptions { method public abstract java.lang.Object getOption(int) throws java.net.SocketException; method public abstract void setOption(int, java.lang.Object) throws java.net.SocketException; @@ -38623,6 +38629,21 @@ package java.net { ctor public SocketTimeoutException(java.lang.String); } + public final class StandardSocketOptions { + ctor public StandardSocketOptions(); + field public static final java.net.SocketOption IP_MULTICAST_IF; + field public static final java.net.SocketOption IP_MULTICAST_LOOP; + field public static final java.net.SocketOption IP_MULTICAST_TTL; + field public static final java.net.SocketOption IP_TOS; + field public static final java.net.SocketOption SO_BROADCAST; + field public static final java.net.SocketOption SO_KEEPALIVE; + field public static final java.net.SocketOption SO_LINGER; + field public static final java.net.SocketOption SO_RCVBUF; + field public static final java.net.SocketOption SO_REUSEADDR; + field public static final java.net.SocketOption SO_SNDBUF; + field public static final java.net.SocketOption TCP_NODELAY; + } + public final class URI implements java.lang.Comparable java.io.Serializable { ctor public URI(java.lang.String) throws java.net.URISyntaxException; ctor public URI(java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException; @@ -38718,6 +38739,7 @@ package java.net { method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException; method public java.lang.String getContentEncoding(); method public int getContentLength(); + method public long getContentLengthLong(); method public java.lang.String getContentType(); method public long getDate(); method public static boolean getDefaultAllowUserInteraction(); @@ -38732,6 +38754,7 @@ package java.net { method public long getHeaderFieldDate(java.lang.String, long); method public int getHeaderFieldInt(java.lang.String, int); method public java.lang.String getHeaderFieldKey(int); + method public long getHeaderFieldLong(java.lang.String, long); method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaderFields(); method public long getIfModifiedSince(); method public java.io.InputStream getInputStream() throws java.io.IOException; @@ -39082,6 +39105,10 @@ package java.nio { package java.nio.channels { + public class AlreadyBoundException extends java.lang.IllegalStateException { + ctor public AlreadyBoundException(); + } + public class AlreadyConnectedException extends java.lang.IllegalStateException { ctor public AlreadyConnectedException(); } @@ -39131,8 +39158,11 @@ package java.nio.channels { public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider); + method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException; method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException; method public abstract java.nio.channels.DatagramChannel disconnect() throws java.io.IOException; + method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; + method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public abstract boolean isConnected(); method public static java.nio.channels.DatagramChannel open() throws java.io.IOException; method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; @@ -39140,14 +39170,16 @@ package java.nio.channels { method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException; method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException; method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException; + method public java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.DatagramSocket socket(); + method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException; method public final synchronized long write(java.nio.ByteBuffer[]) throws java.io.IOException; } - public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { + public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel java.nio.channels.SeekableByteChannel { ctor protected FileChannel(); method public abstract void force(boolean) throws java.io.IOException; method public final java.nio.channels.FileLock lock() throws java.io.IOException; @@ -39211,6 +39243,14 @@ package java.nio.channels { method public abstract void close() throws java.io.IOException; } + public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable { + method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException; + method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException; + method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException; + method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; + method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions(); + } + public class NoConnectionPendingException extends java.lang.IllegalStateException { ctor public NoConnectionPendingException(); } @@ -39261,6 +39301,15 @@ package java.nio.channels { method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException; } + public abstract interface SeekableByteChannel implements java.nio.channels.ByteChannel { + method public abstract long position() throws java.io.IOException; + method public abstract java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException; + method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; + method public abstract long size() throws java.io.IOException; + method public abstract java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException; + method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; + } + public abstract class SelectableChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.Channel { ctor protected SelectableChannel(); method public abstract java.lang.Object blockingLock(); @@ -39309,18 +39358,27 @@ package java.nio.channels { method public abstract java.nio.channels.Selector wakeup(); } - public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel { + public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.NetworkChannel { ctor protected ServerSocketChannel(java.nio.channels.spi.SelectorProvider); method public abstract java.nio.channels.SocketChannel accept() throws java.io.IOException; + method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException; + method public java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException; + method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; + method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException; + method public java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.ServerSocket socket(); + method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); } - public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { + public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel { ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider); + method public java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException; method public abstract boolean connect(java.net.SocketAddress) throws java.io.IOException; method public abstract boolean finishConnect() throws java.io.IOException; + method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; + method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public abstract boolean isConnected(); method public abstract boolean isConnectionPending(); method public static java.nio.channels.SocketChannel open() throws java.io.IOException; @@ -39328,7 +39386,9 @@ package java.nio.channels { method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException; method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException; + method public java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.Socket socket(); + method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException; @@ -45378,6 +45438,7 @@ package java.util.concurrent.locks { method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method public final boolean hasContended(); + method public final boolean hasQueuedPredecessors(); method public final boolean hasQueuedThreads(); method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method protected boolean isHeldExclusively(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9cfd85a..69ada6a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -161,7 +161,7 @@ public final class ActivityThread { private static final int LOG_ON_PAUSE_CALLED = 30021; private static final int LOG_ON_RESUME_CALLED = 30022; - static ContextImpl mSystemContext = null; + private ContextImpl mSystemContext; static IPackageManager sPackageManager; @@ -1709,7 +1709,7 @@ public final class ActivityThread { ? mBoundApplication.processName : null) + ")"); packageInfo = - new LoadedApk(this, aInfo, compatInfo, this, baseLoader, + new LoadedApk(this, aInfo, compatInfo, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); if (includeCode) { @@ -1762,26 +1762,15 @@ public final class ActivityThread { public ContextImpl getSystemContext() { synchronized (this) { if (mSystemContext == null) { - ContextImpl context = - ContextImpl.createSystemContext(this); - LoadedApk info = new LoadedApk(this, "android", context, null, - CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); - context.init(info, null, this); - context.getResources().updateConfiguration(mResourcesManager.getConfiguration(), - mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY)); - mSystemContext = context; - //Slog.i(TAG, "Created system resources " + context.getResources() - // + ": " + context.getResources().getConfiguration()); + mSystemContext = ContextImpl.createSystemContext(this); } + return mSystemContext; } - return mSystemContext; } public void installSystemApplicationInfo(ApplicationInfo info) { synchronized (this) { - ContextImpl context = getSystemContext(); - context.init(new LoadedApk(this, "android", context, info, - CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this); + getSystemContext().installSystemApplicationInfo(info); // give ourselves a default profiler mProfiler = new Profiler(); @@ -2268,8 +2257,7 @@ public final class ActivityThread { private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { - ContextImpl appContext = new ContextImpl(); - appContext.init(r.packageInfo, r.token, this); + ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token); appContext.setOuterContext(activity); Context baseContext = appContext; @@ -2567,8 +2555,7 @@ public final class ActivityThread { agent = (BackupAgent) cl.loadClass(classname).newInstance(); // set up the agent's context - ContextImpl context = new ContextImpl(); - context.init(packageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(agent); agent.attach(context); @@ -2640,11 +2627,10 @@ public final class ActivityThread { try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); - ContextImpl context = new ContextImpl(); - context.init(packageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); + context.setOuterContext(service); Application app = packageInfo.makeApplication(false, mInstrumentation); - context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); service.onCreate(); @@ -4249,8 +4235,7 @@ public final class ActivityThread { } updateDefaultDensity(); - final ContextImpl appContext = new ContextImpl(); - appContext.init(data.info, null, this); + final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); if (!Process.isIsolated()) { final File cacheDir = appContext.getCacheDir(); @@ -4366,8 +4351,7 @@ public final class ActivityThread { instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true); - ContextImpl instrContext = new ContextImpl(); - instrContext.init(pi, null, this); + ContextImpl instrContext = ContextImpl.createAppContext(this, pi); try { java.lang.ClassLoader cl = instrContext.getClassLoader(); @@ -4982,8 +4966,8 @@ public final class ActivityThread { UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); - ContextImpl context = new ContextImpl(); - context.init(getSystemContext().mPackageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext( + this, getSystemContext().mPackageInfo); Application app = Instrumentation.newApplication(Application.class, context); mAllApplications.add(app); mInitialApplication = app; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9b3643c..0351292 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -185,22 +185,31 @@ class ContextImpl extends Context { */ private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs; - /*package*/ LoadedApk mPackageInfo; - private String mBasePackageName; - private String mOpPackageName; - private Resources mResources; - /*package*/ ActivityThread mMainThread; + final ActivityThread mMainThread; + final LoadedApk mPackageInfo; + + private final IBinder mActivityToken; + + private final UserHandle mUser; + + private final ApplicationContentResolver mContentResolver; + + private final String mBasePackageName; + private final String mOpPackageName; + + private final ResourcesManager mResourcesManager; + private final Resources mResources; + private final Display mDisplay; // may be null if default display + private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); + private final Configuration mOverrideConfiguration; + + private final boolean mRestricted; + private Context mOuterContext; - private IBinder mActivityToken = null; - private ApplicationContentResolver mContentResolver; private int mThemeResource = 0; private Resources.Theme mTheme = null; private PackageManager mPackageManager; - private Display mDisplay; // may be null if default display private Context mReceiverRestrictedContext = null; - private boolean mRestricted; - private UserHandle mUser; - private ResourcesManager mResourcesManager; private final Object mSync = new Object(); @@ -222,8 +231,6 @@ class ContextImpl extends Context { private static final String[] EMPTY_FILE_LIST = {}; - final private DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); - /** * Override this class when the system service constructor needs a * ContextImpl. Else, use StaticServiceFetcher below. @@ -1887,20 +1894,17 @@ class ContextImpl extends Context { @Override public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) throws NameNotFoundException { + final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; if (packageName.equals("system") || packageName.equals("android")) { - final ContextImpl context = new ContextImpl(mMainThread.getSystemContext()); - context.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; - context.init(mPackageInfo, null, mMainThread, mResources, mBasePackageName, user); - return context; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + user, restricted, mDisplay, mOverrideConfiguration); } - LoadedApk pi = - mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags, - user.getIdentifier()); + LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), + flags, user.getIdentifier()); if (pi != null) { - ContextImpl c = new ContextImpl(); - c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; - c.init(pi, null, mMainThread, mResources, mBasePackageName, user); + ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, + user, restricted, mDisplay, mOverrideConfiguration); if (c.mResources != null) { return c; } @@ -1908,7 +1912,7 @@ class ContextImpl extends Context { // Should be a better exception. throw new PackageManager.NameNotFoundException( - "Application package " + packageName + " not found"); + "Application package " + packageName + " not found"); } @Override @@ -1917,12 +1921,8 @@ class ContextImpl extends Context { throw new IllegalArgumentException("overrideConfiguration must not be null"); } - ContextImpl c = new ContextImpl(); - c.init(mPackageInfo, null, mMainThread); - c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration, - mResources.getCompatibilityInfo(), mActivityToken); - return c; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + mUser, mRestricted, mDisplay, overrideConfiguration); } @Override @@ -1931,15 +1931,8 @@ class ContextImpl extends Context { throw new IllegalArgumentException("display must not be null"); } - int displayId = display.getDisplayId(); - - ContextImpl context = new ContextImpl(); - context.init(mPackageInfo, null, mMainThread); - context.mDisplay = display; - DisplayAdjustments daj = getDisplayAdjustments(displayId); - context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null); - return context; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + mUser, mRestricted, display, mOverrideConfiguration); } private int getDisplayId() { @@ -1981,43 +1974,76 @@ class ContextImpl extends Context { } static ContextImpl createSystemContext(ActivityThread mainThread) { - final ContextImpl context = new ContextImpl(); - context.init(Resources.getSystem(), mainThread, Process.myUserHandle()); + LoadedApk packageInfo = new LoadedApk(mainThread); + ContextImpl context = new ContextImpl(null, mainThread, + packageInfo, null, null, false, null, null); + context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), + context.mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY)); return context; } - ContextImpl() { - mOuterContext = this; + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { + if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); + return new ContextImpl(null, mainThread, + packageInfo, null, null, false, null, null); } - /** - * Create a new ApplicationContext from an existing one. The new one - * works and operates the same as the one it is copying. - * - * @param context Existing application context. - */ - public ContextImpl(ContextImpl context) { - mPackageInfo = context.mPackageInfo; - mBasePackageName = context.mBasePackageName; - mOpPackageName = context.mOpPackageName; - mResources = context.mResources; - mMainThread = context.mMainThread; - mContentResolver = context.mContentResolver; - mUser = context.mUser; - mDisplay = context.mDisplay; - mOuterContext = this; - mDisplayAdjustments.setCompatibilityInfo(mPackageInfo.getCompatibilityInfo()); + static ContextImpl createActivityContext(ActivityThread mainThread, + LoadedApk packageInfo, IBinder activityToken) { + if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); + if (activityToken == null) throw new IllegalArgumentException("activityInfo"); + return new ContextImpl(null, mainThread, + packageInfo, activityToken, null, false, null, null); } - final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) { - init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle()); - } + private ContextImpl(ContextImpl container, ActivityThread mainThread, + LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, + Display display, Configuration overrideConfiguration) { + mOuterContext = this; + + mMainThread = mainThread; + mActivityToken = activityToken; + mRestricted = restricted; + + if (user == null) { + user = Process.myUserHandle(); + } + mUser = user; - final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, - Resources container, String basePackageName, UserHandle user) { mPackageInfo = packageInfo; - if (basePackageName != null) { - mBasePackageName = mOpPackageName = basePackageName; + mContentResolver = new ApplicationContentResolver(this, mainThread, user); + mResourcesManager = ResourcesManager.getInstance(); + mDisplay = display; + mOverrideConfiguration = overrideConfiguration; + + final int displayId = getDisplayId(); + CompatibilityInfo compatInfo = null; + if (container != null) { + compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo(); + } + if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) { + compatInfo = packageInfo.getCompatibilityInfo(); + } + mDisplayAdjustments.setCompatibilityInfo(compatInfo); + mDisplayAdjustments.setActivityToken(activityToken); + + Resources resources = packageInfo.getResources(mainThread); + if (resources != null) { + if (activityToken != null + || displayId != Display.DEFAULT_DISPLAY + || overrideConfiguration != null + || (compatInfo != null && compatInfo.applicationScale + != resources.getCompatibilityInfo().applicationScale)) { + resources = mResourcesManager.getTopLevelResources( + packageInfo.getResDir(), packageInfo.getOverlayDirs(), displayId, + overrideConfiguration, compatInfo, activityToken); + } + } + mResources = resources; + + if (container != null) { + mBasePackageName = container.mBasePackageName; + mOpPackageName = container.mOpPackageName; } else { mBasePackageName = packageInfo.mPackageName; ApplicationInfo ainfo = packageInfo.getApplicationInfo(); @@ -2031,45 +2057,10 @@ class ContextImpl extends Context { mOpPackageName = mBasePackageName; } } - mResources = mPackageInfo.getResources(mainThread); - mResourcesManager = ResourcesManager.getInstance(); - - CompatibilityInfo compatInfo = - container == null ? null : container.getCompatibilityInfo(); - if (mResources != null && - ((compatInfo != null && compatInfo.applicationScale != - mResources.getCompatibilityInfo().applicationScale) - || activityToken != null)) { - if (DEBUG) { - Log.d(TAG, "loaded context has different scaling. Using container's" + - " compatiblity info:" + container.getDisplayMetrics()); - } - if (compatInfo == null) { - compatInfo = packageInfo.getCompatibilityInfo(); - } - mDisplayAdjustments.setCompatibilityInfo(compatInfo); - mDisplayAdjustments.setActivityToken(activityToken); - mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo, - activityToken); - } else { - mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo()); - mDisplayAdjustments.setActivityToken(activityToken); - } - mMainThread = mainThread; - mActivityToken = activityToken; - mContentResolver = new ApplicationContentResolver(this, mainThread, user); - mUser = user; } - final void init(Resources resources, ActivityThread mainThread, UserHandle user) { - mPackageInfo = null; - mBasePackageName = null; - mOpPackageName = null; - mResources = resources; - mMainThread = mainThread; - mContentResolver = new ApplicationContentResolver(this, mainThread, user); - mUser = user; + void installSystemApplicationInfo(ApplicationInfo info) { + mPackageInfo.installSystemApplicationInfo(info); } final void scheduleFinalCleanup(String who, String what) { diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0115d1b..d409352 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -72,7 +72,7 @@ public final class LoadedApk { private static final String TAG = "LoadedApk"; private final ActivityThread mActivityThread; - private final ApplicationInfo mApplicationInfo; + private ApplicationInfo mApplicationInfo; final String mPackageName; private final String mAppDir; private final String mResDir; @@ -111,8 +111,7 @@ public final class LoadedApk { * so MUST NOT call back out to the activity manager. */ public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, - CompatibilityInfo compatInfo, - ActivityThread mainThread, ClassLoader baseLoader, + CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { mActivityThread = activityThread; mApplicationInfo = aInfo; @@ -134,31 +133,17 @@ public final class LoadedApk { mSecurityViolation = securityViolation; mIncludeCode = includeCode; mDisplayAdjustments.setCompatibilityInfo(compatInfo); - - if (mAppDir == null) { - if (ActivityThread.mSystemContext == null) { - ActivityThread.mSystemContext = - ContextImpl.createSystemContext(mainThread); - ResourcesManager resourcesManager = ResourcesManager.getInstance(); - ActivityThread.mSystemContext.getResources().updateConfiguration( - resourcesManager.getConfiguration(), - resourcesManager.getDisplayMetricsLocked( - Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo); - //Slog.i(TAG, "Created system resources " - // + mSystemContext.getResources() + ": " - // + mSystemContext.getResources().getConfiguration()); - } - mClassLoader = ActivityThread.mSystemContext.getClassLoader(); - mResources = ActivityThread.mSystemContext.getResources(); - } } - public LoadedApk(ActivityThread activityThread, String name, - Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) { + /** + * Create information about the system package. + * Must call {@link #installSystemApplicationInfo} later. + */ + LoadedApk(ActivityThread activityThread) { mActivityThread = activityThread; - mApplicationInfo = info != null ? info : new ApplicationInfo(); - mApplicationInfo.packageName = name; - mPackageName = name; + mApplicationInfo = new ApplicationInfo(); + mApplicationInfo.packageName = "android"; + mPackageName = "android"; mAppDir = null; mResDir = null; mOverlayDirs = null; @@ -169,9 +154,16 @@ public final class LoadedApk { mBaseClassLoader = null; mSecurityViolation = false; mIncludeCode = true; - mClassLoader = systemContext.getClassLoader(); - mResources = systemContext.getResources(); - mDisplayAdjustments.setCompatibilityInfo(compatInfo); + mClassLoader = ClassLoader.getSystemClassLoader(); + mResources = Resources.getSystem(); + } + + /** + * Sets application info about the system package. + */ + void installSystemApplicationInfo(ApplicationInfo info) { + assert info.packageName.equals("android"); + mApplicationInfo = info; } public String getPackageName() { @@ -513,8 +505,7 @@ public final class LoadedApk { try { java.lang.ClassLoader cl = getClassLoader(); - ContextImpl appContext = new ContextImpl(); - appContext.init(this, null, mActivityThread); + ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index f0b7ca8..96479e2 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2768,6 +2768,12 @@ public class Intent implements Parcelable, Cloneable { @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; /** + * Indicates an activity optimized for Leanback mode, and that should + * be displayed in the Leanback launcher. + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER"; + /** * Provides information about the package it is in; typically used if * a package does not contain a {@link #CATEGORY_LAUNCHER} to provide * a front-door to the user without having to be shown in the all apps list. diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 0da77ea..7db4ac2 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -343,8 +343,9 @@ public abstract class BatteryStats implements Parcelable { } public class Pid { - public long mWakeSum; - public long mWakeStart; + public int mWakeNesting; + public long mWakeSumMs; + public long mWakeStartMs; } /** @@ -515,7 +516,8 @@ public abstract class BatteryStats implements Parcelable { public static final byte CMD_UPDATE = 0; // These can be written as deltas public static final byte CMD_NULL = -1; public static final byte CMD_START = 4; - public static final byte CMD_OVERFLOW = 5; + public static final byte CMD_CURRENT_TIME = 5; + public static final byte CMD_OVERFLOW = 6; public byte cmd = CMD_NULL; @@ -610,6 +612,9 @@ public abstract class BatteryStats implements Parcelable { public int eventCode; public HistoryTag eventTag; + // Only set for CMD_CURRENT_TIME. + public long currentTime; + // Meta-data when reading. public int numReadInts; @@ -637,29 +642,28 @@ public abstract class BatteryStats implements Parcelable { | ((((int)batteryLevel)<<8)&0xff00) | ((((int)batteryStatus)<<16)&0xf0000) | ((((int)batteryHealth)<<20)&0xf00000) - | ((((int)batteryPlugType)<<24)&0xf000000); + | ((((int)batteryPlugType)<<24)&0xf000000) + | (wakelockTag != null ? 0x10000000 : 0) + | (wakeReasonTag != null ? 0x20000000 : 0) + | (eventCode != EVENT_NONE ? 0x40000000 : 0); dest.writeInt(bat); bat = (((int)batteryTemperature)&0xffff) | ((((int)batteryVoltage)<<16)&0xffff0000); dest.writeInt(bat); dest.writeInt(states); if (wakelockTag != null) { - dest.writeInt(1); wakelockTag.writeToParcel(dest, flags); - } else { - dest.writeInt(0); } if (wakeReasonTag != null) { - dest.writeInt(1); wakeReasonTag.writeToParcel(dest, flags); - } else { - dest.writeInt(0); } - dest.writeInt(eventCode); if (eventCode != EVENT_NONE) { dest.writeInt(eventCode); eventTag.writeToParcel(dest, flags); } + if (cmd == CMD_CURRENT_TIME) { + dest.writeLong(currentTime); + } } public void readFromParcel(Parcel src) { @@ -670,26 +674,34 @@ public abstract class BatteryStats implements Parcelable { batteryStatus = (byte)((bat>>16)&0xf); batteryHealth = (byte)((bat>>20)&0xf); batteryPlugType = (byte)((bat>>24)&0xf); - bat = src.readInt(); - batteryTemperature = (short)(bat&0xffff); - batteryVoltage = (char)((bat>>16)&0xffff); + int bat2 = src.readInt(); + batteryTemperature = (short)(bat2&0xffff); + batteryVoltage = (char)((bat2>>16)&0xffff); states = src.readInt(); - if (src.readInt() != 0) { + if ((bat&0x10000000) != 0) { wakelockTag = localWakelockTag; wakelockTag.readFromParcel(src); } else { wakelockTag = null; } - if (src.readInt() != 0) { + if ((bat&0x20000000) != 0) { wakeReasonTag = localWakeReasonTag; wakeReasonTag.readFromParcel(src); } else { wakeReasonTag = null; } - eventCode = src.readInt(); - if (eventCode != EVENT_NONE) { + if ((bat&0x40000000) != 0) { + eventCode = src.readInt(); eventTag = localEventTag; eventTag.readFromParcel(src); + } else { + eventCode = EVENT_NONE; + eventTag = null; + } + if (cmd == CMD_CURRENT_TIME) { + currentTime = src.readLong(); + } else { + currentTime = 0; } numReadInts += (src.dataPosition()-start)/4; } @@ -749,6 +761,7 @@ public abstract class BatteryStats implements Parcelable { } else { eventTag = null; } + currentTime = o.currentTime; } public boolean sameNonEvent(HistoryItem o) { @@ -758,7 +771,8 @@ public abstract class BatteryStats implements Parcelable { && batteryPlugType == o.batteryPlugType && batteryTemperature == o.batteryTemperature && batteryVoltage == o.batteryVoltage - && states == o.states; + && states == o.states + && currentTime == o.currentTime; } public boolean same(HistoryItem o) { @@ -2788,6 +2802,18 @@ public abstract class BatteryStats implements Parcelable { pw.print(":"); } pw.println("START"); + } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) { + if (checkin) { + pw.print(":"); + } + pw.print("TIME:"); + if (checkin) { + pw.println(rec.currentTime); + } else { + pw.print(" "); + pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", + rec.currentTime).toString()); + } } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) { if (checkin) { pw.print(":"); @@ -2941,8 +2967,8 @@ public abstract class BatteryStats implements Parcelable { } } pw.println(); + oldState = rec.states; } - oldState = rec.states; } } @@ -3059,8 +3085,8 @@ public abstract class BatteryStats implements Parcelable { pw.println("Per-PID Stats:"); didPid = true; } - long time = pid.mWakeSum + (pid.mWakeStart != 0 - ? (nowRealtime - pid.mWakeStart) : 0); + long time = pid.mWakeSumMs + (pid.mWakeNesting > 0 + ? (nowRealtime - pid.mWakeStartMs) : 0); pw.print(" PID "); pw.print(pids.keyAt(j)); pw.print(" wake time: "); TimeUtils.formatDuration(time, pw); diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index 6650fca..5d55143 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -21,11 +21,11 @@ import android.content.Context; /** * Class that operates the vibrator on the device. * <p> - * If your process exits, any vibration you started with will stop. + * If your process exits, any vibration you started will stop. * </p> * * To obtain an instance of the system vibrator, call - * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument. + * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument. */ public abstract class Vibrator { /** diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java index 1de9c35..0afbde9 100644 --- a/core/java/android/view/ContextThemeWrapper.java +++ b/core/java/android/view/ContextThemeWrapper.java @@ -26,7 +26,6 @@ import android.content.res.Resources; * wrapped context. */ public class ContextThemeWrapper extends ContextWrapper { - private Context mBase; private int mThemeResource; private Resources.Theme mTheme; private LayoutInflater mInflater; @@ -39,13 +38,11 @@ public class ContextThemeWrapper extends ContextWrapper { public ContextThemeWrapper(Context base, int themeres) { super(base); - mBase = base; mThemeResource = themeres; } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); - mBase = newBase; } /** @@ -109,11 +106,11 @@ public class ContextThemeWrapper extends ContextWrapper { @Override public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { - mInflater = LayoutInflater.from(mBase).cloneInContext(this); + mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } - return mBase.getSystemService(name); + return getBaseContext().getSystemService(name); } /** @@ -135,7 +132,7 @@ public class ContextThemeWrapper extends ContextWrapper { final boolean first = mTheme == null; if (first) { mTheme = getResources().newTheme(); - Resources.Theme theme = mBase.getTheme(); + Resources.Theme theme = getBaseContext().getTheme(); if (theme != null) { mTheme.setTo(theme); } diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 3f90f76..5ba5c57 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -41,6 +41,9 @@ interface IBatteryStats { void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, String historyName, int type, boolean unimportantForLogging); + void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, int type, + in WorkSource newWs, int newPid, String newName, + String newHistoryName, int newType, boolean newUnimportantForLogging); void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type); void noteVibratorOn(int uid, long durationMillis); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index db21906..10fd2f0 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -87,7 +87,7 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 98 + (USE_OLD_HISTORY ? 1000 : 0); + private static final int VERSION = 99 + (USE_OLD_HISTORY ? 1000 : 0); // Maximum number of items we will record in the history. private static final int MAX_HISTORY_ITEMS = 2000; @@ -2274,9 +2274,8 @@ public final class BatteryStatsImpl extends BatteryStats { } public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type, - boolean unimportantForLogging) { + boolean unimportantForLogging, long elapsedRealtime) { uid = mapUid(uid); - final long elapsedRealtime = SystemClock.elapsedRealtime(); if (type == WAKE_TYPE_PARTIAL) { // Only care about partial wake locks, since full wake locks // will be canceled when the user puts the screen to sleep. @@ -2308,9 +2307,8 @@ public final class BatteryStatsImpl extends BatteryStats { } } - public void noteStopWakeLocked(int uid, int pid, String name, int type) { + public void noteStopWakeLocked(int uid, int pid, String name, int type, long elapsedRealtime) { uid = mapUid(uid); - final long elapsedRealtime = SystemClock.elapsedRealtime(); if (type == WAKE_TYPE_PARTIAL) { mWakeLockNesting--; if (mWakeLockNesting == 0) { @@ -2328,16 +2326,37 @@ public final class BatteryStatsImpl extends BatteryStats { public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, String historyName, int type, boolean unimportantForLogging) { - int N = ws.size(); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final int N = ws.size(); for (int i=0; i<N; i++) { - noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging); + noteStartWakeLocked(ws.get(i), pid, name, historyName, type, unimportantForLogging, + elapsedRealtime); + } + } + + public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name, int type, + WorkSource newWs, int newPid, String newName, + String newHistoryName, int newType, boolean newUnimportantForLogging) { + final long elapsedRealtime = SystemClock.elapsedRealtime(); + // For correct semantics, we start the need worksources first, so that we won't + // make inappropriate history items as if all wake locks went away and new ones + // appeared. This is okay because tracking of wake locks allows nesting. + final int NN = ws.size(); + for (int i=0; i<NN; i++) { + noteStartWakeLocked(newWs.get(i), newPid, newName, newHistoryName, newType, + newUnimportantForLogging, elapsedRealtime); + } + final int NO = ws.size(); + for (int i=0; i<NO; i++) { + noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime); } } public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) { - int N = ws.size(); + final long elapsedRealtime = SystemClock.elapsedRealtime(); + final int N = ws.size(); for (int i=0; i<N; i++) { - noteStopWakeLocked(ws.get(i), pid, name, type); + noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime); } } @@ -2466,7 +2485,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (u != null) { Uid.Pid p = u.mPids.get(pid); if (p != null) { - return p.mWakeSum + (p.mWakeStart != 0 ? (realtime - p.mWakeStart) : 0); + return p.mWakeSumMs + (p.mWakeNesting > 0 ? (realtime - p.mWakeStartMs) : 0); } } return 0; @@ -2562,8 +2581,8 @@ public final class BatteryStatsImpl extends BatteryStats { // Fake a wake lock, so we consider the device waked as long // as the screen is on. - noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false); - + noteStartWakeLocked(-1, -1, "screen", null, WAKE_TYPE_PARTIAL, false, elapsedRealtime); + // Update discharge amounts. if (mOnBatteryInternal) { updateDischargeScreenLevelsLocked(false, true); @@ -2584,7 +2603,7 @@ public final class BatteryStatsImpl extends BatteryStats { mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime); } - noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL); + noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL, elapsedRealtime); updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true, SystemClock.uptimeMillis() * 1000, elapsedRealtime * 1000); @@ -3999,10 +4018,12 @@ public final class BatteryStatsImpl extends BatteryStats { mProcessStats.clear(); } if (mPids.size() > 0) { - for (int i=0; !active && i<mPids.size(); i++) { + for (int i=mPids.size()-1; i>=0; i--) { Pid pid = mPids.valueAt(i); - if (pid.mWakeStart != 0) { + if (pid.mWakeNesting > 0) { active = true; + } else { + mPids.removeAt(i); } } } @@ -4024,8 +4045,6 @@ public final class BatteryStatsImpl extends BatteryStats { mPackageStats.clear(); } - mPids.clear(); - if (!active) { if (mWifiRunningTimer != null) { mWifiRunningTimer.detach(); @@ -4067,6 +4086,7 @@ public final class BatteryStatsImpl extends BatteryStats { mNetworkPacketActivityCounters[i].detach(); } } + mPids.clear(); } return !active; @@ -5304,8 +5324,8 @@ public final class BatteryStatsImpl extends BatteryStats { } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { Pid p = getPidStatsLocked(pid); - if (p.mWakeStart == 0) { - p.mWakeStart = elapsedRealtimeMs; + if (p.mWakeNesting++ == 0) { + p.mWakeStartMs = elapsedRealtimeMs; } } } @@ -5317,9 +5337,11 @@ public final class BatteryStatsImpl extends BatteryStats { } if (pid >= 0 && type == WAKE_TYPE_PARTIAL) { Pid p = mPids.get(pid); - if (p != null && p.mWakeStart != 0) { - p.mWakeSum += elapsedRealtimeMs - p.mWakeStart; - p.mWakeStart = 0; + if (p != null && p.mWakeNesting > 0) { + if (p.mWakeNesting-- == 1) { + p.mWakeSumMs += elapsedRealtimeMs - p.mWakeStartMs; + p.mWakeStartMs = 0; + } } } } @@ -5765,6 +5787,9 @@ public final class BatteryStatsImpl extends BatteryStats { mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG; if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: " + Integer.toHexString(mHistoryCur.states)); + mHistoryCur.currentTime = System.currentTimeMillis(); + addHistoryBufferLocked(mSecRealtime, HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; addHistoryRecordLocked(mSecRealtime); mDischargeCurrentLevel = mDischargeUnplugLevel = level; if (mScreenOn) { @@ -6414,11 +6439,16 @@ public final class BatteryStatsImpl extends BatteryStats { Slog.e("BatteryStats", "Error reading battery statistics", e); } - long now = SystemClock.elapsedRealtime(); - if (USE_OLD_HISTORY) { - addHistoryRecordLocked(now, HistoryItem.CMD_START); + if (mHistoryBuffer.dataPosition() > 0) { + long now = SystemClock.elapsedRealtime(); + if (USE_OLD_HISTORY) { + addHistoryRecordLocked(now, HistoryItem.CMD_START); + } + addHistoryBufferLocked(now, HistoryItem.CMD_START); + mHistoryCur.currentTime = System.currentTimeMillis(); + addHistoryBufferLocked(now, HistoryItem.CMD_CURRENT_TIME); + mHistoryCur.currentTime = 0; } - addHistoryBufferLocked(now, HistoryItem.CMD_START); } public int describeContents() { diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index cc8ce2c..467d42e 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -126,6 +126,20 @@ public class SwipeDismissLayout extends FrameLayout { mVelocityTracker.addMovement(ev); break; + case MotionEvent.ACTION_POINTER_DOWN: + int actionIndex = ev.getActionIndex(); + mActiveTouchId = ev.getPointerId(actionIndex); + break; + case MotionEvent.ACTION_POINTER_UP: + actionIndex = ev.getActionIndex(); + int pointerId = ev.getPointerId(actionIndex); + if (pointerId == mActiveTouchId) { + // This was our active pointer going up. Choose a new active pointer. + int newActionIndex = actionIndex == 0 ? 1 : 0; + mActiveTouchId = ev.getPointerId(newActionIndex); + } + break; + case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: resetMembers(); @@ -137,6 +151,11 @@ public class SwipeDismissLayout extends FrameLayout { } int pointerIndex = ev.findPointerIndex(mActiveTouchId); + if (pointerIndex == -1) { + Log.e(TAG, "Invalid pointer index: ignoring."); + mDiscardIntercept = true; + break; + } float dx = ev.getRawX() - mDownX; float x = ev.getX(pointerIndex); float y = ev.getY(pointerIndex); @@ -228,11 +247,11 @@ public class SwipeDismissLayout extends FrameLayout { } private void updateDismiss(MotionEvent ev) { + float deltaX = ev.getRawX() - mDownX; if (!mDismissed) { mVelocityTracker.addMovement(ev); mVelocityTracker.computeCurrentVelocity(1000); - float deltaX = ev.getRawX() - mDownX; float velocityX = mVelocityTracker.getXVelocity(); float absVelocityX = Math.abs(velocityX); float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); @@ -247,6 +266,13 @@ public class SwipeDismissLayout extends FrameLayout { mDismissed = true; } } + // Check if the user tried to undo this. + if (mDismissed && mSwiping) { + // Check if the user's finger is actually back + if (deltaX < getWidth() / 2) { + mDismissed = false; + } + } } /** diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp index c8952c1..27345cf 100644 --- a/core/jni/android_view_DisplayList.cpp +++ b/core/jni/android_view_DisplayList.cpp @@ -43,7 +43,7 @@ using namespace uirenderer; static void android_view_DisplayList_setDisplayListName(JNIEnv* env, jobject clazz, jlong displayListPtr, jstring name) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); if (name != NULL) { const char* textArray = env->GetStringUTFChars(name, NULL); displayList->setName(textArray); @@ -53,19 +53,19 @@ static void android_view_DisplayList_setDisplayListName(JNIEnv* env, static void android_view_DisplayList_output(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->output(); } static jlong android_view_DisplayList_create(JNIEnv* env, jobject clazz) { - DisplayList* displayList = new DisplayList(); + RenderNode* displayList = new RenderNode(); return reinterpret_cast<jlong>(displayList); } static void android_view_DisplayList_destroyDisplayList(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - DisplayList::destroyDisplayListDeferred(displayList); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + RenderNode::destroyDisplayListDeferred(displayList); } // ---------------------------------------------------------------------------- @@ -74,130 +74,130 @@ static void android_view_DisplayList_destroyDisplayList(JNIEnv* env, static void android_view_DisplayList_setCaching(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean caching) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setCaching(caching); } static void android_view_DisplayList_setStaticMatrix(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong matrixPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); displayList->setStaticMatrix(matrix); } static void android_view_DisplayList_setAnimationMatrix(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong matrixPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); displayList->setAnimationMatrix(matrix); } static void android_view_DisplayList_setClipToBounds(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean clipToBounds) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setClipToBounds(clipToBounds); } static void android_view_DisplayList_setIsolatedZVolume(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean shouldIsolate) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setIsolatedZVolume(shouldIsolate); } static void android_view_DisplayList_setProjectBackwards(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean shouldProject) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setProjectBackwards(shouldProject); } static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean shouldRecieve) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setProjectionReceiver(shouldRecieve); } static void android_view_DisplayList_setOutline(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong outlinePathPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); SkPath* outline = reinterpret_cast<SkPath*>(outlinePathPtr); displayList->setOutline(outline); } static void android_view_DisplayList_setClipToOutline(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean clipToOutline) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setClipToOutline(clipToOutline); } static void android_view_DisplayList_setCastsShadow(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean castsShadow) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setCastsShadow(castsShadow); } static void android_view_DisplayList_setUsesGlobalCamera(JNIEnv* env, jobject clazz, jlong displayListPtr, jboolean usesGlobalCamera) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setUsesGlobalCamera(usesGlobalCamera); } static void android_view_DisplayList_setAlpha(JNIEnv* env, jobject clazz, jlong displayListPtr, float alpha) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setAlpha(alpha); } static void android_view_DisplayList_setHasOverlappingRendering(JNIEnv* env, jobject clazz, jlong displayListPtr, bool hasOverlappingRendering) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setHasOverlappingRendering(hasOverlappingRendering); } static void android_view_DisplayList_setTranslationX(JNIEnv* env, jobject clazz, jlong displayListPtr, float tx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setTranslationX(tx); } static void android_view_DisplayList_setTranslationY(JNIEnv* env, jobject clazz, jlong displayListPtr, float ty) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setTranslationY(ty); } static void android_view_DisplayList_setTranslationZ(JNIEnv* env, jobject clazz, jlong displayListPtr, float tz) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setTranslationZ(tz); } static void android_view_DisplayList_setRotation(JNIEnv* env, jobject clazz, jlong displayListPtr, float rotation) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setRotation(rotation); } static void android_view_DisplayList_setRotationX(JNIEnv* env, jobject clazz, jlong displayListPtr, float rx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setRotationX(rx); } static void android_view_DisplayList_setRotationY(JNIEnv* env, jobject clazz, jlong displayListPtr, float ry) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setRotationY(ry); } static void android_view_DisplayList_setScaleX(JNIEnv* env, jobject clazz, jlong displayListPtr, float sx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setScaleX(sx); } static void android_view_DisplayList_setScaleY(JNIEnv* env, jobject clazz, jlong displayListPtr, float sy) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setScaleY(sy); } @@ -205,7 +205,7 @@ static void android_view_DisplayList_setTransformationInfo(JNIEnv* env, jobject clazz, jlong displayListPtr, float alpha, float translationX, float translationY, float translationZ, float rotation, float rotationX, float rotationY, float scaleX, float scaleY) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setAlpha(alpha); displayList->setTranslationX(translationX); displayList->setTranslationY(translationY); @@ -219,158 +219,158 @@ static void android_view_DisplayList_setTransformationInfo(JNIEnv* env, static void android_view_DisplayList_setPivotX(JNIEnv* env, jobject clazz, jlong displayListPtr, float px) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setPivotX(px); } static void android_view_DisplayList_setPivotY(JNIEnv* env, jobject clazz, jlong displayListPtr, float py) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setPivotY(py); } static void android_view_DisplayList_setCameraDistance(JNIEnv* env, jobject clazz, jlong displayListPtr, float distance) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setCameraDistance(distance); } static void android_view_DisplayList_setLeft(JNIEnv* env, jobject clazz, jlong displayListPtr, int left) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setLeft(left); } static void android_view_DisplayList_setTop(JNIEnv* env, jobject clazz, jlong displayListPtr, int top) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setTop(top); } static void android_view_DisplayList_setRight(JNIEnv* env, jobject clazz, jlong displayListPtr, int right) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setRight(right); } static void android_view_DisplayList_setBottom(JNIEnv* env, jobject clazz, jlong displayListPtr, int bottom) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setBottom(bottom); } static void android_view_DisplayList_setLeftTopRightBottom(JNIEnv* env, jobject clazz, jlong displayListPtr, int left, int top, int right, int bottom) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->setLeftTopRightBottom(left, top, right, bottom); } static void android_view_DisplayList_offsetLeftAndRight(JNIEnv* env, jobject clazz, jlong displayListPtr, float offset) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->offsetLeftRight(offset); } static void android_view_DisplayList_offsetTopAndBottom(JNIEnv* env, jobject clazz, jlong displayListPtr, float offset) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); displayList->offsetTopBottom(offset); } static jboolean android_view_DisplayList_hasOverlappingRendering(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->hasOverlappingRendering(); } static jfloat android_view_DisplayList_getAlpha(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getAlpha(); } static jfloat android_view_DisplayList_getLeft(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getLeft(); } static jfloat android_view_DisplayList_getTop(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getTop(); } static jfloat android_view_DisplayList_getRight(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getRight(); } static jfloat android_view_DisplayList_getBottom(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getBottom(); } static jfloat android_view_DisplayList_getCameraDistance(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getCameraDistance(); } static jfloat android_view_DisplayList_getScaleX(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getScaleX(); } static jfloat android_view_DisplayList_getScaleY(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getScaleY(); } static jfloat android_view_DisplayList_getTranslationX(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getTranslationX(); } static jfloat android_view_DisplayList_getTranslationY(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getTranslationY(); } static jfloat android_view_DisplayList_getRotation(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getRotation(); } static jfloat android_view_DisplayList_getRotationX(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getRotationX(); } static jfloat android_view_DisplayList_getRotationY(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getRotationY(); } static jfloat android_view_DisplayList_getPivotX(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getPivotX(); } static jfloat android_view_DisplayList_getPivotY(JNIEnv* env, jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); return displayList->getPivotY(); } diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index a4e6679..aa6a035 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -879,7 +879,7 @@ static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong displayListPtr, jobject dirty, jint flags) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); android::uirenderer::Rect bounds; status_t status = renderer->drawDisplayList(displayList, bounds, flags); if (status != DrawGlInfo::kStatusDone && dirty != NULL) { @@ -975,7 +975,7 @@ static void android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) { #ifdef USE_OPENGL_RENDERER int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor); - android::uirenderer::DisplayList::outputLogBuffer(fd); + android::uirenderer::RenderNode::outputLogBuffer(fd); #endif // USE_OPENGL_RENDERER } diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp index b7e795e..228a92e 100644 --- a/core/jni/android_view_GLRenderer.cpp +++ b/core/jni/android_view_GLRenderer.cpp @@ -143,7 +143,7 @@ static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz, static void android_view_GLRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong newDataPtr) { using namespace android::uirenderer; - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); displayList->setData(newData); } diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 5b21e94..ad2e9ff 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -120,7 +120,7 @@ static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject cl jlong layerUpdaterPtr, jlong displayListPtr, jint left, jint top, jint right, jint bottom) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); layer->setDisplayList(displayList, left, top, right, bottom); } diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 2b20758..28cee4b 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -106,7 +106,7 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, static void android_view_ThreadedRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); proxy->setDisplayListData(displayList, newData); } @@ -115,7 +115,7 @@ static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject c jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); } diff --git a/docs/html/google/auth/api-client.jd b/docs/html/google/auth/api-client.jd index fda3310..402a95f 100644 --- a/docs/html/google/auth/api-client.jd +++ b/docs/html/google/auth/api-client.jd @@ -112,7 +112,7 @@ GoogleApiClient}</a>, you must specify an implementation for the callback interf href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html" >{@code ConnectionCallbacks}</a> and <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.OnConnectionFailedListener.html" ->{@code onConnectionFailedListener}</a>. These interfaces receive callbacks in +>{@code OnConnectionFailedListener}</a>. These interfaces receive callbacks in response to the asynchronous <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()" >{@code connect()}</a> method when the connection to Google Play services @@ -512,7 +512,7 @@ private void loadFile(String filename) { new GetFileTask().execute(filename); } -private class GetFileTask extends AsyncTask<String, Void, Void> { +private class GetFileTask extends AsyncTask<String, Void, Void> { protected void doInBackground(String filename) { Query query = new Query.Builder() .addFilter(Filters.eq(SearchableField.TITLE, filename)) diff --git a/docs/html/guide/topics/ui/controls/button.jd b/docs/html/guide/topics/ui/controls/button.jd index 02597c8..b52c3e9 100644 --- a/docs/html/guide/topics/ui/controls/button.jd +++ b/docs/html/guide/topics/ui/controls/button.jd @@ -113,7 +113,7 @@ android.view.View} that was clicked)</li> <h3 id="ClickListener">Using an OnClickListener</h3> -<p>You can also declare the click event handler pragmatically rather than in an XML layout. This +<p>You can also declare the click event handler programmatically rather than in an XML layout. This might be necessary if you instantiate the {@link android.widget.Button} at runtime or you need to declare the click behavior in a {@link android.app.Fragment} subclass.</p> diff --git a/docs/html/guide/topics/ui/controls/togglebutton.jd b/docs/html/guide/topics/ui/controls/togglebutton.jd index c57b510..09af516 100644 --- a/docs/html/guide/topics/ui/controls/togglebutton.jd +++ b/docs/html/guide/topics/ui/controls/togglebutton.jd @@ -99,7 +99,7 @@ android.widget.CompoundButton#toggle()} method to change the state.</p> <h3 id="ClickListener">Using an OnCheckedChangeListener</h3> -<p>You can also declare a click event handler pragmatically rather than in an XML layout. This +<p>You can also declare a click event handler programmatically rather than in an XML layout. This might be necessary if you instantiate the {@link android.widget.ToggleButton} or {@link android.widget.Switch} at runtime or you need to declare the click behavior in a {@link android.app.Fragment} subclass.</p> diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp index 4935b34..8327ef7 100644 --- a/libs/hwui/AmbientShadow.cpp +++ b/libs/hwui/AmbientShadow.cpp @@ -47,9 +47,8 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount const Vector3& centroid3d, float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) { const int rays = SHADOW_RAY_COUNT; - const int layers = SHADOW_LAYER_COUNT; // Validate the inputs. - if (vertexCount < 3 || heightFactor <= 0 || layers <= 0 || rays <= 0 + if (vertexCount < 3 || heightFactor <= 0 || rays <= 0 || geomFactor <= 0) { #if DEBUG_SHADOW ALOGE("Invalid input for createAmbientShadow(), early return!"); @@ -96,33 +95,32 @@ void AmbientShadow::createAmbientShadow(const Vector3* vertices, int vertexCount // calculate the normal N, which should be perpendicular to the edge of the // polygon (represented by the neighbor intersection points) . // Shadow's vertices will be generated as : P + N * scale. - int currentVertexIndex = 0; - for (int layerIndex = 0; layerIndex <= layers; layerIndex++) { - for (int rayIndex = 0; rayIndex < rays; rayIndex++) { - - Vector2 normal(1.0f, 0.0f); - calculateNormal(rays, rayIndex, dir.array(), rayDist, normal); - - float opacity = 1.0 / (1 + rayHeight[rayIndex] / heightFactor); - - // The vertex should be start from rayDist[i] then scale the - // normalizeNormal! - Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] + - Vector2(centroid3d.x, centroid3d.y); - - float layerRatio = layerIndex / (float)(layers); - // The higher the intersection is, the further the ambient shadow expanded. - float expansionDist = rayHeight[rayIndex] / heightFactor * - geomFactor * (1 - layerRatio); - AlphaVertex::set(&shadowVertices[currentVertexIndex++], - intersection.x + normal.x * expansionDist, - intersection.y + normal.y * expansionDist, - layerRatio * opacity); - } - + for (int rayIndex = 0; rayIndex < rays; rayIndex++) { + Vector2 normal(1.0f, 0.0f); + calculateNormal(rays, rayIndex, dir.array(), rayDist, normal); + + // The vertex should be start from rayDist[i] then scale the + // normalizeNormal! + Vector2 intersection = dir[rayIndex] * rayDist[rayIndex] + + Vector2(centroid3d.x, centroid3d.y); + + // outer ring of points, expanded based upon height of each ray intersection + float expansionDist = rayHeight[rayIndex] * heightFactor * + geomFactor; + AlphaVertex::set(&shadowVertices[rayIndex], + intersection.x + normal.x * expansionDist, + intersection.y + normal.y * expansionDist, + 0.0f); + + // inner ring of points + float opacity = 1.0 / (1 + rayHeight[rayIndex] * heightFactor); + AlphaVertex::set(&shadowVertices[rayIndex + rays], + intersection.x, + intersection.y, + opacity); } - float centroidAlpha = 1.0 / (1 + centroid3d.z / heightFactor); - AlphaVertex::set(&shadowVertices[currentVertexIndex++], + float centroidAlpha = 1.0 / (1 + centroid3d.z * heightFactor); + AlphaVertex::set(&shadowVertices[SHADOW_VERTEX_COUNT - 1], centroid3d.x, centroid3d.y, centroidAlpha); #if DEBUG_SHADOW diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 1d58d96..2dfc873 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -315,7 +315,7 @@ void Caches::clearGarbage() { pathCache.clearGarbage(); patchCache.clearGarbage(); - Vector<DisplayList*> displayLists; + Vector<RenderNode*> displayLists; Vector<Layer*> layers; { // scope for the lock @@ -328,7 +328,7 @@ void Caches::clearGarbage() { size_t count = displayLists.size(); for (size_t i = 0; i < count; i++) { - DisplayList* displayList = displayLists.itemAt(i); + RenderNode* displayList = displayLists.itemAt(i); delete displayList; } @@ -345,7 +345,7 @@ void Caches::deleteLayerDeferred(Layer* layer) { mLayerGarbage.push(layer); } -void Caches::deleteDisplayListDeferred(DisplayList* displayList) { +void Caches::deleteDisplayListDeferred(RenderNode* displayList) { Mutex::Autolock _l(mGarbageLock); mDisplayListGarbage.push(displayList); } @@ -702,11 +702,8 @@ TextureVertex* Caches::getRegionMesh() { /////////////////////////////////////////////////////////////////////////////// void Caches::initTempProperties() { - propertyDirtyViewport = false; - propertyEnable3d = false; - propertyCameraDistance = 1.0f; - propertyAmbientShadowStrength = 0x3f; - propertySpotShadowStrength = 0x3f; + propertyAmbientShadowStrength = 25; + propertySpotShadowStrength = 25; propertyLightPosXScale = 0.5f; propertyLightPosYScale = 0.0f; @@ -715,17 +712,7 @@ void Caches::initTempProperties() { void Caches::setTempProperty(const char* name, const char* value) { ALOGD("setting property %s to %s", name, value); - if (!strcmp(name, "enable3d")) { - propertyEnable3d = !strcmp(value, "true"); - propertyDirtyViewport = true; - ALOGD("enable3d = %d", propertyEnable3d); - return; - } else if (!strcmp(name, "cameraDistance")) { - propertyCameraDistance = fmin(fmax(atof(value), 0.001), 10); - propertyDirtyViewport = true; - ALOGD("camera dist multiplier = %.2f", propertyCameraDistance); - return; - } else if (!strcmp(name, "ambientShadowStrength")) { + if (!strcmp(name, "ambientShadowStrength")) { propertyAmbientShadowStrength = atoi(value); ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength); return; @@ -735,17 +722,14 @@ void Caches::setTempProperty(const char* name, const char* value) { return; } else if (!strcmp(name, "lightPosXScale")) { propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0); - propertyDirtyViewport = true; ALOGD("lightPos X Scale = %.2f", propertyLightPosXScale); return; } else if (!strcmp(name, "lightPosYScale")) { propertyLightPosYScale = fmin(fmax(atof(value), 0.0), 1.0); - propertyDirtyViewport = true; ALOGD("lightPos Y Scale = %.2f", propertyLightPosXScale); return; } else if (!strcmp(name, "lightPosZScale")) { propertyLightPosZScale = fmin(fmax(atof(value), 0.0), 1.0); - propertyDirtyViewport = true; ALOGD("lightPos Z Scale = %.2f", propertyLightPosXScale); return; } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 8c0c508..50c5fef 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -102,7 +102,7 @@ struct CacheLogger { // Caches /////////////////////////////////////////////////////////////////////////////// -class DisplayList; +class RenderNode; class ANDROID_API Caches: public Singleton<Caches> { Caches(); @@ -169,7 +169,7 @@ public: /* * Can be used to delete a display list from a non EGL thread. */ - void deleteDisplayListDeferred(DisplayList* layer); + void deleteDisplayListDeferred(RenderNode* layer); /** * Binds the VBO used to render simple textured quads. @@ -356,9 +356,6 @@ public: // TEMPORARY properties void initTempProperties(); void setTempProperty(const char* name, const char* value); - bool propertyEnable3d; - bool propertyDirtyViewport; // flag set when dirtying the viewport - float propertyCameraDistance; // These scaling factors range from 0 to 1, to scale the light position // within the bound of (screenwidth, screenheight, max(screenwidth, screenheight)); @@ -423,7 +420,7 @@ private: mutable Mutex mGarbageLock; Vector<Layer*> mLayerGarbage; - Vector<DisplayList*> mDisplayListGarbage; + Vector<RenderNode*> mDisplayListGarbage; DebugLevel mDebugLevel; bool mInitialized; diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 7a2e288..7a83967 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -54,7 +54,7 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { SkRefCnt_SafeAssign(mColorFilter, colorFilter); } -void DeferredLayerUpdater::setDisplayList(DisplayList* displayList, +void DeferredLayerUpdater::setDisplayList(RenderNode* displayList, int left, int top, int right, int bottom) { mDisplayList = displayList; if (mDirtyRect.isEmpty()) { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 65f225c..d124cde 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -72,7 +72,7 @@ public: mTransform = matrix ? new SkMatrix(*matrix) : 0; } - ANDROID_API void setDisplayList(DisplayList* displayList, + ANDROID_API void setDisplayList(RenderNode* displayList, int left, int top, int right, int bottom); ANDROID_API void setPaint(const SkPaint* paint); @@ -101,7 +101,7 @@ private: // Layer type specific properties // displayList and surfaceTexture are mutually exclusive, only 1 may be set // dirtyRect is only valid if displayList is set - DisplayList* mDisplayList; + RenderNode* mDisplayList; Rect mDirtyRect; sp<GLConsumer> mSurfaceTexture; SkMatrix* mTransform; diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 0f76486..f038427 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -29,7 +29,7 @@ namespace android { namespace uirenderer { -void DisplayList::outputLogBuffer(int fd) { +void RenderNode::outputLogBuffer(int fd) { DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); if (logBuffer.isEmpty()) { return; @@ -48,7 +48,7 @@ void DisplayList::outputLogBuffer(int fd) { fflush(file); } -DisplayList::DisplayList() : +RenderNode::RenderNode() : mDisplayListData(0), mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) { @@ -87,7 +87,7 @@ DisplayList::DisplayList() : mCaching = false; } -DisplayList::~DisplayList() { +RenderNode::~RenderNode() { LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this); mDestroyed = true; @@ -99,14 +99,14 @@ DisplayList::~DisplayList() { delete mAnimationMatrix; } -void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { +void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) { if (displayList) { DISPLAY_LIST_LOGD("Deferring display list destruction"); Caches::getInstance().deleteDisplayListDeferred(displayList); } } -void DisplayList::setData(DisplayListData* data) { +void RenderNode::setData(DisplayListData* data) { delete mDisplayListData; mDisplayListData = data; if (mDisplayListData) { @@ -118,7 +118,7 @@ void DisplayList::setData(DisplayListData* data) { * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ -void DisplayList::output(uint32_t level) { +void RenderNode::output(uint32_t level) { ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, mName.string(), isRenderable()); ALOGD("%*s%s %d", level * 2, "", "Save", @@ -133,17 +133,17 @@ void DisplayList::output(uint32_t level) { ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); } -float DisplayList::getPivotX() { +float RenderNode::getPivotX() { updateMatrix(); return mPivotX; } -float DisplayList::getPivotY() { +float RenderNode::getPivotY() { updateMatrix(); return mPivotY; } -void DisplayList::updateMatrix() { +void RenderNode::updateMatrix() { if (mMatrixDirty) { // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform // to a pure translate. This is safe because the matrix isn't read in pure translate cases. @@ -160,8 +160,8 @@ void DisplayList::updateMatrix() { mPivotY = mPrevHeight / 2.0f; } } - const bool perspectiveEnabled = Caches::getInstance().propertyEnable3d; - if (!perspectiveEnabled && (mMatrixFlags & ROTATION_3D) == 0) { + + if ((mMatrixFlags & ROTATION_3D) == 0) { mTransformMatrix->loadTranslate( mPivotX + mTranslationX, mPivotY + mTranslationY, @@ -170,45 +170,32 @@ void DisplayList::updateMatrix() { mTransformMatrix->scale(mScaleX, mScaleY, 1); mTransformMatrix->translate(-mPivotX, -mPivotY); } else { - if (perspectiveEnabled) { - mTransformMatrix->loadTranslate( - mPivotX + mTranslationX, - mPivotY + mTranslationY, - mTranslationZ); - mTransformMatrix->rotate(mRotationX, 1, 0, 0); - mTransformMatrix->rotate(mRotationY, 0, 1, 0); - mTransformMatrix->rotate(mRotation, 0, 0, 1); - mTransformMatrix->scale(mScaleX, mScaleY, 1); - mTransformMatrix->translate(-mPivotX, -mPivotY); - } else { - /* TODO: support this old transform approach, based on API level */ - if (!mTransformCamera) { - mTransformCamera = new Sk3DView(); - mTransformMatrix3D = new SkMatrix(); - } - SkMatrix transformMatrix; - transformMatrix.reset(); - mTransformCamera->save(); - transformMatrix.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); - transformMatrix.postConcat(*mTransformMatrix3D); - mTransformCamera->restore(); - - mTransformMatrix->load(transformMatrix); + if (!mTransformCamera) { + mTransformCamera = new Sk3DView(); + mTransformMatrix3D = new SkMatrix(); } + SkMatrix transformMatrix; + transformMatrix.reset(); + mTransformCamera->save(); + transformMatrix.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); + transformMatrix.postConcat(*mTransformMatrix3D); + mTransformCamera->restore(); + + mTransformMatrix->load(transformMatrix); } } mMatrixDirty = false; } } -void DisplayList::outputViewProperties(const int level) { +void RenderNode::outputViewProperties(const int level) { updateMatrix(); if (mLeft != 0 || mTop != 0) { ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop); @@ -262,7 +249,7 @@ void DisplayList::outputViewProperties(const int level) { #define PROPERTY_SAVECOUNT 0 template <class T> -void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, +void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler, const int level) { #if DEBUG_DISPLAY_LIST outputViewProperties(level); @@ -278,8 +265,7 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, } if (mMatrixFlags != 0) { if (mMatrixFlags == TRANSLATION) { - renderer.translate(mTranslationX, mTranslationY, - Caches::getInstance().propertyEnable3d ? mTranslationZ : 0.0f); // TODO: necessary? + renderer.translate(mTranslationX, mTranslationY); } else { renderer.concatMatrix(*mTransformMatrix); } @@ -318,8 +304,11 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, /** * Apply property-based transformations to input matrix + * + * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4 + * matrix computation instead of the Skia 3x3 matrix + camera hackery. */ -void DisplayList::applyViewPropertyTransforms(mat4& matrix) { +void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) { if (mLeft != 0 || mTop != 0) { matrix.translate(mLeft, mTop); } @@ -333,24 +322,39 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { if (mMatrixFlags != 0) { updateMatrix(); if (mMatrixFlags == TRANSLATION) { - matrix.translate(mTranslationX, mTranslationY, mTranslationZ); + matrix.translate(mTranslationX, mTranslationY, + true3dTransform ? mTranslationZ : 0.0f); } else { - matrix.multiply(*mTransformMatrix); + if (!true3dTransform) { + matrix.multiply(*mTransformMatrix); + } else { + mat4 true3dMat; + true3dMat.loadTranslate( + mPivotX + mTranslationX, + mPivotY + mTranslationY, + mTranslationZ); + true3dMat.rotate(mRotationX, 1, 0, 0); + true3dMat.rotate(mRotationY, 0, 1, 0); + true3dMat.rotate(mRotation, 0, 0, 1); + true3dMat.scale(mScaleX, mScaleY, 1); + true3dMat.translate(-mPivotX, -mPivotY); + + matrix.multiply(true3dMat); + } } } } /** - * Organizes the DisplayList hierarchy to prepare for Z-based draw order. + * Organizes the DisplayList hierarchy to prepare for background projection reordering. * * This should be called before a call to defer() or drawDisplayList() * * Each DisplayList that serves as a 3d root builds its list of composited children, * which are flagged to not draw in the standard draw loop. */ -void DisplayList::computeOrdering() { +void RenderNode::computeOrdering() { ATRACE_CALL(); - m3dNodes.clear(); mProjectedNodes.clear(); // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that @@ -359,40 +363,23 @@ void DisplayList::computeOrdering() { for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, - &m3dNodes, &mat4::identity(), &mProjectedNodes, &mat4::identity()); } } -void DisplayList::computeOrderingImpl( +void RenderNode::computeOrderingImpl( DrawDisplayListOp* opState, - Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, - const mat4* transformFrom3dRoot, Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { - m3dNodes.clear(); mProjectedNodes.clear(); if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return; // TODO: should avoid this calculation in most cases // TODO: just calculate single matrix, down to all leaf composited elements - Matrix4 localTransformFrom3dRoot(*transformFrom3dRoot); - localTransformFrom3dRoot.multiply(opState->mTransformFromParent); Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); localTransformFromProjectionSurface.multiply(opState->mTransformFromParent); - if (mTranslationZ != 0.0f) { // TODO: other signals for 3d compositing, such as custom matrix4 - // composited 3d layer, flag for out of order draw and save matrix... - opState->mSkipInOrderDraw = true; - opState->mTransformFromCompositingAncestor.load(localTransformFrom3dRoot); - - // ... and insert into current 3d root, keyed with pivot z for later sorting - Vector3 pivot(mPivotX, mPivotY, 0.0f); - mat4 totalTransform(localTransformFrom3dRoot); - applyViewPropertyTransforms(totalTransform); - totalTransform.mapPoint3d(pivot); - compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState)); - } else if (mProjectBackwards) { + if (mProjectBackwards) { // composited projectee, flag for out of order draw, save matrix, and store in proj surface opState->mSkipInOrderDraw = true; opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); @@ -403,20 +390,11 @@ void DisplayList::computeOrderingImpl( } if (mDisplayListData->children.size() > 0) { - if (mIsolatedZVolume) { - // create a new 3d space for descendents by collecting them - compositedChildrenOf3dRoot = &m3dNodes; - transformFrom3dRoot = &mat4::identity(); - } else { - applyViewPropertyTransforms(localTransformFrom3dRoot); - transformFrom3dRoot = &localTransformFrom3dRoot; - } - const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0; bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; - DisplayList* child = childOp->mDisplayList; + RenderNode* child = childOp->mDisplayList; Vector<DrawDisplayListOp*>* projectionChildren = NULL; const mat4* projectionTransform = NULL; @@ -436,9 +414,7 @@ void DisplayList::computeOrderingImpl( projectionChildren = compositedChildrenOfProjectionSurface; projectionTransform = &localTransformFromProjectionSurface; } - child->computeOrderingImpl(childOp, - compositedChildrenOf3dRoot, transformFrom3dRoot, - projectionChildren, projectionTransform); + child->computeOrderingImpl(childOp, projectionChildren, projectionTransform); } } @@ -458,7 +434,7 @@ private: const int mLevel; }; -void DisplayList::defer(DeferStateStruct& deferStruct, const int level) { +void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { DeferOperationHandler handler(deferStruct, level); iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); } @@ -480,7 +456,7 @@ private: const int mLevel; }; -void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { +void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { ReplayOperationHandler handler(replayStruct, level); replayStruct.mRenderer.startMark(mName.string()); @@ -491,14 +467,36 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { replayStruct.mDrawGlStatus); } -#define SHADOW_DELTA 2.0f +void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { + if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return; + + for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { + DrawDisplayListOp* childOp = mDisplayListData->children[i]; + RenderNode* child = childOp->mDisplayList; + float childZ = child->mTranslationZ; + + if (childZ != 0.0f) { + zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp)); + childOp->mSkipInOrderDraw = true; + } else if (!child->mProjectBackwards) { + // regular, in order drawing DisplayList + childOp->mSkipInOrderDraw = false; + } + } + + // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) + std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end()); +} + +#define SHADOW_DELTA 0.1f template <class T> -void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, - T& handler, const int level) { - if (m3dNodes.size() == 0 || - (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) || - (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) { +void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, + ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) { + const int size = zTranslatedNodes.size(); + if (size == 0 + || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f) + || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) { // no 3d children to draw return; } @@ -516,7 +514,7 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are * underneath both, and neither's shadow is drawn on top of the other. */ - const size_t nonNegativeIndex = findNonNegativeIndex(m3dNodes); + const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); size_t drawIndex, shadowIndex, endIndex; if (mode == kNegativeZChildren) { drawIndex = 0; @@ -524,24 +522,29 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren shadowIndex = endIndex; // draw no shadows } else { drawIndex = nonNegativeIndex; - endIndex = m3dNodes.size(); + endIndex = size; shadowIndex = drawIndex; // potentially draw shadow for each pos Z child } float lastCasterZ = 0.0f; while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { - DrawDisplayListOp* casterOp = m3dNodes[shadowIndex].value; - DisplayList* caster = casterOp->mDisplayList; - const float casterZ = m3dNodes[shadowIndex].key; + DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value; + RenderNode* caster = casterOp->mDisplayList; + const float casterZ = zTranslatedNodes[shadowIndex].key; // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { if (caster->mCastsShadow && caster->mAlpha > 0.0f) { - mat4 shadowMatrix(casterOp->mTransformFromCompositingAncestor); - caster->applyViewPropertyTransforms(shadowMatrix); + mat4 shadowMatrixXY(casterOp->mTransformFromParent); + caster->applyViewPropertyTransforms(shadowMatrixXY); - DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, + // Z matrix needs actual 3d transformation, so mapped z values will be correct + mat4 shadowMatrixZ(casterOp->mTransformFromParent); + caster->applyViewPropertyTransforms(shadowMatrixZ, true); + + DisplayListOp* shadowOp = new (alloc) DrawShadowOp( + shadowMatrixXY, shadowMatrixZ, caster->mAlpha, &(caster->mOutline), caster->mWidth, caster->mHeight); handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); } @@ -556,10 +559,10 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren // since it modifies the renderer's matrix int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); - DrawDisplayListOp* childOp = m3dNodes[drawIndex].value; - DisplayList* child = childOp->mDisplayList; + DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value; + RenderNode* child = childOp->mDisplayList; - renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); + renderer.concatMatrix(childOp->mTransformFromParent); childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); childOp->mSkipInOrderDraw = true; @@ -571,7 +574,7 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren } template <class T> -void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { +void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); LinearAllocator& alloc = handler.allocator(); ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, @@ -602,7 +605,7 @@ void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, * defer vs replay logic, per operation */ template <class T> -void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) { +void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) { if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging ALOGW("Error: %s is drawing after destruction", getName()); CRASH(); @@ -631,11 +634,11 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); if (!quickRejected) { - // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(m3dNodes.begin(), m3dNodes.end()); + Vector<ZDrawDisplayListOpPair> zTranslatedNodes; + buildZSortedChildList(zTranslatedNodes); // for 3d root, draw children with negative z values - iterate3dChildren(kNegativeZChildren, renderer, handler, level); + iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler); DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); const int saveCountOffset = renderer.getSaveCount() - 1; @@ -656,7 +659,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) } // for 3d root, draw children with positive z values - iterate3dChildren(kPositiveZChildren, renderer, handler, level); + iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler); } DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index a3577d4..7d0e30e 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -160,17 +160,17 @@ private: * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay * attached. */ -class DisplayList { +class RenderNode { public: - ANDROID_API DisplayList(); - ANDROID_API ~DisplayList(); + ANDROID_API RenderNode(); + ANDROID_API ~RenderNode(); // See flags defined in DisplayList.java enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 }; - ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList); + ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList); ANDROID_API static void outputLogBuffer(int fd); ANDROID_API void setData(DisplayListData* newData); @@ -573,20 +573,20 @@ private: void outputViewProperties(const int level); - void applyViewPropertyTransforms(mat4& matrix); + void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false); void computeOrderingImpl(DrawDisplayListOp* opState, - Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, - const mat4* transformFrom3dRoot, Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface); template <class T> inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level); + void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes); + template <class T> - inline void iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, - T& handler, const int level); + inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, + ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler); template <class T> inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level); @@ -657,9 +657,6 @@ private: * Draw time state - these properties are only set and used during rendering */ - // for 3d roots, contains a z sorted list of all children items - Vector<ZDrawDisplayListOpPair> m3dNodes; - // for projection surfaces, contains a list of all children items Vector<DrawDisplayListOp*> mProjectedNodes; }; // class DisplayList diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 65eda29..549b786 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1488,9 +1488,9 @@ private: }; class DrawDisplayListOp : public DrawBoundedOp { - friend class DisplayList; // grant DisplayList access to info of child + friend class RenderNode; // grant DisplayList access to info of child public: - DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent) + DrawDisplayListOp(RenderNode* displayList, int flags, const mat4& transformFromParent) : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0), mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {} @@ -1522,7 +1522,7 @@ public: virtual const char* name() { return "DrawDisplayList"; } private: - DisplayList* mDisplayList; + RenderNode* mDisplayList; const int mFlags; /////////////////////////// @@ -1534,10 +1534,10 @@ private: const mat4 mTransformFromParent; /** - * Holds the transformation between the 3d root OR projection surface ViewGroup and this - * DisplayList drawing instance. Represents any translations / transformations done within the - * drawing of the compositing ancestor ViewGroup's draw, before the draw of the View represented - * by this DisplayList draw instance. + * Holds the transformation between the projection surface ViewGroup and this DisplayList + * drawing instance. Represents any translations / transformations done within the drawing of + * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this + * DisplayList draw instance. * * Note: doesn't include any transformation recorded within the DisplayList and its properties. */ @@ -1550,19 +1550,20 @@ private: */ class DrawShadowOp : public DrawOp { public: - DrawShadowOp(const mat4& transform, float alpha, const SkPath* outline, + DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha, const SkPath* outline, float fallbackWidth, float fallbackHeight) - : DrawOp(NULL), mTransform(transform), mAlpha(alpha), mOutline(outline), + : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), + mAlpha(alpha), mOutline(outline), mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { - if (!mOutline->isEmpty()) { - return renderer.drawShadow(mTransform, mAlpha, mOutline); + if (mOutline->isEmpty()) { + SkPath fakeOutline; + fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); + return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &fakeOutline); } - SkPath fakeOutline; - fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); - return renderer.drawShadow(mTransform, mAlpha, &fakeOutline); + return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, mOutline); } virtual void output(int level, uint32_t logFlags) const { @@ -1572,7 +1573,8 @@ public: virtual const char* name() { return "DrawShadow"; } private: - const mat4 mTransform; + const mat4 mTransformXY; + const mat4 mTransformZ; const float mAlpha; const SkPath* mOutline; const float mFallbackWidth; diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 3b1d567..e69e08e 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -179,7 +179,7 @@ bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { return StatefulBaseRenderer::clipRegion(region, op); } -status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList, +status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t flags) { // dirty is an out parameter and should not be recorded, // it matters only when replaying the display list diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 1fb72ce..65498a5 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -156,7 +156,7 @@ public: // Canvas draw operations - special // ---------------------------------------------------------------------------- virtual status_t drawLayer(Layer* layer, float x, float y); - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags); // TODO: rename for consistency @@ -309,7 +309,7 @@ private: int mRestoreSaveCount; - friend class DisplayList; + friend class RenderNode; }; // class DisplayListRenderer diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 8992a13..52176d4 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -194,7 +194,7 @@ void Layer::defer() { deferredList = new DeferredDisplayList(dirtyRect); DeferStateStruct deferredState(*deferredList, *renderer, - DisplayList::kReplayFlag_ClipChildren); + RenderNode::kReplayFlag_ClipChildren); renderer->initViewport(width, height); renderer->setupFrameState(dirtyRect.left, dirtyRect.top, @@ -238,7 +238,7 @@ void Layer::render() { renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren); + renderer->drawDisplayList(displayList, dirtyRect, RenderNode::kReplayFlag_ClipChildren); renderer->finish(); renderer = NULL; diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index f6538f2..d8440ea 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -43,7 +43,7 @@ namespace uirenderer { // Forward declarations class Caches; class OpenGLRenderer; -class DisplayList; +class RenderNode; class DeferredDisplayList; class DeferStateStruct; @@ -84,7 +84,7 @@ public: regionRect.translate(layer.left, layer.top); } - void updateDeferred(OpenGLRenderer* renderer, DisplayList* displayList, + void updateDeferred(OpenGLRenderer* renderer, RenderNode* displayList, int left, int top, int right, int bottom) { this->renderer = renderer; this->displayList = displayList; @@ -294,7 +294,7 @@ public: */ bool deferredUpdateScheduled; OpenGLRenderer* renderer; - DisplayList* displayList; + RenderNode* displayList; Rect dirtyRect; bool debugDrawUpdate; bool hasDrawnSinceUpdate; diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 4f5cd26..f06106b 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -372,84 +372,6 @@ void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) { mType = kTypeUnknown; } -// translated from android.opengl.Matrix#frustumM() -void Matrix4::loadFrustum(float left, float top, float right, float bottom, float near, float far) { - float r_width = 1.0f / (right - left); - float r_height = 1.0f / (top - bottom); - float r_depth = 1.0f / (near - far); - float x = 2.0f * (near * r_width); - float y = 2.0f * (near * r_height); - float A = (right + left) * r_width; - float B = (top + bottom) * r_height; - float C = (far + near) * r_depth; - float D = 2.0f * (far * near * r_depth); - - memset(&data, 0, sizeof(data)); - mType = kTypeUnknown; - - data[kScaleX] = x; - data[kScaleY] = y; - data[8] = A; - data[9] = B; - data[kScaleZ] = C; - data[kTranslateZ] = D; - data[11] = -1.0f; -} - -// translated from android.opengl.Matrix#setLookAtM() -void Matrix4::loadLookAt(float eyeX, float eyeY, float eyeZ, - float centerX, float centerY, float centerZ, - float upX, float upY, float upZ) { - float fx = centerX - eyeX; - float fy = centerY - eyeY; - float fz = centerZ - eyeZ; - - // Normalize f - float rlf = 1.0f / sqrt(fx*fx + fy*fy + fz*fz); - fx *= rlf; - fy *= rlf; - fz *= rlf; - - // compute s = f x up (x means "cross product") - float sx = fy * upZ - fz * upY; - float sy = fz * upX - fx * upZ; - float sz = fx * upY - fy * upX; - - // and normalize s - float rls = 1.0f / sqrt(sx*sx + sy*sy + sz*sz); - sx *= rls; - sy *= rls; - sz *= rls; - - // compute u = s x f - float ux = sy * fz - sz * fy; - float uy = sz * fx - sx * fz; - float uz = sx * fy - sy * fx; - - mType = kTypeUnknown; - data[0] = sx; - data[1] = ux; - data[2] = -fx; - data[3] = 0.0f; - - data[4] = sy; - data[5] = uy; - data[6] = -fy; - data[7] = 0.0f; - - data[8] = sz; - data[9] = uz; - data[10] = -fz; - data[11] = 0.0f; - - data[12] = 0.0f; - data[13] = 0.0f; - data[14] = 0.0f; - data[15] = 1.0f; - - translate(-eyeX, -eyeY, -eyeZ); -} - void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) { loadIdentity(); @@ -463,9 +385,14 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float mType = kTypeTranslate | kTypeScale | kTypeRectToRect; } +float Matrix4::mapZ(const Vector3& orig) const { + // duplicates logic for mapPoint3d's z coordinate + return orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ]; +} + void Matrix4::mapPoint3d(Vector3& vec) const { //TODO: optimize simple case - Vector3 orig(vec); + const Vector3 orig(vec); vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX]; vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY]; vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ]; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 5cd79b1..26cb05f 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -129,10 +129,6 @@ public: void loadRotate(float angle); void loadRotate(float angle, float x, float y, float z); void loadMultiply(const Matrix4& u, const Matrix4& v); - void loadFrustum(float left, float top, float right, float bottom, float near, float far); - void loadLookAt(float eyeX, float eyeY, float eyeZ, - float centerX, float centerY, float centerZ, - float upX, float upY, float upZ); void loadOrtho(float left, float right, float bottom, float top, float near, float far); @@ -203,6 +199,7 @@ public: void copyTo(float* v) const; void copyTo(SkMatrix& v) const; + float mapZ(const Vector3& orig) const; void mapPoint3d(Vector3& vec) const; void mapPoint(float& x, float& y) const; // 2d only void mapRect(Rect& r) const; // 2d only diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index b620b80..1475953 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -170,21 +170,7 @@ void OpenGLRenderer::setViewport(int width, int height) { } void OpenGLRenderer::initViewport(int width, int height) { - if (mCaches.propertyEnable3d) { - // TODO: make view proj app configurable - float dist = std::max(width, height) * 1.5; - dist *= mCaches.propertyCameraDistance; - Matrix4 projection; - projection.loadFrustum(-width / 2, -height / 2, width / 2, height / 2, dist, 0); - Matrix4 view; - view.loadLookAt(0, 0, dist, - 0, 0, 0, - 0, 1, 0); - mViewProjMatrix.loadMultiply(projection, view); - mViewProjMatrix.translate(-width/2, -height/2); - } else { - mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1); - } + mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1); initializeViewport(width, height); } @@ -1926,16 +1912,9 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { // Drawing /////////////////////////////////////////////////////////////////////////////// -status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, +status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags) { status_t status; - - if (mCaches.propertyDirtyViewport) { - // force recalc of view/proj matrices - setViewport(getWidth(), getHeight()); - mCaches.propertyDirtyViewport = false; - } - // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList && displayList->isRenderable()) { @@ -3211,8 +3190,16 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* return drawColorRects(rects, count, paint, false, true, true); } -status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha, - const SkPath* casterOutline) { +static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) { + // map z coordinate with true 3d matrix + point.z = transformZ.mapZ(point); + + // map x,y coordinates with draw/Skia matrix + transformXY.mapPoint(point.x, point.y); +} + +status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, + float casterAlpha, const SkPath* casterOutline) { if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; // TODO: use quickRejectWithScissor. For now, always force enable scissor. @@ -3235,10 +3222,12 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp // map 2d caster poly into 3d const int casterVertexCount = casterVertices2d.size(); Vector3 casterPolygon[casterVertexCount]; + float minZ = FLT_MAX; for (int i = 0; i < casterVertexCount; i++) { const Vertex& point2d = casterVertices2d[i]; casterPolygon[i] = Vector3(point2d.x, point2d.y, 0); - casterTransform.mapPoint3d(casterPolygon[i]); + mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ); + minZ = fmin(minZ, casterPolygon[i].z); } // map the centroid of the caster into 3d @@ -3246,7 +3235,16 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp reinterpret_cast<const Vector2*>(casterVertices2d.array()), casterVertexCount); Vector3 centroid3d(centroid.x, centroid.y, 0); - casterTransform.mapPoint3d(centroid3d); + mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); + + // if the caster intersects the z=0 plane, lift it in Z so it doesn't + if (minZ < SHADOW_MIN_CASTER_Z) { + float casterLift = SHADOW_MIN_CASTER_Z - minZ; + for (int i = 0; i < casterVertexCount; i++) { + casterPolygon[i].z += casterLift; + } + centroid3d.z += casterLift; + } // draw caster's shadows if (mCaches.propertyAmbientShadowStrength > 0) { @@ -3265,7 +3263,6 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount, lightPosScale, *currentTransform(), getWidth(), getHeight(), spotShadowVertexBuffer); - drawVertexBuffer(kVertexBufferMode_Shadow, spotShadowVertexBuffer, &paint); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 03beae3..94abfa7 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -54,7 +54,7 @@ namespace android { namespace uirenderer { class DeferredDisplayState; -class DisplayList; +class RenderNode; class TextSetupFunctor; class VertexBuffer; class SkiaShader; @@ -165,7 +165,7 @@ public: int saveLayerDeferred(float left, float top, float right, float bottom, const SkPaint* paint, int flags); - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags = 1); + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1); virtual status_t drawLayer(Layer* layer, float x, float y); virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint); @@ -208,8 +208,8 @@ public: DrawOpMode drawOpMode = kDrawOpMode_Immediate); virtual status_t drawRects(const float* rects, int count, const SkPaint* paint); - status_t drawShadow(const mat4& casterTransform, float casterAlpha, - const SkPath* casterOutline); + status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, + float casterAlpha, const SkPath* casterOutline); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index 4754bad..efcea5f 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -31,7 +31,7 @@ struct Res_png_9patch; namespace uirenderer { -class DisplayList; +class RenderNode; class Layer; class Matrix4; class SkiaColorFilter; @@ -232,7 +232,7 @@ public: // Canvas draw operations - special // ---------------------------------------------------------------------------- virtual status_t drawLayer(Layer* layer, float x, float y) = 0; - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags) = 0; // TODO: rename for consistency diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp index 5469aad..f138222 100644 --- a/libs/hwui/ShadowTessellator.cpp +++ b/libs/hwui/ShadowTessellator.cpp @@ -40,7 +40,7 @@ void ShadowTessellator::tessellateAmbientShadow(const Vector3* casterPolygon, // A bunch of parameters to tweak the shadow. // TODO: Allow some of these changable by debug settings or APIs. - const float heightFactor = 128; + const float heightFactor = 1.0f / 128; const float geomFactor = 64; AmbientShadow::createAmbientShadow(casterPolygon, casterVertexCount, @@ -69,7 +69,7 @@ void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int c reverseReceiverTransform.mapPoint3d(lightCenter); const float lightSize = maximal / 4; - const int lightVertexCount = 16; + const int lightVertexCount = 8; SpotShadow::createSpotShadow(casterPolygon, casterVertexCount, lightCenter, lightSize, lightVertexCount, shadowVertexBuffer); @@ -78,26 +78,23 @@ void ShadowTessellator::tessellateSpotShadow(const Vector3* casterPolygon, int c void ShadowTessellator::generateShadowIndices(uint16_t* shadowIndices) { int currentIndex = 0; - const int layers = SHADOW_LAYER_COUNT; const int rays = SHADOW_RAY_COUNT; // For the penumbra area. - for (int i = 0; i < layers; i++) { - for (int j = 0; j < rays; j++) { - shadowIndices[currentIndex++] = i * rays + j; - shadowIndices[currentIndex++] = (i + 1) * rays + j; - } - // To close the loop, back to the ray 0. - shadowIndices[currentIndex++] = i * rays; - shadowIndices[currentIndex++] = (i + 1) * rays; + for (int i = 0; i < rays; i++) { + shadowIndices[currentIndex++] = i; + shadowIndices[currentIndex++] = rays + i; } - uint16_t base = layers * rays; - uint16_t centroidIndex = (layers + 1) * rays; + // To close the loop, back to the ray 0. + shadowIndices[currentIndex++] = 0; + shadowIndices[currentIndex++] = rays; + + uint16_t centroidIndex = 2 * rays; // For the umbra area, using strips to simulate the fans. - for (int k = 0; k < rays; k++) { - shadowIndices[currentIndex++] = base + k; + for (int i = 0; i < rays; i++) { + shadowIndices[currentIndex++] = rays + i; shadowIndices[currentIndex++] = centroidIndex; } - shadowIndices[currentIndex++] = base; + shadowIndices[currentIndex++] = rays; #if DEBUG_SHADOW if (currentIndex != SHADOW_INDEX_COUNT) { diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h index c49fdcb..c558460 100644 --- a/libs/hwui/ShadowTessellator.h +++ b/libs/hwui/ShadowTessellator.h @@ -46,17 +46,15 @@ namespace uirenderer { // The total number of rays starting from the centroid of shadow area, in order // to generate the shadow geometry. -#define SHADOW_RAY_COUNT 256 - -// The total number of layers in the outer shadow area, 1 being the minimum. -#define SHADOW_LAYER_COUNT 2 +#define SHADOW_RAY_COUNT 128 // The total number of all the vertices representing the shadow. -#define SHADOW_VERTEX_COUNT ((SHADOW_LAYER_COUNT + 1) * SHADOW_RAY_COUNT + 1) +#define SHADOW_VERTEX_COUNT (2 * SHADOW_RAY_COUNT + 1) // The total number of indices used for drawing the shadow geometry as triangle strips. -#define SHADOW_INDEX_COUNT (2 * SHADOW_RAY_COUNT + 1 + 2 * (SHADOW_RAY_COUNT + 1) * \ - SHADOW_LAYER_COUNT) +#define SHADOW_INDEX_COUNT (2 * SHADOW_RAY_COUNT + 1 + 2 * (SHADOW_RAY_COUNT + 1)) + +#define SHADOW_MIN_CASTER_Z 0.001f class ShadowTessellator { public: diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 22d735b..8538b29 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -29,45 +29,46 @@ namespace android { namespace uirenderer { +static const double EPSILON = 1e-7; + /** - * Calculate the intersection of a ray with a polygon. - * It assumes the ray originates inside the polygon. + * Calculate the angle between and x and a y coordinate. + * The atan2 range from -PI to PI. + */ +static float angle(const Vector2& point, const Vector2& center) { + return atan2(point.y - center.y, point.x - center.x); +} + +/** + * Calculate the intersection of a ray with the line segment defined by two points. * - * @param poly The polygon, which is represented in a Vector2 array. - * @param polyLength The length of caster's polygon in terms of number of - * vertices. - * @param point the start of the ray - * @param dx the x vector of the ray - * @param dy the y vector of the ray - * @return the distance along the ray if it intersects with the polygon FP_NAN if otherwise + * Returns a negative value in error conditions. + + * @param rayOrigin The start of the ray + * @param dx The x vector of the ray + * @param dy The y vector of the ray + * @param p1 The first point defining the line segment + * @param p2 The second point defining the line segment + * @return The distance along the ray if it intersects with the line segment, negative if otherwise */ -float SpotShadow::rayIntersectPoly(const Vector2* poly, int polyLength, - const Vector2& point, float dx, float dy) { - double px = point.x; - double py = point.y; - int p1 = polyLength - 1; - for (int p2 = 0; p2 < polyLength; p2++) { - double p1x = poly[p1].x; - double p1y = poly[p1].y; - double p2x = poly[p2].x; - double p2y = poly[p2].y; - // The math below is derived from solving this formula, basically the - // intersection point should stay on both the ray and the edge of (p1, p2). - // solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]); - double div = (dx * (p1y - p2y) + dy * p2x - dy * p1x); - if (div != 0) { - double t = (dx * (p1y - py) + dy * px - dy * p1x) / (div); - if (t >= 0 && t <= 1) { - double t2 = (p1x * (py - p2y) + p2x * (p1y - py) + - px * (p2y - p1y)) / div; - if (t2 > 0) { - return (float)t2; - } - } - } - p1 = p2; - } - return FP_NAN; +static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, + const Vector2& p1, const Vector2& p2) { + // The math below is derived from solving this formula, basically the + // intersection point should stay on both the ray and the edge of (p1, p2). + // solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]); + + double divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x); + if (divisor == 0) return -1.0f; // error, invalid divisor + +#if DEBUG_SHADOW + double interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor; + if (interpVal < 0 || interpVal > 1) return -1.0f; // error, doesn't intersect between points +#endif + + double distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) + + rayOrigin.x * (p2.y - p1.y)) / divisor; + + return distance; // may be negative in error cases } /** @@ -131,30 +132,26 @@ int SpotShadow::hull(Vector2* points, int pointsLength, Vector2* retPoly) { lLowerSize--; } } - int count = 0; + // output points in CW ordering + const int total = lUpperSize + lLowerSize - 2; + int outIndex = total - 1; for (int i = 0; i < lUpperSize; i++) { - retPoly[count] = lUpper[i]; - count++; + retPoly[outIndex] = lUpper[i]; + outIndex--; } for (int i = 1; i < lLowerSize - 1; i++) { - retPoly[count] = lLower[i]; - count++; + retPoly[outIndex] = lLower[i]; + outIndex--; } // TODO: Add test harness which verify that all the points are inside the hull. - return count; + return total; } /** * Test whether the 3 points form a counter clockwise turn. * - * @param ax the x coordinate of point a - * @param ay the y coordinate of point a - * @param bx the x coordinate of point b - * @param by the y coordinate of point b - * @param cx the x coordinate of point c - * @param cy the y coordinate of point c * @return true if a right hand turn */ bool SpotShadow::ccw(double ax, double ay, double bx, double by, @@ -303,15 +300,6 @@ void SpotShadow::sort(Vector2* poly, int polyLength, const Vector2& center) { } /** - * Calculate the angle between and x and a y coordinate. - * The atan2 range from -PI to PI, if we want to sort the vertices as clockwise, - * we just negate the return angle. - */ -float SpotShadow::angle(const Vector2& point, const Vector2& center) { - return -(float)atan2(point.y - center.y, point.x - center.x); -} - -/** * Swap points pointed to by i and j */ void SpotShadow::swap(Vector2* points, int i, int j) { @@ -329,10 +317,10 @@ void SpotShadow::quicksortCirc(Vector2* points, int low, int high, int p = low + (high - low) / 2; float pivot = angle(points[p], center); while (i <= j) { - while (angle(points[i], center) < pivot) { + while (angle(points[i], center) > pivot) { i++; } - while (angle(points[j], center) > pivot) { + while (angle(points[j], center) < pivot) { j--; } @@ -508,8 +496,8 @@ void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter, // TODO: Caching all the sin / cos values and store them in a look up table. for (int i = 0; i < points; i++) { double angle = 2 * i * M_PI / points; - ret[i].x = sinf(angle) * size + lightCenter.x; - ret[i].y = cosf(angle) * size + lightCenter.y; + ret[i].x = cosf(angle) * size + lightCenter.x; + ret[i].y = sinf(angle) * size + lightCenter.y; ret[i].z = lightCenter.z; } } @@ -560,14 +548,9 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength // Validate input, receiver is always at z = 0 plane. bool inputPolyPositionValid = true; for (int i = 0; i < polyLength; i++) { - if (poly[i].z <= 0.00001) { - inputPolyPositionValid = false; - ALOGE("polygon below the surface"); - break; - } if (poly[i].z >= lightPoly[0].z) { inputPolyPositionValid = false; - ALOGE("polygon above the light"); + ALOGW("polygon above the light"); break; } } @@ -657,6 +640,63 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength } /** + * Converts a polygon specified with CW vertices into an array of distance-from-centroid values. + * + * Returns false in error conditions + * + * @param poly Array of vertices. Note that these *must* be CW. + * @param polyLength The number of vertices in the polygon. + * @param polyCentroid The centroid of the polygon, from which rays will be cast + * @param rayDist The output array for the calculated distances, must be SHADOW_RAY_COUNT in size + */ +bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& polyCentroid, + float* rayDist) { + const int rays = SHADOW_RAY_COUNT; + const float step = M_PI * 2 / rays; + + const Vector2* lastVertex = &(poly[polyLength - 1]); + float startAngle = angle(*lastVertex, polyCentroid); + + // Start with the ray that's closest to and less than startAngle + int rayIndex = floor((startAngle - EPSILON) / step); + rayIndex = (rayIndex + rays) % rays; // ensure positive + + for (int polyIndex = 0; polyIndex < polyLength; polyIndex++) { + /* + * For a given pair of vertices on the polygon, poly[i-1] and poly[i], the rays that + * intersect these will be those that are between the two angles from the centroid that the + * vertices define. + * + * Because the polygon vertices are stored clockwise, the closest ray with an angle + * *smaller* than that defined by angle(poly[i], centroid) will be the first ray that does + * not intersect with poly[i-1], poly[i]. + */ + float currentAngle = angle(poly[polyIndex], polyCentroid); + + // find first ray that will not intersect the line segment poly[i-1] & poly[i] + int firstRayIndexOnNextSegment = floor((currentAngle - EPSILON) / step); + firstRayIndexOnNextSegment = (firstRayIndexOnNextSegment + rays) % rays; // ensure positive + + // Iterate through all rays that intersect with poly[i-1], poly[i] line segment. + // This may be 0 rays. + while (rayIndex != firstRayIndexOnNextSegment) { + float distanceToIntersect = rayIntersectPoints(polyCentroid, + cos(rayIndex * step), + sin(rayIndex * step), + *lastVertex, poly[polyIndex]); + if (distanceToIntersect < 0) return false; // error case, abort + + rayDist[rayIndex] = distanceToIntersect; + + rayIndex = (rayIndex - 1 + rays) % rays; + } + lastVertex = &poly[polyIndex]; + } + + return true; +} + +/** * Generate a triangle strip given two convex polygons * * @param penumbra The outer polygon x,y vertexes @@ -669,10 +709,9 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLength, const Vector2* umbra, int umbraLength, VertexBuffer& shadowTriangleStrip) { const int rays = SHADOW_RAY_COUNT; - const int layers = SHADOW_LAYER_COUNT; - int size = rays * (layers + 1); - float step = M_PI * 2 / rays; + const int size = 2 * rays; + const float step = M_PI * 2 / rays; // Centroid of the umbra. Vector2 centroid = ShadowTessellator::centroid2d(umbra, umbraLength); #if DEBUG_SHADOW @@ -683,48 +722,31 @@ void SpotShadow::generateTriangleStrip(const Vector2* penumbra, int penumbraLeng // Intersection to the umbra. float umbraDistPerRay[rays]; - for (int i = 0; i < rays; i++) { - // TODO: Setup a lookup table for all the sin/cos. - float dx = sinf(step * i); - float dy = cosf(step * i); - umbraDistPerRay[i] = rayIntersectPoly(umbra, umbraLength, centroid, - dx, dy); - if (isnan(umbraDistPerRay[i])) { - ALOGE("rayIntersectPoly returns NAN"); - return; - } - penumbraDistPerRay[i] = rayIntersectPoly(penumbra, penumbraLength, - centroid, dx, dy); - if (isnan(umbraDistPerRay[i])) { - ALOGE("rayIntersectPoly returns NAN"); - return; - } - } + // convert CW polygons to ray distance encoding, aborting on conversion failure + if (!convertPolyToRayDist(umbra, umbraLength, centroid, umbraDistPerRay)) return; + if (!convertPolyToRayDist(penumbra, penumbraLength, centroid, penumbraDistPerRay)) return; - int stripSize = getStripSize(rays, layers); - AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(stripSize); - int currentIndex = 0; + AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(getStripSize(rays)); // Calculate the vertices (x, y, alpha) in the shadow area. - for (int layerIndex = 0; layerIndex <= layers; layerIndex++) { - for (int rayIndex = 0; rayIndex < rays; rayIndex++) { - float dx = sinf(step * rayIndex); - float dy = cosf(step * rayIndex); - float layerRatio = layerIndex / (float) layers; - float deltaDist = layerRatio * - (umbraDistPerRay[rayIndex] - penumbraDistPerRay[rayIndex]); - float currentDist = penumbraDistPerRay[rayIndex] + deltaDist; - float op = calculateOpacity(layerRatio); - AlphaVertex::set(&shadowVertices[currentIndex++], - dx * currentDist + centroid.x, dy * currentDist + centroid.y, op); - } + for (int rayIndex = 0; rayIndex < rays; rayIndex++) { + float dx = cosf(step * rayIndex); + float dy = sinf(step * rayIndex); + + // outer ring + float currentDist = penumbraDistPerRay[rayIndex]; + AlphaVertex::set(&shadowVertices[rayIndex], + dx * currentDist + centroid.x, dy * currentDist + centroid.y, 0.0f); + + // inner ring + float deltaDist = umbraDistPerRay[rayIndex] - penumbraDistPerRay[rayIndex]; + currentDist += deltaDist; + AlphaVertex::set(&shadowVertices[rays + rayIndex], + dx * currentDist + centroid.x, dy * currentDist + centroid.y, 1.0f); } // The centroid is in the umbra area, so the opacity is considered as 1.0. - AlphaVertex::set(&shadowVertices[currentIndex++], centroid.x, centroid.y, 1.0); + AlphaVertex::set(&shadowVertices[SHADOW_VERTEX_COUNT - 1], centroid.x, centroid.y, 1.0f); #if DEBUG_SHADOW - if (currentIndex != SHADOW_VERTEX_COUNT) { - ALOGE("number of vertex generated for spot shadow is wrong!"); - } for (int i = 0; i < currentIndex; i++) { ALOGD("spot shadow value: i %d, (x:%f, y:%f, a:%f)", i, shadowVertices[i].x, shadowVertices[i].y, shadowVertices[i].alpha); @@ -754,26 +776,14 @@ void SpotShadow::smoothPolygon(int level, int rays, float* rayDist) { } /** - * Calculate the opacity according to the distance. Ideally, the opacity is 1.0 - * in the umbra area, and fall off to 0.0 till the edge of penumbra area. - * - * @param layerRatio The distance ratio of current sample between umbra and penumbra area. - * Penumbra edge is 0 and umbra edge is 1. - * @return The opacity according to the distance between umbra and penumbra. - */ -float SpotShadow::calculateOpacity(float layerRatio) { - return (layerRatio * layerRatio + layerRatio) / 2.0; -} - -/** * Calculate the number of vertex we will create given a number of rays and layers * * @param rays number of points around the polygons you want * @param layers number of layers of triangle strips you need * @return number of vertex (multiply by 3 for number of floats) */ -int SpotShadow::getStripSize(int rays, int layers) { - return (2 + rays + ((layers) * 2 * (rays + 1))); +int SpotShadow::getStripSize(int rays) { + return (2 + rays + (2 * (rays + 1))); } #if DEBUG_SHADOW @@ -898,7 +908,3 @@ void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length, }; // namespace uirenderer }; // namespace android - - - - diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h index 6727eac..7839dc3 100644 --- a/libs/hwui/SpotShadow.h +++ b/libs/hwui/SpotShadow.h @@ -38,9 +38,8 @@ private: static void computeLightPolygon(int points, const Vector3& lightCenter, float size, Vector3* ret); - static int getStripSize(int rays, int layers); + static int getStripSize(int rays); static void smoothPolygon(int level, int rays, float* rayDist); - static float calculateOpacity(float jf); static float rayIntersectPoly(const Vector2* poly, int polyLength, const Vector2& point, float dx, float dy); @@ -50,7 +49,6 @@ private: static int intersection(Vector2* poly1, int poly1length, Vector2* poly2, int poly2length); static void sort(Vector2* poly, int polyLength, const Vector2& center); - static float angle(const Vector2& point, const Vector2& center); static void swap(Vector2* points, int i, int j); static void quicksortCirc(Vector2* points, int low, int high, const Vector2& center); static void quicksortX(Vector2* points, int low, int high); @@ -65,8 +63,6 @@ private: static void generateTriangleStrip(const Vector2* penumbra, int penumbraLength, const Vector2* umbra, int umbraLength, VertexBuffer& retstrips); - static const double EPSILON = 1e-7; - #if DEBUG_SHADOW // Verification utility function. static bool testConvex(const Vector2* polygon, int polygonLength, diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h index 15b9d6b..c61cb61 100644 --- a/libs/hwui/Vector.h +++ b/libs/hwui/Vector.h @@ -124,6 +124,10 @@ public: Vector3(float px, float py, float pz) : x(px), y(py), z(pz) { } + + void dump() { + ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z); + } }; /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index ce66d8f..5ed9f1d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -373,7 +373,7 @@ void CanvasContext::setup(int width, int height) { mCanvas->setViewport(width, height); } -void CanvasContext::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { +void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { displayList->setData(newData); } @@ -388,7 +388,7 @@ void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* lay } } -void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) { +void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 649ffb6..e3fdf97 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -31,7 +31,7 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; +class RenderNode; class DisplayListData; class OpenGLRenderer; class Rect; @@ -63,9 +63,9 @@ public: bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); void setup(int width, int height); - void setDisplayListData(DisplayList* displayList, DisplayListData* newData); + void setDisplayListData(RenderNode* displayList, DisplayListData* newData); void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters); - void drawDisplayList(DisplayList* displayList, Rect* dirty); + void drawDisplayList(RenderNode* displayList, Rect* dirty); void destroyCanvas(); bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 200c21f..93360fc 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -117,13 +117,13 @@ void RenderProxy::setup(int width, int height) { post(task); } -CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, DisplayList* displayList, +CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, RenderNode* displayList, DisplayListData* newData) { args->context->setDisplayListData(args->displayList, args->newData); return NULL; } -void RenderProxy::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { +void RenderProxy::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { SETUP_TASK(setDisplayListData); args->context = mContext; args->displayList = displayList; @@ -131,7 +131,7 @@ void RenderProxy::setDisplayListData(DisplayList* displayList, DisplayListData* post(task); } -CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList, +CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, RenderNode* displayList, Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) { Rect* dirty = &args->dirty; if (dirty->bottom == -1 && dirty->left == -1 && @@ -143,7 +143,7 @@ CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList return NULL; } -void RenderProxy::drawDisplayList(DisplayList* displayList, +void RenderProxy::drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { SETUP_TASK(drawDisplayList); args->context = mContext; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 83a8a8f..73e9805 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -32,7 +32,7 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; +class RenderNode; class DisplayListData; class Layer; class Rect; @@ -60,8 +60,8 @@ public: ANDROID_API bool initialize(EGLNativeWindowType window); ANDROID_API void updateSurface(EGLNativeWindowType window); ANDROID_API void setup(int width, int height); - ANDROID_API void setDisplayListData(DisplayList* displayList, DisplayListData* newData); - ANDROID_API void drawDisplayList(DisplayList* displayList, + ANDROID_API void setDisplayListData(RenderNode* displayList, DisplayListData* newData); + ANDROID_API void drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvas(); diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index cc464db..2ddbb7d 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -16,15 +16,19 @@ package android.mtp; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.ContentValues; import android.content.IContentProvider; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.MediaScanner; import android.net.Uri; +import android.os.BatteryManager; +import android.os.BatteryStats; import android.os.RemoteException; import android.provider.MediaStore; import android.provider.MediaStore.Audio; @@ -113,11 +117,35 @@ public class MtpDatabase { + Files.FileColumns.PARENT + "=?"; private final MediaScanner mMediaScanner; + private MtpServer mServer; + + // read from native code + private int mBatteryLevel; + private int mBatteryScale; static { System.loadLibrary("media_jni"); } + private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + mBatteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); + int newLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + if (newLevel != mBatteryLevel) { + mBatteryLevel = newLevel; + if (mServer != null) { + // send device property changed event + mServer.sendDevicePropertyChanged( + MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL); + } + } + } + } + }; + public MtpDatabase(Context context, String volumeName, String storagePath, String[] subDirectories) { native_setup(); @@ -171,6 +199,18 @@ public class MtpDatabase { initDeviceProperties(context); } + public void setServer(MtpServer server) { + mServer = server; + + // register for battery notifications when we are connected + if (server != null) { + mContext.registerReceiver(mBatteryReceiver, + new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } else { + mContext.unregisterReceiver(mBatteryReceiver); + } + } + @Override protected void finalize() throws Throwable { try { @@ -663,6 +703,7 @@ public class MtpDatabase { MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE, + MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL, }; } @@ -819,6 +860,8 @@ public class MtpDatabase { outStringValue[imageSize.length()] = 0; return MtpConstants.RESPONSE_OK; + // DEVICE_PROPERTY_BATTERY_LEVEL is implemented in the JNI code + default: return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; } diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java index 266f78e..3814630 100644 --- a/media/java/android/mtp/MtpServer.java +++ b/media/java/android/mtp/MtpServer.java @@ -30,6 +30,7 @@ public class MtpServer implements Runnable { public MtpServer(MtpDatabase database, boolean usePtp) { native_setup(database, usePtp); + database.setServer(this); } public void start() { @@ -51,6 +52,10 @@ public class MtpServer implements Runnable { native_send_object_removed(handle); } + public void sendDevicePropertyChanged(int property) { + native_send_device_property_changed(property); + } + public void addStorage(MtpStorage storage) { native_add_storage(storage); } @@ -64,6 +69,7 @@ public class MtpServer implements Runnable { private native final void native_cleanup(); private native final void native_send_object_added(int handle); private native final void native_send_object_removed(int handle); + private native final void native_send_device_property_changed(int property); private native final void native_add_storage(MtpStorage storage); private native final void native_remove_storage(int storageId); } diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 6b0bd0d..ea75a18 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -68,6 +68,8 @@ static jmethodID method_sessionStarted; static jmethodID method_sessionEnded; static jfieldID field_context; +static jfieldID field_batteryLevel; +static jfieldID field_batteryScale; // MtpPropertyList fields static jfieldID field_mCount; @@ -527,68 +529,75 @@ MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle, MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) { - int type; + JNIEnv* env = AndroidRuntime::getJNIEnv(); - if (!getDevicePropertyInfo(property, type)) - return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) { + // special case - implemented here instead of Java + packet.putUInt8((uint8_t)env->GetIntField(mDatabase, field_batteryLevel)); + return MTP_RESPONSE_OK; + } else { + int type; + + if (!getDevicePropertyInfo(property, type)) + return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + + jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, + (jint)property, mLongBuffer, mStringBuffer); + if (result != MTP_RESPONSE_OK) { + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return result; + } - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, - (jint)property, mLongBuffer, mStringBuffer); - if (result != MTP_RESPONSE_OK) { - checkAndClearExceptionFromCallback(env, __FUNCTION__); - return result; - } + jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); + jlong longValue = longValues[0]; + env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); - jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); - jlong longValue = longValues[0]; - env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); + switch (type) { + case MTP_TYPE_INT8: + packet.putInt8(longValue); + break; + case MTP_TYPE_UINT8: + packet.putUInt8(longValue); + break; + case MTP_TYPE_INT16: + packet.putInt16(longValue); + break; + case MTP_TYPE_UINT16: + packet.putUInt16(longValue); + break; + case MTP_TYPE_INT32: + packet.putInt32(longValue); + break; + case MTP_TYPE_UINT32: + packet.putUInt32(longValue); + break; + case MTP_TYPE_INT64: + packet.putInt64(longValue); + break; + case MTP_TYPE_UINT64: + packet.putUInt64(longValue); + break; + case MTP_TYPE_INT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_UINT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_STR: + { + jchar* str = env->GetCharArrayElements(mStringBuffer, 0); + packet.putString(str); + env->ReleaseCharArrayElements(mStringBuffer, str, 0); + break; + } + default: + ALOGE("unsupported type in getDevicePropertyValue\n"); + return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; + } - switch (type) { - case MTP_TYPE_INT8: - packet.putInt8(longValue); - break; - case MTP_TYPE_UINT8: - packet.putUInt8(longValue); - break; - case MTP_TYPE_INT16: - packet.putInt16(longValue); - break; - case MTP_TYPE_UINT16: - packet.putUInt16(longValue); - break; - case MTP_TYPE_INT32: - packet.putInt32(longValue); - break; - case MTP_TYPE_UINT32: - packet.putUInt32(longValue); - break; - case MTP_TYPE_INT64: - packet.putInt64(longValue); - break; - case MTP_TYPE_UINT64: - packet.putUInt64(longValue); - break; - case MTP_TYPE_INT128: - packet.putInt128(longValue); - break; - case MTP_TYPE_UINT128: - packet.putInt128(longValue); - break; - case MTP_TYPE_STR: - { - jchar* str = env->GetCharArrayElements(mStringBuffer, 0); - packet.putString(str); - env->ReleaseCharArrayElements(mStringBuffer, str, 0); - break; - } - default: - ALOGE("unsupported type in getDevicePropertyValue\n"); - return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return MTP_RESPONSE_OK; } - - checkAndClearExceptionFromCallback(env, __FUNCTION__); - return MTP_RESPONSE_OK; } MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property, @@ -923,6 +932,7 @@ static const PropertyTableEntry kDevicePropertyTable[] = { { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR }, { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR }, { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR }, + { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 }, }; bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) { @@ -1046,7 +1056,7 @@ MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: writable = true; // fall through - case MTP_DEVICE_PROPERTY_IMAGE_SIZE: + case MTP_DEVICE_PROPERTY_IMAGE_SIZE: { result = new MtpProperty(property, MTP_TYPE_STR, writable); // get current value @@ -1063,6 +1073,12 @@ MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { ALOGE("unable to read device property, response: %04X", ret); } break; + } + case MTP_DEVICE_PROPERTY_BATTERY_LEVEL: + result = new MtpProperty(property, MTP_TYPE_UINT8); + result->setFormRange(0, env->GetIntField(mDatabase, field_batteryScale), 1); + result->mCurrentValue.u.u8 = (uint8_t)env->GetIntField(mDatabase, field_batteryLevel); + break; } checkAndClearExceptionFromCallback(env, __FUNCTION__); @@ -1234,6 +1250,16 @@ int register_android_mtp_MtpDatabase(JNIEnv *env) ALOGE("Can't find MtpDatabase.mNativeContext"); return -1; } + field_batteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I"); + if (field_batteryLevel == NULL) { + ALOGE("Can't find MtpDatabase.mBatteryLevel"); + return -1; + } + field_batteryScale = env->GetFieldID(clazz, "mBatteryScale", "I"); + if (field_batteryScale == NULL) { + ALOGE("Can't find MtpDatabase.mBatteryScale"); + return -1; + } // now set up fields for MtpPropertyList class clazz = env->FindClass("android/mtp/MtpPropertyList"); diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp index 9d7f1c2..2f90dfe 100644 --- a/media/jni/android_mtp_MtpServer.cpp +++ b/media/jni/android_mtp_MtpServer.cpp @@ -118,6 +118,18 @@ android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle } static void +android_mtp_MtpServer_send_device_property_changed(JNIEnv *env, jobject thiz, jint property) +{ + Mutex::Autolock autoLock(sMutex); + + MtpServer* server = getMtpServer(env, thiz); + if (server) + server->sendDevicePropertyChanged(property); + else + ALOGE("server is null in send_object_removed"); +} + +static void android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage) { Mutex::Autolock autoLock(sMutex); @@ -174,6 +186,8 @@ static JNINativeMethod gMethods[] = { {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup}, {"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added}, {"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed}, + {"native_send_device_property_changed", "(I)V", + (void *)android_mtp_MtpServer_send_device_property_changed}, {"native_add_storage", "(Landroid/mtp/MtpStorage;)V", (void *)android_mtp_MtpServer_add_storage}, {"native_remove_storage", "(I)V", (void *)android_mtp_MtpServer_remove_storage}, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index eb07d88..a89921f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -931,6 +931,7 @@ public abstract class BaseStatusBar extends SystemUI implements } if (contentViewLocal != null) { + contentViewLocal.setIsRootNamespace(true); SizeAdaptiveLayout.LayoutParams params = new SizeAdaptiveLayout.LayoutParams(contentViewLocal.getLayoutParams()); params.minHeight = minHeight; @@ -938,6 +939,7 @@ public abstract class BaseStatusBar extends SystemUI implements expanded.addView(contentViewLocal, params); } if (bigContentViewLocal != null) { + bigContentViewLocal.setIsRootNamespace(true); SizeAdaptiveLayout.LayoutParams params = new SizeAdaptiveLayout.LayoutParams(bigContentViewLocal.getLayoutParams()); params.minHeight = minHeight+1; @@ -955,6 +957,7 @@ public abstract class BaseStatusBar extends SystemUI implements expandedPublic, mOnClickHandler); if (publicViewLocal != null) { + publicViewLocal.setIsRootNamespace(true); SizeAdaptiveLayout.LayoutParams params = new SizeAdaptiveLayout.LayoutParams(publicViewLocal.getLayoutParams()); params.minHeight = minHeight; diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index bda0183..9de3efe 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -426,8 +426,10 @@ class AlarmManagerService extends SystemService { final Pair<String, ComponentName> mTarget; final BroadcastStats mBroadcastStats; final FilterStats mFilterStats; + final int mAlarmType; - InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource) { + InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource, + int alarmType) { mPendingIntent = pendingIntent; mWorkSource = workSource; Intent intent = pendingIntent.getIntent(); @@ -441,6 +443,7 @@ class AlarmManagerService extends SystemService { mBroadcastStats.filterStats.put(mTarget, fs); } mFilterStats = fs; + mAlarmType = alarmType; } } @@ -1280,17 +1283,12 @@ class AlarmManagerService extends SystemService { // we have an active broadcast so stay awake. if (mBroadcastRefCount == 0) { - setWakelockWorkSource(alarm.operation, alarm.workSource); - mWakeLock.setUnimportantForLogging( - alarm.operation == mTimeTickSender); - mWakeLock.setHistoryTag(alarm.operation.getTag( - alarm.type == ELAPSED_REALTIME_WAKEUP - || alarm.type == RTC_WAKEUP - ? "*walarm*:" : "*alarm*:")); + setWakelockWorkSource(alarm.operation, alarm.workSource, + alarm.type, true); mWakeLock.acquire(); } final InFlight inflight = new InFlight(AlarmManagerService.this, - alarm.operation, alarm.workSource); + alarm.operation, alarm.workSource, alarm.type); mInFlight.add(inflight); mBroadcastRefCount++; @@ -1345,9 +1343,17 @@ class AlarmManagerService extends SystemService { * @param pi PendingIntent to attribute blame to if ws is null. * @param ws WorkSource to attribute blame. */ - void setWakelockWorkSource(PendingIntent pi, WorkSource ws) { + void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, boolean first) { try { + mWakeLock.setUnimportantForLogging(pi == mTimeTickSender); if (ws != null) { + if (first) { + mWakeLock.setHistoryTag(pi.getTag( + type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP + ? "*walarm*:" : "*alarm*:")); + } else { + mWakeLock.setHistoryTag(null); + } mWakeLock.setWorkSource(ws); return; } @@ -1355,6 +1361,7 @@ class AlarmManagerService extends SystemService { final int uid = ActivityManagerNative.getDefault() .getUidForIntentSender(pi.getTarget()); if (uid >= 0) { + mWakeLock.setHistoryTag(null); mWakeLock.setWorkSource(new WorkSource(uid)); return; } @@ -1579,7 +1586,8 @@ class AlarmManagerService extends SystemService { // the next of our alarms is now in flight. reattribute the wakelock. if (mInFlight.size() > 0) { InFlight inFlight = mInFlight.get(0); - setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource); + setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource, + inFlight.mAlarmType, false); } else { // should never happen mLog.w("Alarm wakelock still held but sent queue empty"); diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 39bfc23..3414daf 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -29,6 +29,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Process; import android.os.ServiceManager; +import android.os.SystemClock; import android.os.UserHandle; import android.os.WorkSource; import android.telephony.SignalStrength; @@ -133,14 +134,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub { boolean unimportantForLogging) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging); + mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging, + SystemClock.elapsedRealtime()); } } public void noteStopWakelock(int uid, int pid, String name, int type) { enforceCallingPermission(); synchronized (mStats) { - mStats.noteStopWakeLocked(uid, pid, name, type); + mStats.noteStopWakeLocked(uid, pid, name, type, SystemClock.elapsedRealtime()); } } @@ -153,6 +155,16 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } + public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, int type, + WorkSource newWs, int newPid, String newName, + String newHistoryName, int newType, boolean newUnimportantForLogging) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, type, + newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging); + } + } + public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) { enforceCallingPermission(); synchronized (mStats) { diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java index 12d51aa..6d3702a 100644 --- a/services/core/java/com/android/server/power/DisplayPowerController.java +++ b/services/core/java/com/android/server/power/DisplayPowerController.java @@ -479,7 +479,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && mProximity == PROXIMITY_POSITIVE) { mScreenOffBecauseOfProximity = true; sendOnProximityPositiveWithWakelock(); - setScreenOn(false); } } else if (mWaitingForNegativeProximity && mScreenOffBecauseOfProximity @@ -544,59 +543,62 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUsingScreenAutoBrightness = false; } - // Animate the screen on or off. - if (!mScreenOffBecauseOfProximity) { - if (mPowerRequest.wantScreenOnAny()) { - // Want screen on. - // Wait for previous off animation to complete beforehand. - // It is relatively short but if we cancel it and switch to the - // on animation immediately then the results are pretty ugly. - if (!mElectronBeamOffAnimator.isStarted()) { - // Turn the screen on. The contents of the screen may not yet - // be visible if the electron beam has not been dismissed because - // its last frame of animation is solid black. - setScreenOn(true); - - if (mPowerRequest.blockScreenOn - && mPowerState.getElectronBeamLevel() == 0.0f) { - blockScreenOn(); - } else { - unblockScreenOn(); - if (USE_ELECTRON_BEAM_ON_ANIMATION) { - if (!mElectronBeamOnAnimator.isStarted()) { - if (mPowerState.getElectronBeamLevel() == 1.0f) { - mPowerState.dismissElectronBeam(); - } else if (mPowerState.prepareElectronBeam( - mElectronBeamFadesConfig ? - ElectronBeam.MODE_FADE : - ElectronBeam.MODE_WARM_UP)) { - mElectronBeamOnAnimator.start(); - } else { - mElectronBeamOnAnimator.end(); - } + // Animate the screen on or off unless blocked. + if (mScreenOffBecauseOfProximity) { + // Screen off due to proximity. + setScreenOn(false); + unblockScreenOn(); + } else if (mPowerRequest.wantScreenOnAny()) { + // Want screen on. + // Wait for previous off animation to complete beforehand. + // It is relatively short but if we cancel it and switch to the + // on animation immediately then the results are pretty ugly. + if (!mElectronBeamOffAnimator.isStarted()) { + // Turn the screen on. The contents of the screen may not yet + // be visible if the electron beam has not been dismissed because + // its last frame of animation is solid black. + setScreenOn(true); + + if (mPowerRequest.blockScreenOn + && mPowerState.getElectronBeamLevel() == 0.0f) { + blockScreenOn(); + } else { + unblockScreenOn(); + if (USE_ELECTRON_BEAM_ON_ANIMATION) { + if (!mElectronBeamOnAnimator.isStarted()) { + if (mPowerState.getElectronBeamLevel() == 1.0f) { + mPowerState.dismissElectronBeam(); + } else if (mPowerState.prepareElectronBeam( + mElectronBeamFadesConfig ? + ElectronBeam.MODE_FADE : + ElectronBeam.MODE_WARM_UP)) { + mElectronBeamOnAnimator.start(); + } else { + mElectronBeamOnAnimator.end(); } - } else { - mPowerState.setElectronBeamLevel(1.0f); - mPowerState.dismissElectronBeam(); } + } else { + mPowerState.setElectronBeamLevel(1.0f); + mPowerState.dismissElectronBeam(); } } - } else { - // Want screen off. - // Wait for previous on animation to complete beforehand. - if (!mElectronBeamOnAnimator.isStarted()) { - if (!mElectronBeamOffAnimator.isStarted()) { - if (mPowerState.getElectronBeamLevel() == 0.0f) { - setScreenOn(false); - } else if (mPowerState.prepareElectronBeam( - mElectronBeamFadesConfig ? - ElectronBeam.MODE_FADE : - ElectronBeam.MODE_COOL_DOWN) - && mPowerState.isScreenOn()) { - mElectronBeamOffAnimator.start(); - } else { - mElectronBeamOffAnimator.end(); - } + } + } else { + // Want screen off. + // Wait for previous on animation to complete beforehand. + unblockScreenOn(); + if (!mElectronBeamOnAnimator.isStarted()) { + if (!mElectronBeamOffAnimator.isStarted()) { + if (mPowerState.getElectronBeamLevel() == 0.0f) { + setScreenOn(false); + } else if (mPowerState.prepareElectronBeam( + mElectronBeamFadesConfig ? + ElectronBeam.MODE_FADE : + ElectronBeam.MODE_COOL_DOWN) + && mPowerState.isScreenOn()) { + mElectronBeamOffAnimator.start(); + } else { + mElectronBeamOffAnimator.end(); } } } @@ -641,15 +643,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void unblockScreenOn() { if (mScreenOnWasBlocked) { mScreenOnWasBlocked = false; - if (DEBUG) { - Slog.d(TAG, "Unblocked screen on after " + - (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms"); + long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime; + if (delay > 1000 || DEBUG) { + Slog.d(TAG, "Unblocked screen on after " + delay + " ms"); } } } private void setScreenOn(boolean on) { - if (!mPowerState.isScreenOn() == on) { + if (mPowerState.isScreenOn() != on) { mPowerState.setScreenOn(on); if (on) { mNotifier.onScreenOn(); diff --git a/services/core/java/com/android/server/power/DisplayPowerState.java b/services/core/java/com/android/server/power/DisplayPowerState.java index 42af4b4..8e331ad 100644 --- a/services/core/java/com/android/server/power/DisplayPowerState.java +++ b/services/core/java/com/android/server/power/DisplayPowerState.java @@ -304,8 +304,15 @@ final class DisplayPowerState { int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0; if (mPhotonicModulator.setState(mScreenOn, brightness)) { + if (DEBUG) { + Slog.d(TAG, "Screen ready"); + } mScreenReady = true; invokeCleanListenerIfNeeded(); + } else { + if (DEBUG) { + Slog.d(TAG, "Screen not ready"); + } } } }; @@ -355,7 +362,7 @@ final class DisplayPowerState { AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask); } } - return mChangeInProgress; + return !mChangeInProgress; } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index e1ccf46..df06bae 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -158,6 +158,39 @@ final class Notifier { } /** + * Called when a wake lock is changing. + */ + public void onWakeLockChanging(int flags, String tag, String packageName, + int ownerUid, int ownerPid, WorkSource workSource, String historyTag, + int newFlags, String newTag, String newPackageName, int newOwnerUid, + int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { + + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); + boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 + && ownerUid == Process.SYSTEM_UID; + if (workSource != null && newWorkSource != null) { + if (DEBUG) { + Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag + + "\", packageName=" + newPackageName + + ", ownerUid=" + newOwnerUid + ", ownerPid=" + newOwnerPid + + ", workSource=" + newWorkSource); + } + try { + mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, monitorType, + newWorkSource, newOwnerPid, newTag, newHistoryTag, + newMonitorType, unimportantForLogging); + } catch (RemoteException ex) { + // Ignore + } + } else { + onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource); + onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid, + newWorkSource, newHistoryTag); + } + } + + /** * Called when a wake lock is released. */ public void onWakeLockReleased(int flags, String tag, String packageName, diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e7bbf1c..e0a46b9 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -646,9 +646,9 @@ public final class PowerManagerService extends com.android.server.SystemService wakeLock = mWakeLocks.get(index); if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) { // Update existing wake lock. This shouldn't happen but is harmless. - notifyWakeLockReleasedLocked(wakeLock); + notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName, + uid, pid, ws, historyTag); wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid); - notifyWakeLockAcquiredLocked(wakeLock); } } else { wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid); @@ -765,9 +765,10 @@ public final class PowerManagerService extends com.android.server.SystemService } if (!wakeLock.hasSameWorkSource(ws)) { - notifyWakeLockReleasedLocked(wakeLock); + notifyWakeLockChangingLocked(wakeLock, wakeLock.mFlags, wakeLock.mTag, + wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, + ws, wakeLock.mHistoryTag); wakeLock.updateWorkSource(ws); - notifyWakeLockAcquiredLocked(wakeLock); } } } @@ -791,6 +792,15 @@ public final class PowerManagerService extends com.android.server.SystemService } } + private void notifyWakeLockChangingLocked(WakeLock wakeLock, int flags, String tag, + String packageName, int uid, int pid, WorkSource ws, String historyTag) { + if (mSystemReady && wakeLock.mNotifiedAcquired) { + mNotifier.onWakeLockChanging(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, + wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, + wakeLock.mHistoryTag, flags, tag, packageName, uid, pid, ws, historyTag); + } + } + private void notifyWakeLockReleasedLocked(WakeLock wakeLock) { if (mSystemReady && wakeLock.mNotifiedAcquired) { wakeLock.mNotifiedAcquired = false; @@ -1037,6 +1047,9 @@ public final class PowerManagerService extends com.android.server.SystemService if (!mSystemReady || mDirty == 0) { return; } + if (!Thread.holdsLock(mLock)) { + Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked"); + } // Phase 0: Basic state updates. updateIsPoweredLocked(mDirty); |