diff options
Diffstat (limited to 'core/java/android')
25 files changed, 388 insertions, 84 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index fab88a2..8cee587 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6068,6 +6068,17 @@ public class Activity extends ContextThemeWrapper " did not call through to super.onResume()"); } + // invisible activities must be finished before onResume() completes + if (!mVisibleFromClient && !mFinished) { + Log.w(TAG, "An activity without a UI must call finish() before onResume() completes"); + if (getApplicationInfo().targetSdkVersion + > android.os.Build.VERSION_CODES.LOLLIPOP_MR1) { + throw new IllegalStateException( + "Activity " + mComponent.toShortString() + + " did not call finish() prior to onResume() completing"); + } + } + // Now really resume, and install the current status bar and menu. mCalled = false; diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 360f308..0cff4c0 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -286,10 +286,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { final String original = setCallingPackage(callingPkg); try { ContentProviderResult[] results = ContentProvider.this.applyBatch(operations); - for (int i = 0; i < results.length ; i++) { - if (userIds[i] != UserHandle.USER_CURRENT) { - // Adding the userId to the uri. - results[i] = new ContentProviderResult(results[i], userIds[i]); + if (results != null) { + for (int i = 0; i < results.length ; i++) { + if (userIds[i] != UserHandle.USER_CURRENT) { + // Adding the userId to the uri. + results[i] = new ContentProviderResult(results[i], userIds[i]); + } } } return results; diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 73913b6..ab0dad7 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2425,6 +2425,9 @@ public class Resources { final String themeKey = theme == null ? "" : theme.mKey; LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey); if (themedCache == null) { + // Clean out the caches before we add more. This shouldn't + // happen very often. + pruneCaches(caches); themedCache = new LongSparseArray<WeakReference<ConstantState>>(1); caches.put(themeKey, themedCache); } @@ -2434,6 +2437,40 @@ public class Resources { } /** + * Prunes empty caches from the cache map. + * + * @param caches The map of caches to prune. + */ + private void pruneCaches(ArrayMap<String, + LongSparseArray<WeakReference<ConstantState>>> caches) { + final int N = caches.size(); + for (int i = N - 1; i >= 0; i--) { + final LongSparseArray<WeakReference<ConstantState>> cache = caches.get(i); + if (pruneCache(cache)) { + caches.removeAt(i); + } + } + } + + /** + * Prunes obsolete weak references from a cache, returning {@code true} if + * the cache is empty and should be removed. + * + * @param cache The cache of weak references to prune. + * @return {@code true} if the cache is empty and should be removed. + */ + private boolean pruneCache(LongSparseArray<WeakReference<ConstantState>> cache) { + final int N = cache.size(); + for (int i = N - 1; i >= 0; i--) { + final WeakReference entry = cache.valueAt(i); + if (entry.get() == null) { + cache.removeAt(i); + } + } + return cache.size() == 0; + } + + /** * Loads a drawable from XML or resources stream. */ private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) { diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index 4853b81..a0a0716 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -58,6 +58,11 @@ public class SurfaceTextureRenderer { private static final int GLES_VERSION = 2; private static final int PBUFFER_PIXEL_BYTES = 4; + private static final int FLIP_TYPE_NONE = 0; + private static final int FLIP_TYPE_HORIZONTAL = 1; + private static final int FLIP_TYPE_VERTICAL = 2; + private static final int FLIP_TYPE_BOTH = FLIP_TYPE_HORIZONTAL | FLIP_TYPE_VERTICAL; + private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY; private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT; private EGLConfig mConfigs; @@ -82,8 +87,8 @@ public class SurfaceTextureRenderer { private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; - // Sampling is mirrored across the vertical axis to undo horizontal flip from the front camera - private static final float[] sFrontCameraTriangleVertices = { + // Sampling is mirrored across the horizontal axis + private static final float[] sHorizontalFlipTriangleVertices = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 1.f, 0.f, 1.0f, -1.0f, 0, 0.f, 0.f, @@ -91,8 +96,26 @@ public class SurfaceTextureRenderer { 1.0f, 1.0f, 0, 0.f, 1.f, }; + // Sampling is mirrored across the vertical axis + private static final float[] sVerticalFlipTriangleVertices = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0, 0.f, 1.f, + 1.0f, -1.0f, 0, 1.f, 1.f, + -1.0f, 1.0f, 0, 0.f, 0.f, + 1.0f, 1.0f, 0, 1.f, 0.f, + }; + + // Sampling is mirrored across the both axes + private static final float[] sBothFlipTriangleVertices = { + // X, Y, Z, U, V + -1.0f, -1.0f, 0, 1.f, 1.f, + 1.0f, -1.0f, 0, 0.f, 1.f, + -1.0f, 1.0f, 0, 1.f, 0.f, + 1.0f, 1.0f, 0, 0.f, 0.f, + }; + // Sampling is 1:1 for a straight copy for the back camera - private static final float[] sBackCameraTriangleVertices = { + private static final float[] sRegularTriangleVertices = { // X, Y, Z, U, V -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, @@ -100,7 +123,11 @@ public class SurfaceTextureRenderer { 1.0f, 1.0f, 0, 1.f, 1.f, }; - private FloatBuffer mTriangleVertices; + private FloatBuffer mRegularTriangleVertices; + private FloatBuffer mHorizontalFlipTriangleVertices; + private FloatBuffer mVerticalFlipTriangleVertices; + private FloatBuffer mBothFlipTriangleVertices; + private final int mFacing; /** * As used in this file, this vertex shader maps a unit square to the view, and @@ -148,15 +175,27 @@ public class SurfaceTextureRenderer { private static final String LEGACY_PERF_PROPERTY = "persist.camera.legacy_perf"; public SurfaceTextureRenderer(int facing) { - if (facing == CameraCharacteristics.LENS_FACING_BACK) { - mTriangleVertices = ByteBuffer.allocateDirect(sBackCameraTriangleVertices.length * - FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); - mTriangleVertices.put(sBackCameraTriangleVertices).position(0); - } else { - mTriangleVertices = ByteBuffer.allocateDirect(sFrontCameraTriangleVertices.length * - FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); - mTriangleVertices.put(sFrontCameraTriangleVertices).position(0); - } + mFacing = facing; + + mRegularTriangleVertices = ByteBuffer.allocateDirect(sRegularTriangleVertices.length * + FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mRegularTriangleVertices.put(sRegularTriangleVertices).position(0); + + mHorizontalFlipTriangleVertices = ByteBuffer.allocateDirect( + sHorizontalFlipTriangleVertices.length * FLOAT_SIZE_BYTES). + order(ByteOrder.nativeOrder()).asFloatBuffer(); + mHorizontalFlipTriangleVertices.put(sHorizontalFlipTriangleVertices).position(0); + + mVerticalFlipTriangleVertices = ByteBuffer.allocateDirect( + sVerticalFlipTriangleVertices.length * FLOAT_SIZE_BYTES). + order(ByteOrder.nativeOrder()).asFloatBuffer(); + mVerticalFlipTriangleVertices.put(sVerticalFlipTriangleVertices).position(0); + + mBothFlipTriangleVertices = ByteBuffer.allocateDirect( + sBothFlipTriangleVertices.length * FLOAT_SIZE_BYTES). + order(ByteOrder.nativeOrder()).asFloatBuffer(); + mBothFlipTriangleVertices.put(sBothFlipTriangleVertices).position(0); + Matrix.setIdentityM(mSTMatrix, 0); } @@ -209,7 +248,7 @@ public class SurfaceTextureRenderer { return program; } - private void drawFrame(SurfaceTexture st, int width, int height) { + private void drawFrame(SurfaceTexture st, int width, int height, int flipType) { checkGlError("onDrawFrame start"); st.getTransformMatrix(mSTMatrix); @@ -266,16 +305,32 @@ public class SurfaceTextureRenderer { GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); - mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); + FloatBuffer triangleVertices; + switch(flipType) { + case FLIP_TYPE_HORIZONTAL: + triangleVertices = mHorizontalFlipTriangleVertices; + break; + case FLIP_TYPE_VERTICAL: + triangleVertices = mVerticalFlipTriangleVertices; + break; + case FLIP_TYPE_BOTH: + triangleVertices = mBothFlipTriangleVertices; + break; + default: + triangleVertices = mRegularTriangleVertices; + break; + } + + triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); GLES20.glVertexAttribPointer(maPositionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT, - /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); checkGlError("glVertexAttribPointer maPosition"); GLES20.glEnableVertexAttribArray(maPositionHandle); checkGlError("glEnableVertexAttribArray maPositionHandle"); - mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); + triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); GLES20.glVertexAttribPointer(maTextureHandle, VERTEX_UV_SIZE, GLES20.GL_FLOAT, - /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices); checkGlError("glVertexAttribPointer maTextureHandle"); GLES20.glEnableVertexAttribArray(maTextureHandle); checkGlError("glEnableVertexAttribArray maTextureHandle"); @@ -666,7 +721,9 @@ public class SurfaceTextureRenderer { makeCurrent(holder.eglSurface); LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second); - drawFrame(mSurfaceTexture, holder.width, holder.height); + drawFrame(mSurfaceTexture, holder.width, holder.height, + (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ? + FLIP_TYPE_HORIZONTAL : FLIP_TYPE_NONE); swapBuffers(holder.eglSurface); } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { Log.w(TAG, "Surface abandoned, dropping frame. ", e); @@ -676,7 +733,10 @@ public class SurfaceTextureRenderer { for (EGLSurfaceHolder holder : mConversionSurfaces) { if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) { makeCurrent(holder.eglSurface); - drawFrame(mSurfaceTexture, holder.width, holder.height); + // glReadPixels reads from the bottom of the buffer, so add an extra vertical flip + drawFrame(mSurfaceTexture, holder.width, holder.height, + (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ? + FLIP_TYPE_BOTH : FLIP_TYPE_VERTICAL); mPBufferPixels.clear(); GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPBufferPixels); diff --git a/core/java/android/midi/MidiDevice.java b/core/java/android/midi/MidiDevice.java index e704ea0..7f83896 100644 --- a/core/java/android/midi/MidiDevice.java +++ b/core/java/android/midi/MidiDevice.java @@ -140,6 +140,12 @@ public final class MidiDevice implements Parcelable { mReceivers = new ArrayList[outputPorts]; } + /** + * Called to open a {@link MidiInputPort} for the specified port number. + * + * @param portNumber the number of the input port to open + * @return the {@link MidiInputPort} + */ public MidiInputPort openInputPort(int portNumber) { if (portNumber < 0 || portNumber >= mDeviceInfo.getInputPortCount()) { throw new IllegalArgumentException("input port number out of range"); @@ -152,6 +158,12 @@ public final class MidiDevice implements Parcelable { } } + /** + * Called to open a {@link MidiOutputPort} for the specified port number. + * + * @param portNumber the number of the output port to open + * @return the {@link MidiOutputPort} + */ public MidiOutputPort openOutputPort(int portNumber) { if (portNumber < 0 || portNumber >= mDeviceInfo.getOutputPortCount()) { throw new IllegalArgumentException("output port number out of range"); @@ -203,7 +215,7 @@ public final class MidiDevice implements Parcelable { return true; } - void close() { + /* package */ void close() { try { if (mInputStream != null) { mInputStream.close(); @@ -216,7 +228,11 @@ public final class MidiDevice implements Parcelable { } } - // returns our MidiDeviceInfo object, which describes this device + /** + * Returns a {@link MidiDeviceInfo} object, which describes this device. + * + * @return the {@link MidiDeviceInfo} object + */ public MidiDeviceInfo getInfo() { return mDeviceInfo; } @@ -239,10 +255,12 @@ public final class MidiDevice implements Parcelable { } }; + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeParcelable(mDeviceInfo, flags); parcel.writeParcelable(mParcelFileDescriptor, flags); diff --git a/core/java/android/midi/MidiDeviceInfo.java b/core/java/android/midi/MidiDeviceInfo.java index 239481b..5b57696 100644 --- a/core/java/android/midi/MidiDeviceInfo.java +++ b/core/java/android/midi/MidiDeviceInfo.java @@ -34,7 +34,14 @@ public class MidiDeviceInfo implements Parcelable { private static final String TAG = "MidiDeviceInfo"; + /** + * Constant representing USB MIDI devices for {@link #getType} + */ public static final int TYPE_USB = 1; + + /** + * Constant representing virtual (software based) MIDI devices for {@link #getType} + */ public static final int TYPE_VIRTUAL = 2; private final int mType; // USB or virtual diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java index 583c367..31449a5 100644 --- a/core/java/android/midi/MidiInputPort.java +++ b/core/java/android/midi/MidiInputPort.java @@ -38,14 +38,15 @@ public final class MidiInputPort extends MidiPort implements MidiReceiver { /** * Writes a MIDI message to the input port * - * @param msg message bytes - * @param offset offset of first byte of the message in msg array + * @param msg byte array containing the message + * @param offset offset of first byte of the message in msg byte array * @param count size of the message in bytes - * @param timestamp future time to post the message + * @param timestamp future time to post the message (based on + * {@link java.lang.System#nanoTime} */ public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException { synchronized (mBuffer) { - int length = MidiDevice.packMessage(msg, offset, count, timestamp, mPortNumber, + int length = MidiDevice.packMessage(msg, offset, count, timestamp, getPortNumber(), mBuffer); mOutputStream.write(mBuffer, 0, length); } diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java index f4d1918..64cd4fe 100644 --- a/core/java/android/midi/MidiManager.java +++ b/core/java/android/midi/MidiManager.java @@ -35,6 +35,7 @@ import java.util.HashMap; * * {@samplecode * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);} + * * @hide */ public class MidiManager { @@ -64,9 +65,22 @@ public class MidiManager { } } - // Callback interface clients to receive Device added and removed notifications + /** + * Callback interface used for clients to receive MIDI device added and removed notifications + */ public interface DeviceCallback { + /** + * Called to notify when a new MIDI device has been added + * + * @param device a {@link MidiDeviceInfo} for the newly added device + */ void onDeviceAdded(MidiDeviceInfo device); + + /** + * Called to notify when a MIDI device has been removed + * + * @param device a {@link MidiDeviceInfo} for the removed device + */ void onDeviceRemoved(MidiDeviceInfo device); } @@ -78,7 +92,11 @@ public class MidiManager { mService = service; } - // Used by clients to register for Device added and removed notifications + /** + * Registers a callback to receive notifications when MIDI devices are added and removed. + * + * @param callback a {@link DeviceCallback} for MIDI device notifications + */ public void registerDeviceCallback(DeviceCallback callback) { DeviceListener deviceListener = new DeviceListener(callback); try { @@ -90,7 +108,11 @@ public class MidiManager { mDeviceListeners.put(callback, deviceListener); } - // Used by clients to unregister for device added and removed notifications + /** + * Unregisters a {@link DeviceCallback}. + * + * @param callback a {@link DeviceCallback} to unregister + */ public void unregisterDeviceCallback(DeviceCallback callback) { DeviceListener deviceListener = mDeviceListeners.remove(callback); if (deviceListener != null) { @@ -102,6 +124,11 @@ public class MidiManager { } } + /** + * Gets the list of all connected MIDI devices. + * + * @return an array of all MIDI devices + */ public MidiDeviceInfo[] getDeviceList() { try { return mService.getDeviceList(); @@ -111,7 +138,12 @@ public class MidiManager { } } - // Use this if you want to communicate with a MIDI device. + /** + * Opens a MIDI device for reading and writing. + * + * @param deviceInfo a {@link android.midi.MidiDeviceInfo} to open + * @return a {@link MidiDevice} object for the device + */ public MidiDevice openDevice(MidiDeviceInfo deviceInfo) { try { ParcelFileDescriptor pfd = mService.openDevice(mToken, deviceInfo); @@ -130,8 +162,15 @@ public class MidiManager { return null; } - // Use this if you want to register and implement a virtual device. - // The MidiDevice returned by this method is the proxy you use to implement the device. + /** + * Creates a new MIDI virtual device. + * NOTE: The method for creating virtual devices is likely to change before release. + * + * @param numInputPorts number of input ports for the virtual device + * @param numOutputPorts number of output ports for the virtual device + * @param properties a {@link android.os.Bundle} containing properties describing the device + * @return a {@link MidiDevice} object to locally represent the device + */ public MidiDevice createVirtualDevice(int numInputPorts, int numOutputPorts, Bundle properties) { try { @@ -147,6 +186,11 @@ public class MidiManager { } } + /** + * Removes a MIDI virtual device. + * + * @param device the {@link MidiDevice} for the virtual device to remove + */ public void closeVirtualDevice(MidiDevice device) { try { device.close(); diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java index 69a33cb..7ce286b 100644 --- a/core/java/android/midi/MidiOutputPort.java +++ b/core/java/android/midi/MidiOutputPort.java @@ -32,11 +32,22 @@ public final class MidiOutputPort extends MidiPort implements MidiSender { mDevice = device; } + /** + * Connects a {@link MidiReceiver} to the output port to allow receiving + * MIDI messages from the port. + * + * @param receiver the receiver to connect + */ public void connect(MidiReceiver receiver) { - mDevice.connect(receiver, mPortNumber); + mDevice.connect(receiver, getPortNumber()); } + /** + * Disconnects a {@link MidiReceiver} from the output port. + * + * @param receiver the receiver to connect + */ public void disconnect(MidiReceiver receiver) { - mDevice.disconnect(receiver, mPortNumber); + mDevice.disconnect(receiver, getPortNumber()); } } diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java index e94f62d..fdd0233 100644 --- a/core/java/android/midi/MidiPort.java +++ b/core/java/android/midi/MidiPort.java @@ -20,13 +20,14 @@ import java.io.FileOutputStream; import java.io.IOException; /** - * This class represents a MIDI input or output port + * This class represents a MIDI input or output port. + * Base class for {@link MidiInputPort} and {@link MidiOutputPort} * * @hide */ public class MidiPort { - protected final int mPortNumber; + private final int mPortNumber; /* package */ MidiPort(int portNumber) { mPortNumber = portNumber; @@ -37,7 +38,7 @@ public class MidiPort { * * @return the port's port number */ - public int getPortNumber() { + public final int getPortNumber() { return mPortNumber; } } diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java index 1101105..0b183cc 100644 --- a/core/java/android/midi/MidiReceiver.java +++ b/core/java/android/midi/MidiReceiver.java @@ -24,7 +24,18 @@ import java.io.IOException; * @hide */ public interface MidiReceiver { - // NOTE: the msg array is only valid within the context of this call. - // the byte array may get reused by the MIDI device for the next message. + /** + * Called to pass a MIDI event to the receiver. + * + * NOTE: the msg array parameter is only valid within the context of this call. + * The msg bytes should be copied by the receiver rather than retaining a reference + * to this parameter. + * + * @param msg a byte array containing the MIDI message + * @param offset the offset of the first byte of the message in the byte array + * @param count the number of bytes in the message + * @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime} + * @throws IOException + */ public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException; } diff --git a/core/java/android/midi/MidiSender.java b/core/java/android/midi/MidiSender.java index cba7079..7958a06 100644 --- a/core/java/android/midi/MidiSender.java +++ b/core/java/android/midi/MidiSender.java @@ -23,6 +23,17 @@ package android.midi; * @hide */ public interface MidiSender { + /** + * Called to connect a {@link MidiReceiver} to the sender + * + * @param receiver the receiver to connect + */ public void connect(MidiReceiver receiver); + + /** + * Called to disconnect a {@link MidiReceiver} from the sender + * + * @param receiver the receiver to disconnect + */ public void disconnect(MidiReceiver receiver); } diff --git a/core/java/android/midi/MidiUtils.java b/core/java/android/midi/MidiUtils.java index f80e83a..e60e2db 100644 --- a/core/java/android/midi/MidiUtils.java +++ b/core/java/android/midi/MidiUtils.java @@ -26,6 +26,8 @@ import android.util.Log; public final class MidiUtils { private static final String TAG = "MidiUtils"; + private MidiUtils() { } + /** * Returns data size of a MIDI message based on the message's command byte * @param b the message command byte diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 6ddd8b3..9b80e74 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -274,4 +274,12 @@ public class NetworkFactory extends Handler { protected void log(String s) { Log.d(LOG_TAG, s); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter="). + append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests="). + append(mNetworkRequests.size()).append("}"); + return sb.toString(); + } } diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java index 9fdf88d..5b07397 100644 --- a/core/java/android/text/StaticLayout.java +++ b/core/java/android/text/StaticLayout.java @@ -354,12 +354,14 @@ public class StaticLayout extends Layout { while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) { int endPos = paraStart + breaks[breakIndex]; + boolean moreChars = (endPos < paraEnd); // XXX is this the right way to calculate this? + v = out(source, here, endPos, fmAscent, fmDescent, fmTop, fmBottom, v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad, chs, widths, paraStart, ellipsize, ellipsizedWidth, - lineWidths[breakIndex], paint, true); + lineWidths[breakIndex], paint, moreChars); if (endPos < spanEnd) { // preserve metrics for current span diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 753a4e7..143aa24 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8185,8 +8185,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #performAccessibilityAction(int, Bundle) * * Note: Called from the default {@link AccessibilityDelegate}. + * + * @hide Until we've refactored all accessibility delegation methods. */ - boolean performAccessibilityActionInternal(int action, Bundle arguments) { + public boolean performAccessibilityActionInternal(int action, Bundle arguments) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { if (isClickable()) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 277e445..10af0c3 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -825,6 +825,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } + // Clip the bounds by our bounds. + bounds.left = Math.max(bounds.left, 0); + bounds.top = Math.max(bounds.top, 0); + bounds.right = Math.min(bounds.right, mRight); + bounds.bottom = Math.min(bounds.bottom, mBottom); + Iterator<View> iterator = obtainOrderedChildIterator(); while (iterator.hasNext()) { View sibling = iterator.next(); @@ -5113,7 +5119,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager final int height = mBottom - mTop; boolean rectIsVisible = true; - if (mParent instanceof ViewGroup && ((ViewGroup)mParent).getClipChildren()) { + if (mParent == null || + (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) { // Clip to bounds. rectIsVisible = rect.intersect(0, 0, width, height); } diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java index d68a860..9f9ed5b 100644 --- a/core/java/android/view/ViewStub.java +++ b/core/java/android/view/ViewStub.java @@ -69,8 +69,8 @@ import java.lang.ref.WeakReference; */ @RemoteView public final class ViewStub extends View { - private int mLayoutResource = 0; private int mInflatedId; + private int mLayoutResource; private WeakReference<View> mInflatedViewRef; @@ -78,7 +78,7 @@ public final class ViewStub extends View { private OnInflateListener mInflateListener; public ViewStub(Context context) { - initialize(context); + this(context, 0); } /** @@ -88,38 +88,29 @@ public final class ViewStub extends View { * @param layoutResource The reference to a layout resource that will be inflated. */ public ViewStub(Context context, int layoutResource) { + this(context, null); + mLayoutResource = layoutResource; - initialize(context); } public ViewStub(Context context, AttributeSet attrs) { this(context, attrs, 0); } - @SuppressWarnings({"UnusedDeclaration"}) public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - TypedArray a = context.obtainStyledAttributes( - attrs, com.android.internal.R.styleable.ViewStub, defStyleAttr, defStyleRes); + super(context); + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.ViewStub, defStyleAttr, defStyleRes); mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID); mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0); - - a.recycle(); - - a = context.obtainStyledAttributes( - attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); - mID = a.getResourceId(R.styleable.View_id, NO_ID); + mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID); a.recycle(); - initialize(context); - } - - private void initialize(Context context) { - mContext = context; setVisibility(GONE); setWillNotDraw(true); } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 0d82087..0d3727b 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -212,15 +212,15 @@ public final class WindowManagerGlobal { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } - final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; + final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); - } else { + } else if (ActivityManager.isHighEndGfx()) { // If there's no parent and we're running on L or above (or in the // system context), assume we want hardware acceleration. final Context context = view.getContext(); - if (context != null - && context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { + if (context != null && context.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.LOLLIPOP) { wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } } diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index eca96f9..6d5fac1 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -31,10 +31,7 @@ public abstract class CookieManager { } /** - * Gets the singleton CookieManager instance. If this method is used - * before the application instantiates a {@link WebView} instance, - * {@link CookieSyncManager#createInstance CookieSyncManager.createInstance(Context)} - * must be called first. + * Gets the singleton CookieManager instance. * * @return the singleton CookieManager instance */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 6793634..3694863 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -239,6 +239,34 @@ import java.util.Map; * and {@link WebChromeClient#onHideCustomView()} are required, * {@link WebChromeClient#getVideoLoadingProgressView()} is optional. * </p> + * + * <h3>Layout size</h3> + * <p> + * It is recommended to set the WebView layout height to a fixed value or to + * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} instead of using + * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}. + * When using {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} + * for the height none of the WebView's parents should use a + * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} layout height since that could result in + * incorrect sizing of the views. + * </p> + * + * <p>Setting the WebView's height to {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} + * enables the following behaviors: + * <ul> + * <li>The HTML body layout height is set to a fixed value. This means that elements with a height + * relative to the HTML body may not be sized correctly. </li> + * <li>For applications targetting {@link android.os.Build.VERSION_CODES#KITKAT} and earlier SDKs the + * HTML viewport meta tag will be ignored in order to preserve backwards compatibility. </li> + * </ul> + * </p> + * + * <p> + * Using a layout width of {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} is not + * supported. If such a width is used the WebView will attempt to use the width of the parent + * instead. + * </p> + * */ // Implementation notes. // The WebView is a thin API class that delegates its public API to a backend WebViewProvider diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 54c4505..e75643ab 100644 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -372,10 +372,9 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mCurrentDate.set(Calendar.MONTH, monthOfYear); mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - onDateChanged(false); - - // Set the listener last so that we don't call it. mDateChangedListener = callBack; + + onDateChanged(false, false); } @Override @@ -384,11 +383,11 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mCurrentDate.set(Calendar.MONTH, month); mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); - onDateChanged(false); + onDateChanged(false, true); } - private void onDateChanged(boolean fromUser) { - if (mDateChangedListener != null) { + private void onDateChanged(boolean fromUser, boolean callbackToClient) { + if (callbackToClient && mDateChangedListener != null) { final int year = mCurrentDate.get(Calendar.YEAR); final int monthOfYear = mCurrentDate.get(Calendar.MONTH); final int dayOfMonth = mCurrentDate.get(Calendar.DAY_OF_MONTH); @@ -432,7 +431,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i } if (mCurrentDate.before(mTempDate)) { mCurrentDate.setTimeInMillis(minDate); - onDateChanged(false); + onDateChanged(false, true); } mMinDate.setTimeInMillis(minDate); mDayPickerView.setMinDate(minDate); @@ -453,7 +452,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i } if (mCurrentDate.after(mTempDate)) { mCurrentDate.setTimeInMillis(maxDate); - onDateChanged(false); + onDateChanged(false, true); } mMaxDate.setTimeInMillis(maxDate); mDayPickerView.setMaxDate(maxDate); @@ -592,7 +591,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i public void onYearSelected(int year) { adjustDayInMonthIfNeeded(mCurrentDate.get(Calendar.MONTH), year); mCurrentDate.set(Calendar.YEAR, year); - onDateChanged(true); + onDateChanged(true, true); // Auto-advance to month and day view. setCurrentView(MONTH_AND_DAY_VIEW); @@ -665,7 +664,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i @Override public void onDaySelected(DayPickerView view, Calendar day) { mCurrentDate.setTimeInMillis(day.getTimeInMillis()); - onDateChanged(true); + onDateChanged(true, true); } }; diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 75c6184..7b64cf5 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -1456,6 +1456,32 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { final boolean selected = isVirtualViewSelected(type, value); node.setSelected(selected); + + final int nextId = getVirtualViewIdAfter(type, value); + if (nextId != INVALID_ID) { + node.setTraversalBefore(RadialTimePickerView.this, nextId); + } + } + + private int getVirtualViewIdAfter(int type, int value) { + if (type == TYPE_HOUR) { + final int nextValue = value + 1; + final int max = mIs24HourMode ? 23 : 12; + if (nextValue <= max) { + return makeId(type, nextValue); + } + } else if (type == TYPE_MINUTE) { + final int current = getCurrentMinute(); + final int snapValue = value - (value % MINUTE_INCREMENT); + final int nextValue = snapValue + MINUTE_INCREMENT; + if (value < current && nextValue > current) { + // The current value is between two snap values. + return makeId(type, current); + } else if (nextValue < 60) { + return makeId(type, nextValue); + } + } + return INVALID_ID; } @Override diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 597de1e..edba9f5 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8476,8 +8476,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } + /** + * Performs an accessibility action after it has been offered to the + * delegate. + * + * @hide + */ @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { + public boolean performAccessibilityActionInternal(int action, Bundle arguments) { switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { boolean handled = false; @@ -8558,10 +8564,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { ensureIterableTextForAccessibilitySelectable(); - return super.performAccessibilityAction(action, arguments); + return super.performAccessibilityActionInternal(action, arguments); } default: { - return super.performAccessibilityAction(action, arguments); + return super.performAccessibilityActionInternal(action, arguments); } } } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index d61b6fc..8d475a7 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -33,9 +33,11 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; +import android.view.View.AccessibilityDelegate; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; @@ -136,9 +138,13 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl // Set up hour/minute labels. mHourView = (TextView) mHeaderView.findViewById(R.id.hours); mHourView.setOnClickListener(mClickListener); + mHourView.setAccessibilityDelegate( + new ClickActionDelegate(context, R.string.select_hours)); mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator); mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes); mMinuteView.setOnClickListener(mClickListener); + mMinuteView.setAccessibilityDelegate( + new ClickActionDelegate(context, R.string.select_minutes)); final int headerTimeTextAppearance = a.getResourceId( R.styleable.TimePicker_headerTimeTextAppearance, 0); @@ -206,6 +212,22 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX); } + private static class ClickActionDelegate extends AccessibilityDelegate { + private final AccessibilityAction mClickAction; + + public ClickActionDelegate(Context context, int resId) { + mClickAction = new AccessibilityAction( + AccessibilityNodeInfo.ACTION_CLICK, context.getString(resId)); + } + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + + info.addAction(mClickAction); + } + } + private int computeStableWidth(TextView v, int maxNumber) { int maxWidth = 0; |
