diff options
Diffstat (limited to 'core/java/android')
24 files changed, 303 insertions, 196 deletions
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 2276229..c203a8e 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -51,7 +51,6 @@ public final class BluetoothGatt implements BluetoothProfile { private int mConnState; private final Object mStateLock = new Object(); private Boolean mDeviceBusy = false; - private Boolean mIsCongested = false; private int mTransport; private static final int CONN_STATE_IDLE = 0; @@ -607,21 +606,6 @@ public final class BluetoothGatt implements BluetoothProfile { Log.w(TAG, "Unhandled exception in callback", ex); } } - - /** - * Callback indicating the remote device connection is congested. - * @hide - */ - public void onConnectionCongested(String address, boolean congested) { - if (DBG) Log.d(TAG, "onConnectionCongested() - Device=" + address - + " congested=" + congested); - if (!address.equals(mDevice.getAddress())) return; - try { - mIsCongested = congested; - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } }; /*package*/ BluetoothGatt(Context context, IBluetoothGatt iGatt, BluetoothDevice device, diff --git a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java index da992f5..cdb24f4 100644 --- a/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java +++ b/core/java/android/bluetooth/BluetoothGattCallbackWrapper.java @@ -120,10 +120,6 @@ public class BluetoothGattCallbackWrapper extends IBluetoothGattCallback.Stub { } @Override - public void onConnectionCongested(String address, boolean congested) throws RemoteException { - } - - @Override public void onFoundOrLost(boolean onFound, ScanResult scanResult) throws RemoteException { } diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java index a7f117b..e94a8ce 100644 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -48,7 +48,6 @@ public final class BluetoothGattServer implements BluetoothProfile { private BluetoothAdapter mAdapter; private IBluetoothGatt mService; private BluetoothGattServerCallback mCallback; - private Boolean mIsCongested = false; private Object mServerIfLock = new Object(); private int mServerIf; @@ -285,24 +284,6 @@ public final class BluetoothGattServer implements BluetoothProfile { Log.w(TAG, "Unhandled exception: " + ex); } } - - /** - * Callback indicating the remote device connection is congested. - * @hide - */ - public void onConnectionCongested(String address, boolean congested) { - if (DBG) Log.d(TAG, "onConnectionCongested() - Device=" + address - + " congested=" + congested); - - BluetoothDevice device = mAdapter.getRemoteDevice(address); - if (device == null) return; - - try { - mIsCongested = congested; - } catch (Exception ex) { - Log.w(TAG, "Unhandled exception in callback", ex); - } - } }; /** diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl index 00b6b1b..91e62ea 100644 --- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl @@ -68,6 +68,5 @@ oneway interface IBluetoothGattCallback { void onMultiAdvertiseCallback(in int status, boolean isStart, in AdvertiseSettings advertiseSettings); void onConfigureMTU(in String address, in int mtu, in int status); - void onConnectionCongested(in String address, in boolean congested); void onFoundOrLost(in boolean onFound, in ScanResult scanResult); } diff --git a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl index 6e31da1..5d4d6c6 100644 --- a/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattServerCallback.aidl @@ -59,5 +59,4 @@ oneway interface IBluetoothGattServerCallback { in byte[] value); void onExecuteWrite(in String address, in int transId, in boolean execWrite); void onNotificationSent(in String address, in int status); - void onConnectionCongested(in String address, in boolean congested); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 702ac6b..77981f4 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2723,6 +2723,9 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE"; + /** {@hide} */ + public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). @@ -3425,6 +3428,9 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_TIME_PREF_24_HOUR_FORMAT = "android.intent.extra.TIME_PREF_24_HOUR_FORMAT"; + /** {@hide} */ + public static final String EXTRA_REASON = "android.intent.extra.REASON"; + // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Intent flags (see mFlags variable). diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java index c141c51..b9c89f8 100644 --- a/core/java/android/hardware/camera2/legacy/BurstHolder.java +++ b/core/java/android/hardware/camera2/legacy/BurstHolder.java @@ -22,6 +22,7 @@ import android.util.Log; import android.view.Surface; import java.util.ArrayList; +import java.util.Collection; import java.util.List; /** @@ -38,14 +39,16 @@ public class BurstHolder { * * @param requestId id of the burst request. * @param repeating true if this burst is repeating. - * @param requests a {@link java.util.List} of {@link CaptureRequest}s in this burst. + * @param requests a {@link List} of {@link CaptureRequest}s in this burst. + * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs. */ - public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests) { - mRequestBuilders = new ArrayList<RequestHolder.Builder>(); + public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests, + Collection<Long> jpegSurfaceIds) { + mRequestBuilders = new ArrayList<>(); int i = 0; for (CaptureRequest r : requests) { mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i, - /*request*/r, repeating)); + /*request*/r, repeating, jpegSurfaceIds)); ++i; } mRepeating = repeating; diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index e19f587..fcf172c 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -336,8 +336,16 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(cameraId, info); + Camera.Parameters legacyParameters = null; + try { + legacyParameters = legacyCamera.getParameters(); + } catch (RuntimeException e) { + throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR, + "Unable to get initial parameters", e); + } + CameraCharacteristics characteristics = - LegacyMetadataMapper.createCharacteristics(legacyCamera.getParameters(), info); + LegacyMetadataMapper.createCharacteristics(legacyParameters, info); LegacyCameraDevice device = new LegacyCameraDevice( cameraId, legacyCamera, characteristics, threadCallbacks); return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks); diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index a724b41..4587c6f 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -522,7 +522,7 @@ public class LegacyCameraDevice implements AutoCloseable { return surfaceIds; } - static boolean containsSurfaceId(Surface s, List<Long> ids) { + static boolean containsSurfaceId(Surface s, Collection<Long> ids) { long id = getSurfaceId(s); return ids.contains(id); } diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java index 69c140b..edd8e4e 100644 --- a/core/java/android/hardware/camera2/legacy/RequestHolder.java +++ b/core/java/android/hardware/camera2/legacy/RequestHolder.java @@ -43,71 +43,6 @@ public class RequestHolder { private volatile boolean mFailed = false; /** - * Returns true if the given surface requires jpeg buffers. - * - * @param s a {@link android.view.Surface} to check. - * @return true if the surface requires a jpeg buffer. - */ - public static boolean jpegType(Surface s) - throws LegacyExceptionUtils.BufferQueueAbandonedException { - return LegacyCameraDevice.detectSurfaceType(s) == - CameraMetadataNative.NATIVE_JPEG_FORMAT; - } - - /** - * Returns true if the given surface requires non-jpeg buffer types. - * - * <p> - * "Jpeg buffer" refers to the buffers returned in the jpeg - * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee - * of the preview stream drawn to the surface - * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or - * equivalent methods. - * </p> - * @param s a {@link android.view.Surface} to check. - * @return true if the surface requires a non-jpeg buffer type. - */ - public static boolean previewType(Surface s) - throws LegacyExceptionUtils.BufferQueueAbandonedException { - return LegacyCameraDevice.detectSurfaceType(s) != - CameraMetadataNative.NATIVE_JPEG_FORMAT; - } - - /** - * Returns the number of surfaces targeted by the request that require jpeg buffers. - */ - private static int numJpegTargets(CaptureRequest request) { - int count = 0; - for (Surface s : request.getTargets()) { - try { - if (jpegType(s)) { - ++count; - } - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } - } - return count; - } - - /** - * Returns the number of surfaces targeted by the request that require non-jpeg buffers. - */ - private static int numPreviewTargets(CaptureRequest request) { - int count = 0; - for (Surface s : request.getTargets()) { - try { - if (previewType(s)) { - ++count; - } - } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { - Log.w(TAG, "Surface abandoned, skipping...", e); - } - } - return count; - } - - /** * A builder class for {@link RequestHolder} objects. * * <p> @@ -121,6 +56,7 @@ public class RequestHolder { private final boolean mRepeating; private final int mNumJpegTargets; private final int mNumPreviewTargets; + private final Collection<Long> mJpegSurfaceIds; /** * Construct a new {@link Builder} to generate {@link RequestHolder} objects. @@ -132,17 +68,81 @@ public class RequestHolder { * @param repeating {@code true} if the request is repeating. */ public Builder(int requestId, int subsequenceId, CaptureRequest request, - boolean repeating) { + boolean repeating, Collection<Long> jpegSurfaceIds) { checkNotNull(request, "request must not be null"); mRequestId = requestId; mSubsequenceId = subsequenceId; mRequest = request; mRepeating = repeating; + mJpegSurfaceIds = jpegSurfaceIds; mNumJpegTargets = numJpegTargets(mRequest); mNumPreviewTargets = numPreviewTargets(mRequest); } /** + * Returns true if the given surface requires jpeg buffers. + * + * @param s a {@link android.view.Surface} to check. + * @return true if the surface requires a jpeg buffer. + */ + private boolean jpegType(Surface s) + throws LegacyExceptionUtils.BufferQueueAbandonedException { + return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds); + } + + /** + * Returns true if the given surface requires non-jpeg buffer types. + * + * <p> + * "Jpeg buffer" refers to the buffers returned in the jpeg + * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee + * of the preview stream drawn to the surface + * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or + * equivalent methods. + * </p> + * @param s a {@link android.view.Surface} to check. + * @return true if the surface requires a non-jpeg buffer type. + */ + private boolean previewType(Surface s) + throws LegacyExceptionUtils.BufferQueueAbandonedException { + return !jpegType(s); + } + + /** + * Returns the number of surfaces targeted by the request that require jpeg buffers. + */ + private int numJpegTargets(CaptureRequest request) { + int count = 0; + for (Surface s : request.getTargets()) { + try { + if (jpegType(s)) { + ++count; + } + } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { + Log.d(TAG, "Surface abandoned, skipping...", e); + } + } + return count; + } + + /** + * Returns the number of surfaces targeted by the request that require non-jpeg buffers. + */ + private int numPreviewTargets(CaptureRequest request) { + int count = 0; + for (Surface s : request.getTargets()) { + try { + if (previewType(s)) { + ++count; + } + } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { + Log.d(TAG, "Surface abandoned, skipping...", e); + } + } + return count; + } + + /** * Build a new {@link RequestHolder} using with parameters generated from this * {@link Builder}. * diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java index 7598f99..c995029 100644 --- a/core/java/android/hardware/camera2/legacy/RequestQueue.java +++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java @@ -39,8 +39,11 @@ public class RequestQueue { private long mCurrentFrameNumber = 0; private long mCurrentRepeatingFrameNumber = INVALID_FRAME; private int mCurrentRequestId = 0; + private final List<Long> mJpegSurfaceIds; - public RequestQueue() {} + public RequestQueue(List<Long> jpegSurfaceIds) { + mJpegSurfaceIds = jpegSurfaceIds; + } /** * Return and remove the next burst on the queue. @@ -117,7 +120,7 @@ public class RequestQueue { public synchronized int submit(List<CaptureRequest> requests, boolean repeating, /*out*/LongParcelable frameNumber) { int requestId = mCurrentRequestId++; - BurstHolder burst = new BurstHolder(requestId, repeating, requests); + BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds); long ret = INVALID_FRAME; if (burst.isRepeating()) { Log.i(TAG, "Repeating capture request set."); diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index 4f8fe0b..a7ea89c 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -91,9 +91,11 @@ public class RequestThreadManager { private SurfaceTexture mPreviewTexture; private Camera.Parameters mParams; + private final List<Long> mJpegSurfaceIds = new ArrayList<>(); + private Size mIntermediateBufferSize; - private final RequestQueue mRequestQueue = new RequestQueue(); + private final RequestQueue mRequestQueue = new RequestQueue(mJpegSurfaceIds); private LegacyRequest mLastRequest = null; private SurfaceTexture mDummyTexture; private Surface mDummySurface; @@ -102,6 +104,10 @@ public class RequestThreadManager { private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview"); private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests"); + // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write + // limitations for (b/17379185). + private static final boolean USE_BLOB_FORMAT_OVERRIDE = true; + /** * Container object for Configure messages. */ @@ -189,18 +195,21 @@ public class RequestThreadManager { public void onPictureTaken(byte[] data, Camera camera) { Log.i(TAG, "Received jpeg."); Pair<RequestHolder, Long> captureInfo = mCaptureCollector.jpegProduced(); - RequestHolder holder = captureInfo.first; - long timestamp = captureInfo.second; - if (holder == null) { + if (captureInfo == null || captureInfo.first == null) { Log.e(TAG, "Dropping jpeg frame."); return; } + RequestHolder holder = captureInfo.first; + long timestamp = captureInfo.second; for (Surface s : holder.getHolderTargets()) { try { - if (RequestHolder.jpegType(s)) { + if (LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds)) { Log.i(TAG, "Producing jpeg buffer..."); - LegacyCameraDevice.setSurfaceDimens(s, data.length + - LegacyCameraDevice.nativeGetJpegFooterSize(), /*height*/1); + + int totalSize = data.length + LegacyCameraDevice.nativeGetJpegFooterSize(); + totalSize += ((totalSize - 1) & ~0x3) + 4; // align to next octonibble + + LegacyCameraDevice.setSurfaceDimens(s, totalSize, /*height*/1); LegacyCameraDevice.setNextTimestamp(s, timestamp); LegacyCameraDevice.produceFrame(s, data, data.length, /*height*/1, CameraMetadataNative.NATIVE_JPEG_FORMAT); @@ -316,8 +325,10 @@ public class RequestThreadManager { mGLThreadManager.ignoreNewFrames(); mGLThreadManager.waitUntilIdle(); } + resetJpegSurfaceFormats(mCallbackOutputs); mPreviewOutputs.clear(); mCallbackOutputs.clear(); + mJpegSurfaceIds.clear(); mPreviewTexture = null; int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING); @@ -329,6 +340,12 @@ public class RequestThreadManager { LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation); switch (format) { case CameraMetadataNative.NATIVE_JPEG_FORMAT: + if (USE_BLOB_FORMAT_OVERRIDE) { + // Override to RGBA_8888 format. + LegacyCameraDevice.setSurfaceFormat(s, + LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888); + } + mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s)); mCallbackOutputs.add(s); break; default: @@ -340,7 +357,14 @@ public class RequestThreadManager { } } } - mParams = mCamera.getParameters(); + try { + mParams = mCamera.getParameters(); + } catch (RuntimeException e) { + Log.e(TAG, "Received device exception: ", e); + mDeviceState.setError( + CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); + return; + } List<int[]> supportedFpsRanges = mParams.getSupportedPreviewFpsRange(); int[] bestRange = getPhotoPreviewFpsRange(supportedFpsRanges); @@ -426,8 +450,19 @@ public class RequestThreadManager { } mCamera.setParameters(mParams); - // TODO: configure the JPEG surface with some arbitrary size - // using LegacyCameraDevice.nativeConfigureSurface + } + + private void resetJpegSurfaceFormats(Collection<Surface> surfaces) { + if (!USE_BLOB_FORMAT_OVERRIDE || surfaces == null) { + return; + } + for(Surface s : surfaces) { + try { + LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB); + } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) { + Log.w(TAG, "Surface abandoned, skipping...", e); + } + } } /** @@ -459,9 +494,8 @@ public class RequestThreadManager { List<Size> configuredJpegSizes = new ArrayList<Size>(); for (Surface callbackSurface : callbackOutputs) { try { - int format = LegacyCameraDevice.detectSurfaceType(callbackSurface); - if (format != CameraMetadataNative.NATIVE_JPEG_FORMAT) { + if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) { continue; // Ignore non-JPEG callback formats } @@ -754,7 +788,14 @@ public class RequestThreadManager { if (DEBUG) { Log.d(TAG, "Params changed -- getting new Parameters from HAL."); } - mParams = mCamera.getParameters(); + try { + mParams = mCamera.getParameters(); + } catch (RuntimeException e) { + Log.e(TAG, "Received device exception: ", e); + mDeviceState.setError( + CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE); + break; + } // Update parameters to the latest that we think the camera is using mLastRequest.setParameters(mParams); @@ -821,6 +862,7 @@ public class RequestThreadManager { if (mCamera != null) { mCamera.release(); } + resetJpegSurfaceFormats(mCallbackOutputs); break; default: throw new AssertionError("Unhandled message " + msg.what + diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index c018c3e..c0d1d5e 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -581,6 +581,7 @@ public class SurfaceTextureRenderer { // If pixel conversions aren't handled by egl, use a pbuffer try { if (LegacyCameraDevice.needsConversion(s)) { + // Always override to YV12 output for YUV surface formats. LegacyCameraDevice.setSurfaceFormat(s, ImageFormat.YV12); EGLSurfaceHolder holder = new EGLSurfaceHolder(); holder.surface = s; diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index ba71605..362afba 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -17,6 +17,7 @@ package android.os; import android.util.Log; +import android.util.Slog; import com.android.internal.util.FastPrintWriter; import java.io.FileDescriptor; @@ -48,7 +49,7 @@ public class Binder implements IBinder { * of classes can potentially create leaks. */ private static final boolean FIND_POTENTIAL_LEAKS = false; - private static final String TAG = "Binder"; + static final String TAG = "Binder"; /** * Control whether dump() calls are allowed. @@ -385,7 +386,14 @@ public class Binder implements IBinder { super.finalize(); } } - + + static void checkParcel(Parcel parcel, String msg) { + if (parcel.dataSize() >= 800*1024) { + // Trying to send > 800k, this is way too much + Slog.wtfStack(TAG, msg + parcel.dataSize()); + } + } + private native final void init(); private native final void destroy(); @@ -424,6 +432,7 @@ public class Binder implements IBinder { reply.writeException(re); res = true; } + checkParcel(reply, "Unreasonably large binder reply buffer: "); reply.recycle(); data.recycle(); return res; @@ -433,13 +442,18 @@ public class Binder implements IBinder { final class BinderProxy implements IBinder { public native boolean pingBinder(); public native boolean isBinderAlive(); - + public IInterface queryLocalInterface(String descriptor) { return null; } - + + public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + Binder.checkParcel(data, "Unreasonably large binder buffer: "); + return transactNative(code, data, reply, flags); + } + public native String getInterfaceDescriptor() throws RemoteException; - public native boolean transact(int code, Parcel data, Parcel reply, + public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; public native void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException; diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index 7a46e40..b879c83 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.UserManager; +import android.text.TextUtils; import android.util.Log; import java.io.ByteArrayInputStream; @@ -333,9 +334,10 @@ public class RecoverySystem { throws IOException { String filename = packageFile.getCanonicalPath(); Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!"); - String arg = "--update_package=" + filename + - "\n--locale=" + Locale.getDefault().toString(); - bootCommand(context, arg); + + final String filenameArg = "--update_package=" + filename; + final String localeArg = "--locale=" + Locale.getDefault().toString(); + bootCommand(context, filenameArg, localeArg); } /** @@ -352,7 +354,18 @@ public class RecoverySystem { * @throws SecurityException if the current user is not allowed to wipe data. */ public static void rebootWipeUserData(Context context) throws IOException { - rebootWipeUserData(context, false); + rebootWipeUserData(context, false, context.getPackageName()); + } + + /** {@hide} */ + public static void rebootWipeUserData(Context context, String reason) throws IOException { + rebootWipeUserData(context, false, reason); + } + + /** {@hide} */ + public static void rebootWipeUserData(Context context, boolean shutdown) + throws IOException { + rebootWipeUserData(context, shutdown, context.getPackageName()); } /** @@ -373,8 +386,8 @@ public class RecoverySystem { * * @hide */ - public static void rebootWipeUserData(Context context, boolean shutdown) - throws IOException { + public static void rebootWipeUserData(Context context, boolean shutdown, String reason) + throws IOException { UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) { throw new SecurityException("Wiping data is not allowed for this user."); @@ -395,13 +408,18 @@ public class RecoverySystem { // Block until the ordered broadcast has completed. condition.block(); - String shutdownArg = ""; + String shutdownArg = null; if (shutdown) { - shutdownArg = "--shutdown_after\n"; + shutdownArg = "--shutdown_after"; + } + + String reasonArg = null; + if (!TextUtils.isEmpty(reason)) { + reasonArg = "--reason=" + sanitizeArg(reason); } - bootCommand(context, shutdownArg + "--wipe_data\n--locale=" + - Locale.getDefault().toString()); + final String localeArg = "--locale=" + Locale.getDefault().toString(); + bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg); } /** @@ -409,23 +427,38 @@ public class RecoverySystem { * @throws IOException if something goes wrong. */ public static void rebootWipeCache(Context context) throws IOException { - bootCommand(context, "--wipe_cache\n--locale=" + Locale.getDefault().toString()); + rebootWipeCache(context, context.getPackageName()); + } + + /** {@hide} */ + public static void rebootWipeCache(Context context, String reason) throws IOException { + String reasonArg = null; + if (!TextUtils.isEmpty(reason)) { + reasonArg = "--reason=" + sanitizeArg(reason); + } + + final String localeArg = "--locale=" + Locale.getDefault().toString(); + bootCommand(context, "--wipe_cache", reasonArg, localeArg); } /** * Reboot into the recovery system with the supplied argument. - * @param arg to pass to the recovery utility. + * @param args to pass to the recovery utility. * @throws IOException if something goes wrong. */ - private static void bootCommand(Context context, String arg) throws IOException { + private static void bootCommand(Context context, String... args) throws IOException { RECOVERY_DIR.mkdirs(); // In case we need it COMMAND_FILE.delete(); // In case it's not writable LOG_FILE.delete(); FileWriter command = new FileWriter(COMMAND_FILE); try { - command.write(arg); - command.write("\n"); + for (String arg : args) { + if (!TextUtils.isEmpty(arg)) { + command.write(arg); + command.write("\n"); + } + } } finally { command.close(); } @@ -470,5 +503,15 @@ public class RecoverySystem { return log; } + /** + * Internally, recovery treats each line of the command file as a separate + * argv, so we only need to protect against newlines and nulls. + */ + private static String sanitizeArg(String arg) { + arg = arg.replace('\0', '?'); + arg = arg.replace('\n', '?'); + return arg; + } + private void RecoverySystem() { } // Do not instantiate } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 440b1ec..ec4a53e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -978,6 +978,19 @@ public final class Settings { public static final String EXTRA_INPUT_METHOD_ID = "input_method_id"; /** + * Activity Extra: The device identifier to act upon. + * <p> + * This can be passed as an extra field in an Activity Intent with a single + * InputDeviceIdentifier. This field is used by some activities to jump straight into the + * settings for the given device. + * <p> + * Example: The {@link #INPUT_METHOD_SETTINGS} intent opens the keyboard layout dialog for the + * given device. + * @hide + */ + public static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier"; + + /** * @hide * Activity Extra: Enable or disable Airplane Mode. * <p> diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index b22fd9c..35fff74 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -478,7 +478,7 @@ public abstract class NotificationListenerService extends Service { public final int getCurrentInterruptionFilter() { if (!isBound()) return 0; try { - return getNotificationInterface().getHintsFromListener(mWrapper); + return getNotificationInterface().getInterruptionFilterFromListener(mWrapper); } catch (android.os.RemoteException ex) { Log.v(TAG, "Unable to contact notification manager", ex); return 0; diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java index d41aa67..6262fcb 100644 --- a/core/java/android/speech/tts/SynthesisRequest.java +++ b/core/java/android/speech/tts/SynthesisRequest.java @@ -61,7 +61,7 @@ public final class SynthesisRequest { /** * Gets the text which should be synthesized. - * @deprecated As of API level 20, replaced by {@link #getCharSequenceText}. + * @deprecated As of API level 21, replaced by {@link #getCharSequenceText}. */ @Deprecated public String getText() { diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 120c9e3..c59ca8a 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -575,7 +575,7 @@ public class TextToSpeech { * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) * @see TextToSpeech#getFeatures(java.util.Locale) * - * @deprecated Starting from API level 20, to select network synthesis, call + * @deprecated Starting from API level 21, to select network synthesis, call * ({@link TextToSpeech#getVoices()}, find a suitable network voice * ({@link Voice#isNetworkConnectionRequired()}) and pass it * to {@link TextToSpeech#setVoice(Voice)}). @@ -593,7 +593,7 @@ public class TextToSpeech { * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) * @see TextToSpeech#getFeatures(java.util.Locale) - * @deprecated Starting from API level 20, to select embedded synthesis, call + * @deprecated Starting from API level 21, to select embedded synthesis, call * ({@link TextToSpeech#getVoices()}, find a suitable embedded voice * ({@link Voice#isNetworkConnectionRequired()}) and pass it * to {@link TextToSpeech#setVoice(Voice)}). @@ -1015,7 +1015,7 @@ public class TextToSpeech { * * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. * - * @deprecated As of API level 20, replaced by + * @deprecated As of API level 21, replaced by * {@link #addEarcon(String, File)}. */ @Deprecated @@ -1124,7 +1124,7 @@ public class TextToSpeech { * engine named "com.svox.pico" if it is being used. * * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation. - * @deprecated As of API level 20, replaced by + * @deprecated As of API level 21, replaced by * {@link #speak(CharSequence, int, Bundle, String)}. */ @Deprecated @@ -1194,7 +1194,7 @@ public class TextToSpeech { * engine named "com.svox.pico" if it is being used. * * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation. - * @deprecated As of API level 20, replaced by + * @deprecated As of API level 21, replaced by * {@link #playEarcon(String, int, Bundle, String)}. */ @Deprecated @@ -1218,9 +1218,9 @@ public class TextToSpeech { * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. * @param utteranceId An unique identifier for this request. * - * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation. + * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilentUtterance operation. */ - public int playSilence(final long durationInMs, final int queueMode, + public int playSilentUtterance(final long durationInMs, final int queueMode, final String utteranceId) { return runAction(new Action<Integer>() { @Override @@ -1228,7 +1228,7 @@ public class TextToSpeech { return service.playSilence(getCallerIdentity(), durationInMs, queueMode, utteranceId); } - }, ERROR, "playSilence"); + }, ERROR, "playSilentUtterance"); } /** @@ -1252,13 +1252,13 @@ public class TextToSpeech { * engine named "com.svox.pico" if it is being used. * * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation. - * @deprecated As of API level 20, replaced by - * {@link #playSilence(long, int, String)}. + * @deprecated As of API level 21, replaced by + * {@link #playSilentUtterance(long, int, String)}. */ @Deprecated public int playSilence(final long durationInMs, final int queueMode, final HashMap<String, String> params) { - return playSilence(durationInMs, queueMode, + return playSilentUtterance(durationInMs, queueMode, params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID)); } @@ -1276,7 +1276,7 @@ public class TextToSpeech { * * @param locale The locale to query features for. * @return Set instance. May return {@code null} on error. - * @deprecated As of API level 20, please use voices. In order to query features of the voice, + * @deprecated As of API level 21, please use voices. In order to query features of the voice, * call {@link #getVoices()} to retrieve the list of available voices and * {@link Voice#getFeatures()} to retrieve the set of features. */ @@ -1421,7 +1421,7 @@ public class TextToSpeech { * * @return language, country (if any) and variant (if any) used by the client stored in a * Locale instance, or {@code null} on error. - * @deprecated As of API Level 20, use <code>getDefaultVoice().getLocale()</code> ({@link + * @deprecated As of API level 21, use <code>getDefaultVoice().getLocale()</code> ({@link * #getDefaultVoice()}) */ @Deprecated @@ -1476,7 +1476,7 @@ public class TextToSpeech { String variant = loc.getVariant(); - // As of API level 20, setLanguage is implemented using setVoice. + // As of API level 21, setLanguage is implemented using setVoice. // (which, in the default implementation, will call loadLanguage on the service // interface). @@ -1535,7 +1535,7 @@ public class TextToSpeech { * @return language, country (if any) and variant (if any) used by the client stored in a * Locale instance, or {@code null} on error. * - * @deprecated As of API level 20, please use <code>getVoice().getLocale()</code> + * @deprecated As of API level 21, please use <code>getVoice().getLocale()</code> * ({@link #getVoice()}). */ @Deprecated @@ -1831,7 +1831,7 @@ public class TextToSpeech { * something like "/sdcard/myappsounds/mysound.wav". * * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation. - * @deprecated As of API level 20, replaced by + * @deprecated As of API level 21, replaced by * {@link #synthesizeToFile(CharSequence, Bundle, File, String)}. */ @Deprecated diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index 079467a..9bb7f02 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -91,7 +91,7 @@ import java.util.Set; * The first three methods are siblings of the {@link #onGetLanguage}, * {@link #onIsLanguageAvailable} and {@link #onLoadLanguage} methods. The last one, * {@link #onGetDefaultVoiceNameFor(String, String, String)} is a link between locale and voice - * based methods. Since API level 20 {@link TextToSpeech#setLanguage} is implemented by + * based methods. Since API level 21 {@link TextToSpeech#setLanguage} is implemented by * calling {@link TextToSpeech#setVoice} with the voice returned by * {@link #onGetDefaultVoiceNameFor(String, String, String)}. * diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 946a3f7..c855e57 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -81,7 +81,7 @@ public class DisplayMetrics { /** * Intermediate density for screens that sit somewhere between - * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (560 dpi). + * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (640 dpi). * This is not a density that applications should target, instead relying * on the system to scale their {@link #DENSITY_XXXHIGH} assets for them. */ diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java index a283b91..baa133d 100644 --- a/core/java/android/view/AccessibilityInteractionController.java +++ b/core/java/android/view/AccessibilityInteractionController.java @@ -889,7 +889,13 @@ final class AccessibilityInteractionController { } } } else { - AccessibilityNodeInfo root = provider.createAccessibilityNodeInfo(virtualViewId); + final AccessibilityNodeInfo root; + if (virtualViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) { + root = provider.createAccessibilityNodeInfo(virtualViewId); + } else { + root = provider.createAccessibilityNodeInfo( + AccessibilityNodeProvider.HOST_VIEW_ID); + } if (root != null) { outInfos.add(root); if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) { diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 08160c8..dffcca4 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -434,11 +434,12 @@ public final class WindowManagerGlobal { boolean hasVisibleWindows = false; synchronized (mLock) { for (int i = mRoots.size() - 1; i >= 0; --i) { - if (mRoots.get(i).getHostVisibility() == View.VISIBLE - && mRoots.get(i).mAttachInfo.mHardwareRenderer != null) { + final ViewRootImpl root = mRoots.get(i); + if (root.mView != null && root.getHostVisibility() == View.VISIBLE + && root.mAttachInfo.mHardwareRenderer != null) { hasVisibleWindows = true; } else { - mRoots.get(i).destroyHardwareResources(); + root.destroyHardwareResources(); } } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 2b8b4dc..0439168 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1493,11 +1493,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te super.onInitializeAccessibilityNodeInfo(info); info.setClassName(AbsListView.class.getName()); if (isEnabled()) { - if (getFirstVisiblePosition() > 0) { + if (canScrollUp()) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); info.setScrollable(true); } - if (getLastVisiblePosition() < getCount() - 1) { + if (canScrollDown()) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); info.setScrollable(true); } @@ -2203,36 +2203,44 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te void updateScrollIndicators() { if (mScrollUp != null) { - boolean canScrollUp; - // 0th element is not visible - canScrollUp = mFirstPosition > 0; - - // ... Or top of 0th element is not visible - if (!canScrollUp) { - if (getChildCount() > 0) { - View child = getChildAt(0); - canScrollUp = child.getTop() < mListPadding.top; - } - } - - mScrollUp.setVisibility(canScrollUp ? View.VISIBLE : View.INVISIBLE); + mScrollUp.setVisibility(canScrollUp() ? View.VISIBLE : View.INVISIBLE); } if (mScrollDown != null) { - boolean canScrollDown; - int count = getChildCount(); + mScrollDown.setVisibility(canScrollDown() ? View.VISIBLE : View.INVISIBLE); + } + } - // Last item is not visible - canScrollDown = (mFirstPosition + count) < mItemCount; + private boolean canScrollUp() { + boolean canScrollUp; + // 0th element is not visible + canScrollUp = mFirstPosition > 0; - // ... Or bottom of the last element is not visible - if (!canScrollDown && count > 0) { - View child = getChildAt(count - 1); - canScrollDown = child.getBottom() > mBottom - mListPadding.bottom; + // ... Or top of 0th element is not visible + if (!canScrollUp) { + if (getChildCount() > 0) { + View child = getChildAt(0); + canScrollUp = child.getTop() < mListPadding.top; } + } + + return canScrollUp; + } - mScrollDown.setVisibility(canScrollDown ? View.VISIBLE : View.INVISIBLE); + private boolean canScrollDown() { + boolean canScrollDown; + int count = getChildCount(); + + // Last item is not visible + canScrollDown = (mFirstPosition + count) < mItemCount; + + // ... Or bottom of the last element is not visible + if (!canScrollDown && count > 0) { + View child = getChildAt(count - 1); + canScrollDown = child.getBottom() > mBottom - mListPadding.bottom; } + + return canScrollDown; } @Override |
