diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/Presentation.java | 10 | ||||
| -rw-r--r-- | core/java/android/content/Context.java | 20 | ||||
| -rw-r--r-- | core/java/android/os/Environment.java | 23 | ||||
| -rw-r--r-- | core/java/android/os/Trace.java | 56 | ||||
| -rw-r--r-- | core/java/android/text/TextLine.java | 33 | ||||
| -rw-r--r-- | core/java/android/view/Surface.java | 8 | ||||
| -rw-r--r-- | core/java/android/view/ViewManager.java | 10 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 44 | ||||
| -rw-r--r-- | core/java/android/view/WindowManager.java | 13 | ||||
| -rw-r--r-- | core/java/android/view/WindowManagerGlobal.java | 37 | ||||
| -rw-r--r-- | core/java/android/webkit/AccessibilityInjector.java | 2 |
11 files changed, 190 insertions, 66 deletions
diff --git a/core/java/android/app/Presentation.java b/core/java/android/app/Presentation.java index b5e5244..20b27c5 100644 --- a/core/java/android/app/Presentation.java +++ b/core/java/android/app/Presentation.java @@ -141,6 +141,16 @@ public class Presentation extends Dialog { } /** + * Inherited from {@link Dialog#show}. Will throw + * {@link android.view.WindowManager.InvalidDisplayException} if the specified secondary + * {@link Display} can't be found. + */ + @Override + public void show() { + super.show(); + } + + /** * Called by the system when the {@link Display} to which the presentation * is attached has been removed. * diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 201b43f..7aa2507 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -33,6 +33,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; +import android.os.UserManager; import android.util.AttributeSet; import android.view.CompatibilityInfoHolder; import android.view.Display; @@ -587,6 +588,10 @@ public abstract class Context { * can read and write files placed here. * </ul> * + * <p>On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated external storage. Applications only + * have access to the external storage for the user they're running as.</p> + * * <p>Here is an example of typical code to manipulate a file in * an application's private storage:</p> * @@ -616,6 +621,9 @@ public abstract class Context { * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * private_picture} * + * <p>Writing to this path requires the + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p> + * * @param type The type of files directory to return. May be null for * the root of the files directory or one of * the following Environment constants for a subdirectory: @@ -641,6 +649,11 @@ public abstract class Context { * Return the directory where this application's OBB files (if there * are any) can be found. Note if the application does not have any OBB * files, this directory may not exist. + * + * <p>On devices with multiple users (as described by {@link UserManager}), + * multiple users may share the same OBB storage location. Applications + * should ensure that multiple instances running under different users + * don't interfere with each other.</p> */ public abstract File getObbDir(); @@ -689,6 +702,13 @@ public abstract class Context { * can read and write files placed here. * </ul> * + * <p>On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated external storage. Applications only + * have access to the external storage for the user they're running as.</p> + * + * <p>Writing to this path requires the + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.</p> + * * @return Returns the path of the directory holding application cache files * on external storage. Returns null if external storage is not currently * mounted so it could not ensure the path exists; you will need to call diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 3315566..88529f8 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -274,6 +274,10 @@ public class Environment { * built-in storage in a device that is distinct from the protected * internal storage and can be mounted as a filesystem on a computer.</em></p> * + * <p>On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated external storage. Applications only + * have access to the external storage for the user they're running as.</p> + * * <p>In devices with multiple "external" storage directories (such as * both secure app storage and mountable shared storage), this directory * represents the "primary" external storage that the user will interact @@ -286,7 +290,16 @@ public class Environment { * Context.getExternalFilesDir}, which the system will take care of deleting * if the application is uninstalled. Other shared files should be placed * in one of the directories returned by - * {@link #getExternalStoragePublicDirectory}. + * {@link #getExternalStoragePublicDirectory}.</p> + * + * <p>Writing to this path requires the + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission. In + * a future platform release, access to this path will require the + * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission, + * which is automatically granted if you hold the write permission.</p> + * + * <p>This path may change between platform versions, so applications + * should only persist relative paths.</p> * * <p>Here is an example of typical code to monitor the state of * external storage:</p> @@ -423,6 +436,10 @@ public class Environment { * to ensure you don't erase their files or get in the way of their own * organization. * + * <p>On devices with multiple users (as described by {@link UserManager}), + * each user has their own isolated external storage. Applications only + * have access to the external storage for the user they're running as.</p> + * * <p>Here is an example of typical code to manipulate a picture on * the public external storage:</p> * @@ -500,7 +517,7 @@ public class Environment { } /** - * Gets the Android Download/Cache content directory. + * Gets the Android download/cache content directory. */ public static File getDownloadCacheDirectory() { return DOWNLOAD_CACHE_DIRECTORY; @@ -563,7 +580,7 @@ public class Environment { /** * Gets the current state of the primary "external" storage device. * - * <p>See {@link #getExternalStorageDirectory()} for more information. + * @see #getExternalStorageDirectory() */ public static String getExternalStorageState() { try { diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 59d0f7a..ed51818 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -16,6 +16,8 @@ package android.os; +import android.util.Log; + /** * Writes trace events to the kernel trace buffer. These trace events can be * collected using the "atrace" program for offline analysis. @@ -27,6 +29,8 @@ package android.os; * @hide */ public final class Trace { + private static final String TAG = "Trace"; + // These tags must be kept in sync with frameworks/native/include/utils/Trace.h. public static final long TRACE_TAG_NEVER = 0; public static final long TRACE_TAG_ALWAYS = 1L << 0; @@ -49,7 +53,11 @@ public final class Trace { public static final String PROPERTY_TRACE_TAG_ENABLEFLAGS = "debug.atrace.tags.enableflags"; - private static long sEnabledTags = nativeGetEnabledTags(); + // This works as a "not ready" flag because TRACE_TAG_ALWAYS is always set. + private static final long TRACE_FLAGS_NOT_READY = 0; + + // Must be volatile to avoid word tearing. + private static volatile long sEnabledTags = TRACE_FLAGS_NOT_READY; private static native long nativeGetEnabledTags(); private static native void nativeTraceCounter(long tag, String name, int value); @@ -57,9 +65,17 @@ public final class Trace { private static native void nativeTraceEnd(long tag); static { + // We configure two separate change callbacks, one in Trace.cpp and one here. The + // native callback reads the tags from the system property, and this callback + // reads the value that the native code retrieved. It's essential that the native + // callback executes first. + // + // The system provides ordering through a priority level. Callbacks made through + // SystemProperties.addChangeCallback currently have a negative priority, while + // our native code is using a priority of zero. SystemProperties.addChangeCallback(new Runnable() { @Override public void run() { - sEnabledTags = nativeGetEnabledTags(); + cacheEnabledTags(); } }); } @@ -68,13 +84,41 @@ public final class Trace { } /** + * Caches a copy of the enabled-tag bits. The "master" copy is held by the native code, + * and comes from the PROPERTY_TRACE_TAG_ENABLEFLAGS property. + * <p> + * If the native code hasn't yet read the property, we will cause it to do one-time + * initialization. We don't want to do this during class init, because this class is + * preloaded, so all apps would be stuck with whatever the zygote saw. (The zygote + * doesn't see the system-property update broadcasts.) + * <p> + * We want to defer initialization until the first use by an app, post-zygote. + * <p> + * We're okay if multiple threads call here simultaneously -- the native state is + * synchronized, and sEnabledTags is volatile (prevents word tearing). + */ + private static long cacheEnabledTags() { + long tags = nativeGetEnabledTags(); + if (tags == TRACE_FLAGS_NOT_READY) { + Log.w(TAG, "Unexpected value from nativeGetEnabledTags: " + tags); + // keep going + } + sEnabledTags = tags; + return tags; + } + + /** * Returns true if a trace tag is enabled. * * @param traceTag The trace tag to check. * @return True if the trace tag is valid. */ public static boolean isTagEnabled(long traceTag) { - return (sEnabledTags & traceTag) != 0; + long tags = sEnabledTags; + if (tags == TRACE_FLAGS_NOT_READY) { + tags = cacheEnabledTags(); + } + return (tags & traceTag) != 0; } /** @@ -85,7 +129,7 @@ public final class Trace { * @param counterValue The counter value. */ public static void traceCounter(long traceTag, String counterName, int counterValue) { - if ((sEnabledTags & traceTag) != 0) { + if (isTagEnabled(traceTag)) { nativeTraceCounter(traceTag, counterName, counterValue); } } @@ -98,7 +142,7 @@ public final class Trace { * @param methodName The method name to appear in the trace. */ public static void traceBegin(long traceTag, String methodName) { - if ((sEnabledTags & traceTag) != 0) { + if (isTagEnabled(traceTag)) { nativeTraceBegin(traceTag, methodName); } } @@ -110,7 +154,7 @@ public final class Trace { * @param traceTag The trace tag. */ public static void traceEnd(long traceTag) { - if ((sEnabledTags & traceTag) != 0) { + if (isTagEnabled(traceTag)) { nativeTraceEnd(traceTag); } } diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 0d2835a..1fecf81 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -939,27 +939,22 @@ class TextLine { continue; } - if (c == null) { - x += handleText(wp, i, mlimit, i, inext, runIsRtl, c, x, top, - y, bottom, fmi, needWidth || mlimit < measureLimit); - } else { - for (int j = i, jnext; j < mlimit; j = jnext) { - jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) - - mStart; - - wp.set(mPaint); - for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { - // Intentionally using >= and <= as explained above - if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) || - (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue; - - CharacterStyle span = mCharacterStyleSpanSet.spans[k]; - span.updateDrawState(wp); - } + for (int j = i, jnext; j < mlimit; j = jnext) { + jnext = mCharacterStyleSpanSet.getNextTransition(mStart + j, mStart + mlimit) - + mStart; + + wp.set(mPaint); + for (int k = 0; k < mCharacterStyleSpanSet.numberOfSpans; k++) { + // Intentionally using >= and <= as explained above + if ((mCharacterStyleSpanSet.spanStarts[k] >= mStart + jnext) || + (mCharacterStyleSpanSet.spanEnds[k] <= mStart + j)) continue; - x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, - top, y, bottom, fmi, needWidth || jnext < measureLimit); + CharacterStyle span = mCharacterStyleSpanSet.spans[k]; + span.updateDrawState(wp); } + + x += handleText(wp, j, jnext, i, inext, runIsRtl, c, x, + top, y, bottom, fmi, needWidth || jnext < measureLimit); } } diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 183b012..550a740 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -758,6 +758,7 @@ public class Surface implements Parcelable { public float density; public float xDpi; public float yDpi; + public boolean secure; public PhysicalDisplayInfo() { } @@ -778,7 +779,8 @@ public class Surface implements Parcelable { && refreshRate == other.refreshRate && density == other.density && xDpi == other.xDpi - && yDpi == other.yDpi; + && yDpi == other.yDpi + && secure == other.secure; } @Override @@ -793,13 +795,15 @@ public class Surface implements Parcelable { density = other.density; xDpi = other.xDpi; yDpi = other.yDpi; + secure = other.secure; } // For debugging purposes @Override public String toString() { return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " - + "density " + density + ", " + xDpi + " x " + yDpi + " dpi}"; + + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure + + "}"; } } diff --git a/core/java/android/view/ViewManager.java b/core/java/android/view/ViewManager.java index 7f318c1..ab6856f 100644 --- a/core/java/android/view/ViewManager.java +++ b/core/java/android/view/ViewManager.java @@ -21,6 +21,16 @@ package android.view; */ public interface ViewManager { + /** + * Assign the passed LayoutParams to the passed View and add the view to the window. + * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming + * errors, such as adding a second view to a window without removing the first view. + * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a + * secondary {@link Display} and the specified display can't be found + * (see {@link android.app.Presentation}). + * @param view The view to be added to this window. + * @param params The LayoutParams to assign to view. + */ public void addView(View view, ViewGroup.LayoutParams params); public void updateViewLayout(View view, ViewGroup.LayoutParams params); public void removeView(View view); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 8a82a54..a3360bc 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -29,14 +29,12 @@ import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.Region; import android.graphics.drawable.Drawable; import android.media.AudioManager; @@ -558,7 +556,6 @@ public final class ViewRootImpl implements ViewParent, mPendingVisibleInsets.set(0, 0, 0, 0); if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { - mView = null; mAttachInfo.mRootView = null; mAdded = false; mFallbackEventHandler.setView(null); @@ -594,6 +591,10 @@ public final class ViewRootImpl implements ViewParent, throw new WindowManager.BadTokenException( "Unable to add window " + mWindow + " -- permission denied for this window type"); + case WindowManagerGlobal.ADD_INVALID_DISPLAY: + throw new WindowManager.InvalidDisplayException( + "Unable to add window " + mWindow + + " -- the specified display can not be found"); } throw new RuntimeException( "Unable to add window -- unknown error code " + res); @@ -810,27 +811,21 @@ public final class ViewRootImpl implements ViewParent, } } - /** - * {@inheritDoc} - */ + @Override public void requestFitSystemWindows() { checkThread(); mFitSystemWindowsRequested = true; scheduleTraversals(); } - /** - * {@inheritDoc} - */ + @Override public void requestLayout() { checkThread(); mLayoutRequested = true; scheduleTraversals(); } - /** - * {@inheritDoc} - */ + @Override public boolean isLayoutRequested() { return mLayoutRequested; } @@ -850,6 +845,7 @@ public final class ViewRootImpl implements ViewParent, } } + @Override public void invalidateChild(View child, Rect dirty) { invalidateChildInParent(null, dirty); } @@ -861,7 +857,7 @@ public final class ViewRootImpl implements ViewParent, if (dirty == null) { invalidate(); return null; - } else if (dirty.isEmpty()) { + } else if (dirty.isEmpty() && !mIsAnimating) { return null; } @@ -890,14 +886,14 @@ public final class ViewRootImpl implements ViewParent, // Intersect with the bounds of the window to skip // updates that lie outside of the visible region final float appScale = mAttachInfo.mApplicationScale; - if (localDirty.intersect(0, 0, - (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f))) { - if (!mWillDrawSoon) { - scheduleTraversals(); - } - } else { + final boolean intersected = localDirty.intersect(0, 0, + (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); + if (!intersected) { localDirty.setEmpty(); } + if (!mWillDrawSoon && (intersected || mIsAnimating)) { + scheduleTraversals(); + } return null; } @@ -1424,8 +1420,6 @@ public final class ViewRootImpl implements ViewParent, layerCanvas.setViewport(mWidth, mHeight); layerCanvas.onPreDraw(null); final int restoreCount = layerCanvas.save(); - - layerCanvas.drawColor(0xff000000, PorterDuff.Mode.SRC); int yoff; final boolean scrolling = mScroller != null @@ -1442,7 +1436,13 @@ public final class ViewRootImpl implements ViewParent, mTranslator.translateCanvas(layerCanvas); } - mView.draw(layerCanvas); + DisplayList displayList = mView.mDisplayList; + if (displayList != null) { + layerCanvas.drawDisplayList(displayList, null, + DisplayList.FLAG_CLIP_CHILDREN); + } else { + mView.draw(layerCanvas); + } drawAccessibilityFocusedDrawableIfNeeded(layerCanvas); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 4c97414..01923e2 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -62,6 +62,19 @@ public interface WindowManager extends ViewManager { } /** + * Exception that is thrown when calling {@link #addView} to a secondary display that cannot + * be found. See {@link android.app.Presentation} for more information on secondary displays. + */ + public static class InvalidDisplayException extends RuntimeException { + public InvalidDisplayException() { + } + + public InvalidDisplayException(String name) { + super(name); + } + } + + /** * Returns the {@link Display} upon which this {@link WindowManager} instance * will create new windows. * <p> diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 5cdc1ed..e8945aa 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -186,8 +186,8 @@ public final class WindowManagerGlobal { mSystemPropertyUpdater = new Runnable() { @Override public void run() { synchronized (mLock) { - for (ViewRootImpl root : mRoots) { - root.loadSystemProperties(); + for (ViewRootImpl viewRoot : mRoots) { + viewRoot.loadSystemProperties(); } } } @@ -242,7 +242,18 @@ public final class WindowManagerGlobal { } // do this last because it fires off messages to start doing things - root.setView(view, wparams, panelParentView); + try { + root.setView(view, wparams, panelParentView); + } catch (RuntimeException e) { + // BadTokenException or InvalidDisplayException, clean up. + synchronized (mLock) { + final int index = findViewLocked(view, false); + if (index >= 0) { + removeViewLocked(index, true); + } + } + throw e; + } } public void updateViewLayout(View view, ViewGroup.LayoutParams params) { @@ -360,20 +371,18 @@ public final class WindowManagerGlobal { } private int findViewLocked(View view, boolean required) { - synchronized (mLock) { - if (mViews != null) { - final int count = mViews.length; - for (int i = 0; i < count; i++) { - if (mViews[i] == view) { - return i; - } + if (mViews != null) { + final int count = mViews.length; + for (int i = 0; i < count; i++) { + if (mViews[i] == view) { + return i; } } - if (required) { - throw new IllegalArgumentException("View not attached to window manager"); - } - return -1; } + if (required) { + throw new IllegalArgumentException("View not attached to window manager"); + } + return -1; } public void startTrimMemory(int level) { diff --git a/core/java/android/webkit/AccessibilityInjector.java b/core/java/android/webkit/AccessibilityInjector.java index fe5cad4..95a0416 100644 --- a/core/java/android/webkit/AccessibilityInjector.java +++ b/core/java/android/webkit/AccessibilityInjector.java @@ -514,6 +514,8 @@ class AccessibilityInjector { } } catch (URISyntaxException e) { // Do nothing. + } catch (IllegalArgumentException e) { + // Catch badly-formed URLs. } return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED; |
