diff options
Diffstat (limited to 'core/java/android')
57 files changed, 1533 insertions, 110 deletions
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 82206ea..d50483e 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -460,6 +460,9 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene // If set this fragment is being retained across the current config change. boolean mRetaining; + // If set this fragment's loaders are being retained across the current config change. + boolean mRetainLoader; + // If set this fragment has menu items to contribute. boolean mHasMenu; @@ -2401,7 +2404,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false); } if (mLoaderManager != null) { - if (mRetaining) { + if (mRetainLoader) { mLoaderManager.doRetain(); } else { mLoaderManager.doStop(); diff --git a/core/java/android/app/FragmentController.java b/core/java/android/app/FragmentController.java index 28dadfa..1b45137 100644 --- a/core/java/android/app/FragmentController.java +++ b/core/java/android/app/FragmentController.java @@ -341,6 +341,7 @@ public class FragmentController { */ public void doLoaderStop(boolean retain) { mHost.doLoaderStop(retain); + mHost.mFragmentManager.setRetainLoader(retain); } /** diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 132ffef..51d6132 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -869,6 +869,17 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate } } + void setRetainLoader(boolean retain) { + if (mActive != null) { + for (int i=0; i<mActive.size(); i++) { + Fragment f = mActive.get(i); + if (f != null) { + f.mRetainLoader = retain; + } + } + } + } + void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) { if (DEBUG && false) Log.v(TAG, "moveToState: " + f diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 31d1ab7..5e8ad68 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -90,6 +90,9 @@ public class StatusBarManager { public static final int WINDOW_STATE_HIDING = 1; public static final int WINDOW_STATE_HIDDEN = 2; + public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0; + public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1; + private Context mContext; private IStatusBarService mService; private IBinder mToken = new Binder(); diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl new file mode 100644 index 0000000..36c71bf --- /dev/null +++ b/core/java/android/app/trust/IStrongAuthTracker.aidl @@ -0,0 +1,26 @@ +/* +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +package android.app.trust; + +/** + * Private API to be notified about strong auth changes + * + * {@hide} + */ +oneway interface IStrongAuthTracker { + void onStrongAuthRequiredChanged(int strongAuthRequired, int userId); +}
\ No newline at end of file diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl index 32951d9..2dea545 100644 --- a/core/java/android/app/trust/ITrustManager.aidl +++ b/core/java/android/app/trust/ITrustManager.aidl @@ -26,11 +26,9 @@ import android.app.trust.ITrustListener; interface ITrustManager { void reportUnlockAttempt(boolean successful, int userId); void reportEnabledTrustAgentsChanged(int userId); - void reportRequireCredentialEntry(int userId); void registerTrustListener(in ITrustListener trustListener); void unregisterTrustListener(in ITrustListener trustListener); void reportKeyguardShowingChanged(); boolean isDeviceLocked(int userId); boolean isDeviceSecure(int userId); - boolean hasUserAuthenticatedSinceBoot(int userId); } diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 8cab565..aff69f0 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -16,13 +16,19 @@ package android.app.trust; +import android.annotation.IntDef; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseIntArray; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * See {@link com.android.server.trust.TrustManagerService} @@ -73,21 +79,6 @@ public class TrustManager { } /** - * Reports that trust is disabled until credentials have been entered for user {@param userId}. - * - * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. - * - * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} - */ - public void reportRequireCredentialEntry(int userId) { - try { - mService.reportRequireCredentialEntry(userId); - } catch (RemoteException e) { - onError(e); - } - } - - /** * Reports that the visibility of the keyguard has changed. * * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. @@ -147,23 +138,6 @@ public class TrustManager { } } - /** - * Checks whether the specified user has been authenticated since the last boot. - * - * @param userId the user id of the user to check for - * @return true if the user has authenticated since boot, false otherwise - * - * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. - */ - public boolean hasUserAuthenticatedSinceBoot(int userId) { - try { - return mService.hasUserAuthenticatedSinceBoot(userId); - } catch (RemoteException e) { - onError(e); - return false; - } - } - private void onError(Exception e) { Log.e(TAG, "Error while calling TrustManagerService", e); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index b4af2c9..ae827e4 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4748,6 +4748,17 @@ public class PackageParser { return applicationInfo.isUpdatedSystemApp(); } + /** + * @hide + */ + public boolean canHaveOatDir() { + // The following app types CANNOT have oat directory + // - non-updated system apps + // - forward-locked apps or apps installed in ASEC containers + return (!isSystemApp() || isUpdatedSystemApp()) + && !isForwardLocked() && !applicationInfo.isExternalAsec(); + } + public String toString() { return "Package{" + Integer.toHexString(System.identityHashCode(this)) diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl index 0bb24bc..0e654d5 100644 --- a/core/java/android/hardware/ICameraServiceProxy.aidl +++ b/core/java/android/hardware/ICameraServiceProxy.aidl @@ -19,6 +19,8 @@ package android.hardware; /** * Binder interface for the camera service proxy running in system_server. * + * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h + * * @hide */ interface ICameraServiceProxy @@ -27,4 +29,9 @@ interface ICameraServiceProxy * Ping the service proxy to update the valid users for the camera service. */ oneway void pingForUserUpdate(); + + /** + * Update the status of a camera device + */ + oneway void notifyCameraState(String cameraId, int newCameraState); } diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index 46ffe36..766868d 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -138,6 +138,48 @@ public abstract class CameraCaptureSession implements AutoCloseable { */ public abstract void prepare(@NonNull Surface surface) throws CameraAccessException; + /** + * <p>Pre-allocate at most maxCount buffers for an output Surface.</p> + * + * <p>Like the {@link #prepare(Surface)} method, this method can be used to allocate output + * buffers for a given Surface. However, while the {@link #prepare(Surface)} method allocates + * the maximum possible buffer count, this method allocates at most maxCount buffers.</p> + * + * <p>If maxCount is greater than the possible maximum count (which is the sum of the buffer + * count requested by the creator of the Surface and the count requested by the camera device), + * only the possible maximum count is allocated, in which case the function acts exactly like + * {@link #prepare(Surface)}.</p> + * + * <p>The restrictions on when this method can be called are the same as for + * {@link #prepare(Surface)}.</p> + * + * <p>Repeated calls to this method are allowed, and a mix of {@link #prepare(Surface)} and + * this method is also allowed. Note that after the first call to {@link #prepare(Surface)}, + * subsequent calls to either prepare method are effectively no-ops. In addition, this method + * is not additive in terms of buffer count. This means calling it twice with maxCount = 2 + * will only allocate 2 buffers, not 4 (assuming the possible maximum is at least 2); to + * allocate two buffers on the first call and two on the second, the application needs to call + * prepare with prepare(surface, 2) and prepare(surface, 4).</p> + * + * @param maxCount the buffer count to try to allocate. If this is greater than the possible + * maximum for this output, the possible maximum is allocated instead. If + * maxCount buffers are already allocated, then prepare will do nothing. + * @param surface the output Surface for which buffers should be pre-allocated. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error. + * @throws IllegalStateException if this session is no longer active, either because the + * session was explicitly closed, a new session has been created + * or the camera device has been closed. + * @throws IllegalArgumentException if the Surface is invalid, not part of this Session, + * or has already been used as a target of a CaptureRequest in + * this session or immediately prior sessions without an + * intervening tearDown call. + * + * @hide + */ + public abstract void prepare(int maxCount, @NonNull Surface surface) + throws CameraAccessException; /** * <p>Free all buffers allocated for an output Surface.</p> diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 20b0be1..8f45f72 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -46,7 +46,7 @@ import java.lang.annotation.RetentionPolicy; * provide substantially improved capabilities over the older camera * API. Applications that target the limited level devices will run unchanged on * the full-level devices; if your application requires a full-level device for - * proper operation, declare the "android.hardware.camera2.full" feature in your + * proper operation, declare the "android.hardware.camera.level.full" feature in your * manifest.</p> * * @see CameraManager#openCamera diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index e965d65..3f566eb 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1545,7 +1545,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> /** * <p>Whether video stabilization is * active.</p> - * <p>Video stabilization automatically translates and scales images from + * <p>Video stabilization automatically warps images from * the camera in order to stabilize motion between consecutive frames.</p> * <p>If enabled, video stabilization can modify the * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p> @@ -1555,6 +1555,15 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * the video stabilization modes in the first several capture results may * still be "OFF", and it will become "ON" when the initialization is * done.</p> + * <p>In addition, not all recording sizes or frame rates may be supported for + * stabilization by a device that reports stabilization support. It is guaranteed + * that an output targeting a MediaRecorder or MediaCodec will be stabilized if + * the recording resolution is less than or equal to 1920 x 1080 (width less than + * or equal to 1920, height less than or equal to 1080), and the recording + * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult + * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return + * OFF if the recording output is not stabilized, or if there are no output + * Surface types that can be stabilized.</p> * <p>If a camera device supports both this mode and OIS * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may * produce undesirable interaction, so it is recommended not to enable @@ -1566,6 +1575,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>> * </ul></p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 46eddb3..b3acf2b 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2056,7 +2056,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { /** * <p>Whether video stabilization is * active.</p> - * <p>Video stabilization automatically translates and scales images from + * <p>Video stabilization automatically warps images from * the camera in order to stabilize motion between consecutive frames.</p> * <p>If enabled, video stabilization can modify the * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p> @@ -2066,6 +2066,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * the video stabilization modes in the first several capture results may * still be "OFF", and it will become "ON" when the initialization is * done.</p> + * <p>In addition, not all recording sizes or frame rates may be supported for + * stabilization by a device that reports stabilization support. It is guaranteed + * that an output targeting a MediaRecorder or MediaCodec will be stabilized if + * the recording resolution is less than or equal to 1920 x 1080 (width less than + * or equal to 1920, height less than or equal to 1080), and the recording + * frame rate is less than or equal to 30fps. At other sizes, the CaptureResult + * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return + * OFF if the recording output is not stabilized, or if there are no output + * Surface types that can be stabilized.</p> * <p>If a camera device supports both this mode and OIS * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may * produce undesirable interaction, so it is recommended not to enable @@ -2077,6 +2086,7 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * </ul></p> * <p>This key is available on all devices.</p> * + * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE * @see CaptureRequest#SCALER_CROP_REGION * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 7cb3673..c9c9abc 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -102,4 +102,6 @@ interface ICameraDeviceUser int prepare(int streamId); int tearDown(int streamId); + + int prepare2(int maxCount, int streamId); } diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index d325c77..5573896 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -146,6 +146,11 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession } @Override + public void prepare(int maxCount, Surface surface) throws CameraAccessException { + mDeviceImpl.prepare(maxCount, surface); + } + + @Override public void tearDown(Surface surface) throws CameraAccessException { mDeviceImpl.tearDown(surface); } diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java index a920e2b..8cd1da5 100644 --- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java @@ -169,6 +169,11 @@ public class CameraConstrainedHighSpeedCaptureSessionImpl } @Override + public void prepare(int maxCount, Surface surface) throws CameraAccessException { + mSessionImpl.prepare(maxCount, surface); + } + + @Override public void tearDown(Surface surface) throws CameraAccessException { mSessionImpl.tearDown(surface); } diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 91d623e..6e02df1 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -679,6 +679,33 @@ public class CameraDeviceImpl extends CameraDevice { } } + public void prepare(int maxCount, Surface surface) throws CameraAccessException { + if (surface == null) throw new IllegalArgumentException("Surface is null"); + if (maxCount <= 0) throw new IllegalArgumentException("Invalid maxCount given: " + + maxCount); + + synchronized(mInterfaceLock) { + int streamId = -1; + for (int i = 0; i < mConfiguredOutputs.size(); i++) { + if (surface == mConfiguredOutputs.valueAt(i).getSurface()) { + streamId = mConfiguredOutputs.keyAt(i); + break; + } + } + if (streamId == -1) { + throw new IllegalArgumentException("Surface is not part of this session"); + } + try { + mRemoteDevice.prepare2(maxCount, streamId); + } catch (CameraRuntimeException e) { + throw e.asChecked(); + } catch (RemoteException e) { + // impossible + return; + } + } + } + public void tearDown(Surface surface) throws CameraAccessException { if (surface == null) throw new IllegalArgumentException("Surface is null"); diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java index e20eaa7..6b8e113 100644 --- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java +++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java @@ -636,6 +636,11 @@ public class CameraDeviceUserShim implements ICameraDeviceUser { return CameraBinderDecorator.NO_ERROR; } + public int prepare2(int maxCount, int streamId) { + // We don't support this in LEGACY mode. + return prepare(streamId); + } + public int tearDown(int streamId) { if (DEBUG) { Log.d(TAG, "tearDown called."); diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 7aa9787..a04cdce 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -19,7 +19,9 @@ package android.hardware.camera2.params; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.utils.HashCodeHelpers; +import android.hardware.camera2.utils.SurfaceUtils; import android.util.Log; +import android.util.Size; import android.view.Surface; import android.os.Parcel; import android.os.Parcelable; @@ -66,9 +68,7 @@ public final class OutputConfiguration implements Parcelable { * */ public OutputConfiguration(Surface surface) { - checkNotNull(surface, "Surface must not be null"); - mSurface = surface; - mRotation = ROTATION_0; + this(surface, ROTATION_0); } /** @@ -94,6 +94,9 @@ public final class OutputConfiguration implements Parcelable { checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); mSurface = surface; mRotation = rotation; + mConfiguredSize = SurfaceUtils.getSurfaceSize(surface); + mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface); + mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface); } /** @@ -106,6 +109,9 @@ public final class OutputConfiguration implements Parcelable { checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant"); mSurface = surface; mRotation = rotation; + mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface); + mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface); + mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface); } /** @@ -163,8 +169,9 @@ public final class OutputConfiguration implements Parcelable { /** * Check if this {@link OutputConfiguration} is equal to another {@link OutputConfiguration}. * - * <p>Two output configurations are only equal if and only if the underlying surface and - * all other configuration parameters are equal. </p> + * <p>Two output configurations are only equal if and only if the underlying surfaces, surface + * properties (width, height, format, dataspace) when the output configurations are created, + * and all other configuration parameters are equal. </p> * * @return {@code true} if the objects were equal, {@code false} otherwise */ @@ -176,7 +183,11 @@ public final class OutputConfiguration implements Parcelable { return true; } else if (obj instanceof OutputConfiguration) { final OutputConfiguration other = (OutputConfiguration) obj; - return (mSurface == other.mSurface && mRotation == other.mRotation); + return mSurface == other.mSurface && + mRotation == other.mRotation && + mConfiguredSize.equals(other.mConfiguredSize) && + mConfiguredFormat == other.mConfiguredFormat && + mConfiguredDataspace == other.mConfiguredDataspace; } return false; } @@ -192,4 +203,9 @@ public final class OutputConfiguration implements Parcelable { private static final String TAG = "OutputConfiguration"; private final Surface mSurface; private final int mRotation; + + // The size, format, and dataspace of the surface when OutputConfiguration is created. + private final Size mConfiguredSize; + private final int mConfiguredFormat; + private final int mConfiguredDataspace; } diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 21ba7bd..121a187 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -359,6 +359,14 @@ public final class DisplayManagerGlobal { } } + public void requestColorTransform(int displayId, int colorTransformId) { + try { + mDm.requestColorTransform(displayId, colorTransformId); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to request color transform.", ex); + } + } + public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection, String name, int width, int height, int densityDpi, Surface surface, int flags, VirtualDisplay.Callback callback, Handler handler) { diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 4486dd4..8a1abf1 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -59,6 +59,9 @@ interface IDisplayManager { // No permissions required. WifiDisplayStatus getWifiDisplayStatus(); + // Requires CONFIGURE_DISPLAY_COLOR_TRANSFORM + void requestColorTransform(int displayId, int colorTransformId); + // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate // MediaProjection token for certain combinations of flags. int createVirtualDisplay(in IVirtualDisplayCallback callback, diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 6e29989..122df23 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -27,6 +27,7 @@ import android.os.CancellationSignal.OnCancelListener; import android.os.Handler; import android.os.IBinder; import android.os.Looper; +import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; import android.security.keystore.AndroidKeyStoreProvider; @@ -392,6 +393,18 @@ public class FingerprintManager { }; /** + * @hide + */ + public static abstract class LockoutResetCallback { + + /** + * Called when lockout period expired and clients are allowed to listen for fingerprint + * again. + */ + public void onLockoutReset() { } + }; + + /** * Request authentication of a crypto object. This call warms up the fingerprint hardware * and starts scanning for a fingerprint. It terminates when * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or @@ -668,6 +681,60 @@ public class FingerprintManager { return 0; } + /** + * Reset the lockout timer when asked to do so by keyguard. + * + * @param token an opaque token returned by password confirmation. + * + * @hide + */ + public void resetTimeout(byte[] token) { + if (mService != null) { + try { + mService.resetTimeout(token); + } catch (RemoteException e) { + Log.v(TAG, "Remote exception in resetTimeout(): ", e); + } + } else { + Log.w(TAG, "resetTimeout(): Service not connected!"); + } + } + + /** + * @hide + */ + public void addLockoutResetCallback(final LockoutResetCallback callback) { + if (mService != null) { + try { + final PowerManager powerManager = mContext.getSystemService(PowerManager.class); + mService.addLockoutResetCallback( + new IFingerprintServiceLockoutResetCallback.Stub() { + + @Override + public void onLockoutReset(long deviceId) throws RemoteException { + final PowerManager.WakeLock wakeLock = powerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback"); + wakeLock.acquire(); + mHandler.post(new Runnable() { + @Override + public void run() { + try { + callback.onLockoutReset(); + } finally { + wakeLock.release(); + } + } + }); + } + }); + } catch (RemoteException e) { + Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e); + } + } else { + Log.w(TAG, "addLockoutResetCallback(): Service not connected!"); + } + } + private class MyHandler extends Handler { private MyHandler(Context context) { super(context.getMainLooper()); @@ -677,6 +744,7 @@ public class FingerprintManager { super(looper); } + @Override public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: @@ -707,7 +775,7 @@ public class FingerprintManager { if (fingerId != reqFingerId) { Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId); } - if (fingerId != reqFingerId) { + if (groupId != reqGroupId) { Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId); } mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 5e233b8..690a751 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -17,6 +17,7 @@ package android.hardware.fingerprint; import android.os.Bundle; import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback; import android.hardware.fingerprint.Fingerprint; import java.util.List; @@ -68,4 +69,10 @@ interface IFingerprintService { // Gets the authenticator ID for fingerprint long getAuthenticatorId(String opPackageName); + + // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password) + void resetTimeout(in byte [] cryptoToken); + + // Add a callback which gets notified when the fingerprint lockout period expired. + void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl new file mode 100644 index 0000000..e027a2b --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.fingerprint; + +import android.hardware.fingerprint.Fingerprint; +import android.os.Bundle; +import android.os.UserHandle; + +/** + * Callback when lockout period expired and clients are allowed to authenticate again. + * @hide + */ +interface IFingerprintServiceLockoutResetCallback { + + /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */ + void onLockoutReset(long deviceId); +} diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 465d142..c8b45c7 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -19,6 +19,7 @@ package android.hardware.input; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.KeyboardLayout; import android.hardware.input.IInputDevicesChangedListener; +import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.TouchCalibration; import android.os.IBinder; import android.view.InputDevice; @@ -60,6 +61,9 @@ interface IInputManager { // Registers an input devices changed listener. void registerInputDevicesChangedListener(IInputDevicesChangedListener listener); + // Registers a tablet mode change listener + void registerTabletModeChangedListener(ITabletModeChangedListener listener); + // Input device vibrator control. void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token); void cancelVibrate(int deviceId, IBinder token); diff --git a/core/java/android/hardware/input/ITabletModeChangedListener.aidl b/core/java/android/hardware/input/ITabletModeChangedListener.aidl new file mode 100644 index 0000000..a8559a7 --- /dev/null +++ b/core/java/android/hardware/input/ITabletModeChangedListener.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.input; + +/** @hide */ +interface ITabletModeChangedListener { + /* Called when the device enters or exits tablet mode. */ + oneway void onTabletModeChanged(long whenNanos, boolean inTabletMode); +} diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 444f020..a754d6b 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -16,6 +16,7 @@ package android.hardware.input; +import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import android.annotation.SdkConstant; @@ -29,6 +30,7 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemClock; import android.os.Vibrator; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -38,6 +40,7 @@ import android.view.InputDevice; import android.view.InputEvent; import java.util.ArrayList; +import java.util.List; /** * Provides information about input devices and available key layouts. @@ -67,6 +70,11 @@ public final class InputManager { private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners = new ArrayList<InputDeviceListenerDelegate>(); + // Guarded by mTabletModeLock + private final Object mTabletModeLock = new Object(); + private TabletModeChangedListener mTabletModeChangedListener; + private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners; + /** * Broadcast Action: Query available keyboard layouts. * <p> @@ -331,6 +339,72 @@ public final class InputManager { } /** + * Register a tablet mode changed listener. + * + * @param listener The listener to register. + * @param handler The handler on which the listener should be invoked, or null + * if the listener should be invoked on the calling thread's looper. + * @hide + */ + public void registerOnTabletModeChangedListener( + OnTabletModeChangedListener listener, Handler handler) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + synchronized (mTabletModeLock) { + if (mOnTabletModeChangedListeners == null) { + initializeTabletModeListenerLocked(); + } + int idx = findOnTabletModeChangedListenerLocked(listener); + if (idx < 0) { + OnTabletModeChangedListenerDelegate d = + new OnTabletModeChangedListenerDelegate(listener, handler); + mOnTabletModeChangedListeners.add(d); + } + } + } + + /** + * Unregister a tablet mode changed listener. + * + * @param listener The listener to unregister. + * @hide + */ + public void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + synchronized (mTabletModeLock) { + int idx = findOnTabletModeChangedListenerLocked(listener); + if (idx >= 0) { + OnTabletModeChangedListenerDelegate d = mOnTabletModeChangedListeners.remove(idx); + d.removeCallbacksAndMessages(null); + } + } + } + + private void initializeTabletModeListenerLocked() { + final TabletModeChangedListener listener = new TabletModeChangedListener(); + try { + mIm.registerTabletModeChangedListener(listener); + } catch (RemoteException ex) { + throw new RuntimeException("Could not register tablet mode changed listener", ex); + } + mTabletModeChangedListener = listener; + mOnTabletModeChangedListeners = new ArrayList<>(); + } + + private int findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener) { + final int N = mOnTabletModeChangedListeners.size(); + for (int i = 0; i < N; i++) { + if (mOnTabletModeChangedListeners.get(i).mListener == listener) { + return i; + } + } + return -1; + } + + /** * Gets information about all supported keyboard layouts. * <p> * The input manager consults the built-in keyboard layouts as well @@ -769,6 +843,22 @@ public final class InputManager { return false; } + + private void onTabletModeChanged(long whenNanos, boolean inTabletMode) { + if (DEBUG) { + Log.d(TAG, "Received tablet mode changed: " + + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode); + } + synchronized (mTabletModeLock) { + final int N = mOnTabletModeChangedListeners.size(); + for (int i = 0; i < N; i++) { + OnTabletModeChangedListenerDelegate listener = + mOnTabletModeChangedListeners.get(i); + listener.sendTabletModeChanged(whenNanos, inTabletMode); + } + } + } + /** * Gets a vibrator service associated with an input device, assuming it has one. * @return The vibrator, never null. @@ -838,6 +928,57 @@ public final class InputManager { } } + /** @hide */ + public interface OnTabletModeChangedListener { + /** + * Called whenever the device goes into or comes out of tablet mode. + * + * @param whenNanos The time at which the device transitioned into or + * out of tablet mode. This is given in nanoseconds in the + * {@link SystemClock#uptimeMillis} time base. + */ + void onTabletModeChanged(long whenNanos, boolean inTabletMode); + } + + private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub { + @Override + public void onTabletModeChanged(long whenNanos, boolean inTabletMode) { + InputManager.this.onTabletModeChanged(whenNanos, inTabletMode); + } + } + + private static final class OnTabletModeChangedListenerDelegate extends Handler { + private static final int MSG_TABLET_MODE_CHANGED = 0; + + public final OnTabletModeChangedListener mListener; + + public OnTabletModeChangedListenerDelegate( + OnTabletModeChangedListener listener, Handler handler) { + super(handler != null ? handler.getLooper() : Looper.myLooper()); + mListener = listener; + } + + public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = (int) (whenNanos & 0xFFFFFFFF); + args.argi2 = (int) (whenNanos >> 32); + args.arg1 = (Boolean) inTabletMode; + obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget(); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_TABLET_MODE_CHANGED: + SomeArgs args = (SomeArgs) msg.obj; + long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32); + boolean inTabletMode = (boolean) args.arg1; + mListener.onTabletModeChanged(whenNanos, inTabletMode); + break; + } + } + } + private final class InputDeviceVibrator extends Vibrator { private final int mDeviceId; private final Binder mToken; diff --git a/core/java/android/hardware/location/ActivityRecognitionHardware.java b/core/java/android/hardware/location/ActivityRecognitionHardware.java index 5d3953a..8acd1ff 100644 --- a/core/java/android/hardware/location/ActivityRecognitionHardware.java +++ b/core/java/android/hardware/location/ActivityRecognitionHardware.java @@ -30,20 +30,34 @@ import android.util.Log; * @hide */ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.Stub { - private static final String TAG = "ActivityRecognitionHardware"; + private static final String TAG = "ActivityRecognitionHW"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE; + private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '" + + HARDWARE_PERMISSION + "' not granted to access ActivityRecognitionHardware"; + private static final int INVALID_ACTIVITY_TYPE = -1; private static final int NATIVE_SUCCESS_RESULT = 0; + private static final int EVENT_TYPE_DISABLED = 0; + private static final int EVENT_TYPE_ENABLED = 1; + + /** + * Contains the number of supported Event Types. + * + * NOTE: increment this counter every time a new EVENT_TYPE_ is added to + * com.android.location.provider.ActivityRecognitionProvider + */ + private static final int EVENT_TYPE_COUNT = 3; - private static ActivityRecognitionHardware sSingletonInstance = null; + private static ActivityRecognitionHardware sSingletonInstance; private static final Object sSingletonInstanceLock = new Object(); private final Context mContext; + private final int mSupportedActivitiesCount; private final String[] mSupportedActivities; - - private final RemoteCallbackList<IActivityRecognitionHardwareSink> mSinks = - new RemoteCallbackList<IActivityRecognitionHardwareSink>(); + private final int[][] mSupportedActivitiesEnabledEvents; + private final SinkList mSinks = new SinkList(); private static class Event { public int activity; @@ -56,6 +70,8 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St mContext = context; mSupportedActivities = fetchSupportedActivities(); + mSupportedActivitiesCount = mSupportedActivities.length; + mSupportedActivitiesEnabledEvents = new int[mSupportedActivitiesCount][EVENT_TYPE_COUNT]; } public static ActivityRecognitionHardware getInstance(Context context) { @@ -107,7 +123,11 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St } int result = nativeEnableActivityEvent(activityType, eventType, reportLatencyNs); - return result == NATIVE_SUCCESS_RESULT; + if (result == NATIVE_SUCCESS_RESULT) { + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_ENABLED; + return true; + } + return false; } @Override @@ -120,7 +140,11 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St } int result = nativeDisableActivityEvent(activityType, eventType); - return result == NATIVE_SUCCESS_RESULT; + if (result == NATIVE_SUCCESS_RESULT) { + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED; + return true; + } + return false; } @Override @@ -135,7 +159,7 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St */ private void onActivityChanged(Event[] events) { if (events == null || events.length == 0) { - Log.d(TAG, "No events to broadcast for onActivityChanged."); + if (DEBUG) Log.d(TAG, "No events to broadcast for onActivityChanged."); return; } @@ -161,7 +185,6 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St } } mSinks.finishBroadcast(); - } private String getActivityName(int activityType) { @@ -193,10 +216,7 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St } private void checkPermissions() { - String message = String.format( - "Permission '%s' not granted to access ActivityRecognitionHardware", - HARDWARE_PERMISSION); - mContext.enforceCallingPermission(HARDWARE_PERMISSION, message); + mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE); } private String[] fetchSupportedActivities() { @@ -208,6 +228,39 @@ public class ActivityRecognitionHardware extends IActivityRecognitionHardware.St return new String[0]; } + private class SinkList extends RemoteCallbackList<IActivityRecognitionHardwareSink> { + @Override + public void onCallbackDied(IActivityRecognitionHardwareSink callback) { + int callbackCount = mSinks.getRegisteredCallbackCount(); + if (DEBUG) Log.d(TAG, "RegisteredCallbackCount: " + callbackCount); + if (callbackCount != 0) { + return; + } + // currently there is only one client for this, so if all its sinks have died, we clean + // up after them, this ensures that the AR HAL is not out of sink + for (int activity = 0; activity < mSupportedActivitiesCount; ++activity) { + for (int event = 0; event < EVENT_TYPE_COUNT; ++event) { + disableActivityEventIfEnabled(activity, event); + } + } + } + + private void disableActivityEventIfEnabled(int activityType, int eventType) { + if (mSupportedActivitiesEnabledEvents[activityType][eventType] != EVENT_TYPE_ENABLED) { + return; + } + + int result = nativeDisableActivityEvent(activityType, eventType); + mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED; + String message = String.format( + "DisableActivityEvent: activityType=%d, eventType=%d, result=%d", + activityType, + eventType, + result); + Log.e(TAG, message); + } + } + // native bindings static { nativeClassInit(); } diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl new file mode 100644 index 0000000..d2c3d75 --- /dev/null +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/license/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.location; + +import android.hardware.location.IActivityRecognitionHardware; + +/** + * Activity Recognition Hardware client interface. + * This interface can be used to receive interfaces to implementations of + * {@link IActivityRecognitionHardware}. + * + * @hide + */ +interface IActivityRecognitionHardwareClient { + /** + * Hardware Activity-Recognition availability event. + * + * @param isSupported whether the platform has hardware support for the feature + * @param instance the available instance to provide access to the feature + */ + void onAvailabilityChanged(in boolean isSupported, in IActivityRecognitionHardware instance); +} diff --git a/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl b/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl index 0507f52..12e3117 100644 --- a/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl +++ b/core/java/android/hardware/location/IActivityRecognitionHardwareWatcher.aidl @@ -22,6 +22,8 @@ import android.hardware.location.IActivityRecognitionHardware; * Activity Recognition Hardware watcher. This interface can be used to receive interfaces to * implementations of {@link IActivityRecognitionHardware}. * + * @deprecated use {@link IActivityRecognitionHardwareClient} instead. + * @hide */ interface IActivityRecognitionHardwareWatcher { @@ -29,4 +31,4 @@ interface IActivityRecognitionHardwareWatcher { * Hardware Activity-Recognition availability event. */ void onInstanceChanged(in IActivityRecognitionHardware instance); -}
\ No newline at end of file +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 15016c2..11e0b48 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -102,6 +102,16 @@ public class ConnectivityManager { public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; /** + * A temporary hack until SUPL system can get off the legacy APIS. + * They do too many network requests and the long list of apps listening + * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive. + * Use this bcast intent instead for SUPL requests. + * @hide + */ + public static final String CONNECTIVITY_ACTION_SUPL = + "android.net.conn.CONNECTIVITY_CHANGE_SUPL"; + + /** * The device has connected to a network that has presented a captive * portal, which is blocking Internet connectivity. The user was presented * with a notification that network sign in is required, @@ -1049,11 +1059,13 @@ public class ConnectivityManager { type = "enableDUN"; result = TYPE_MOBILE_DUN; } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { - type = "enableSUPL"; + type = "enableSUPL"; result = TYPE_MOBILE_SUPL; - } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { - type = "enableMMS"; - result = TYPE_MOBILE_MMS; + // back out this hack for mms as they no longer need this and it's causing + // device slowdowns - b/23350688 (note, supl still needs this) + //} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { + // type = "enableMMS"; + // result = TYPE_MOBILE_MMS; } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { type = "enableHIPRI"; result = TYPE_MOBILE_HIPRI; @@ -1190,6 +1202,144 @@ public class ConnectivityManager { return true; } + /** @hide */ + public static class PacketKeepaliveCallback { + /** The requested keepalive was successfully started. */ + public void onStarted() {} + /** The keepalive was successfully stopped. */ + public void onStopped() {} + /** An error occurred. */ + public void onError(int error) {} + } + + /** + * Allows applications to request that the system periodically send specific packets on their + * behalf, using hardware offload to save battery power. + * + * To request that the system send keepalives, call one of the methods that return a + * {@link ConnectivityManager.PacketKeepalive} object, such as {@link #startNattKeepalive}, + * passing in a non-null callback. If the callback is successfully started, the callback's + * {@code onStarted} method will be called. If an error occurs, {@code onError} will be called, + * specifying one of the {@code ERROR_*} constants in this class. + * + * To stop an existing keepalive, call {@link stop}. The system will call {@code onStopped} if + * the operation was successfull or {@code onError} if an error occurred. + * + * @hide + */ + public class PacketKeepalive { + + private static final String TAG = "PacketKeepalive"; + + /** @hide */ + public static final int SUCCESS = 0; + + /** @hide */ + public static final int NO_KEEPALIVE = -1; + + /** @hide */ + public static final int BINDER_DIED = -10; + + /** The specified {@code Network} is not connected. */ + public static final int ERROR_INVALID_NETWORK = -20; + /** The specified IP addresses are invalid. For example, the specified source IP address is + * not configured on the specified {@code Network}. */ + public static final int ERROR_INVALID_IP_ADDRESS = -21; + /** The requested port is invalid. */ + public static final int ERROR_INVALID_PORT = -22; + /** The packet length is invalid (e.g., too long). */ + public static final int ERROR_INVALID_LENGTH = -23; + /** The packet transmission interval is invalid (e.g., too short). */ + public static final int ERROR_INVALID_INTERVAL = -24; + + /** The hardware does not support this request. */ + public static final int ERROR_HARDWARE_UNSUPPORTED = -30; + /** The hardware returned an error. */ + public static final int ERROR_HARDWARE_ERROR = -31; + + public static final int NATT_PORT = 4500; + + private final Network mNetwork; + private final PacketKeepaliveCallback mCallback; + private final Looper mLooper; + private final Messenger mMessenger; + + private volatile Integer mSlot; + + void stopLooper() { + mLooper.quit(); + } + + public void stop() { + try { + mService.stopKeepalive(mNetwork, mSlot); + } catch (RemoteException e) { + Log.e(TAG, "Error stopping packet keepalive: ", e); + stopLooper(); + } + } + + private PacketKeepalive(Network network, PacketKeepaliveCallback callback) { + checkNotNull(network, "network cannot be null"); + checkNotNull(callback, "callback cannot be null"); + mNetwork = network; + mCallback = callback; + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mLooper = thread.getLooper(); + mMessenger = new Messenger(new Handler(mLooper) { + @Override + public void handleMessage(Message message) { + switch (message.what) { + case NetworkAgent.EVENT_PACKET_KEEPALIVE: + int error = message.arg2; + try { + if (error == SUCCESS) { + if (mSlot == null) { + mSlot = message.arg1; + mCallback.onStarted(); + } else { + mSlot = null; + stopLooper(); + mCallback.onStopped(); + } + } else { + stopLooper(); + mCallback.onError(error); + } + } catch (Exception e) { + Log.e(TAG, "Exception in keepalive callback(" + error + ")", e); + } + break; + default: + Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what)); + break; + } + } + }); + } + } + + /** + * Starts an IPsec NAT-T keepalive packet with the specified parameters. + * + * @hide + */ + public PacketKeepalive startNattKeepalive( + Network network, int intervalSeconds, PacketKeepaliveCallback callback, + InetAddress srcAddr, int srcPort, InetAddress dstAddr) { + final PacketKeepalive k = new PacketKeepalive(network, callback); + try { + mService.startNattKeepalive(network, intervalSeconds, k.mMessenger, new Binder(), + srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress()); + } catch (RemoteException e) { + Log.e(TAG, "Error starting packet keepalive: ", e); + k.stopLooper(); + return null; + } + return k; + } + /** * Ensure that a network route exists to deliver traffic to the specified * host via the specified network interface. An attempt to add a route that @@ -2136,6 +2286,7 @@ public class ConnectivityManager { private final AtomicInteger mRefCount; private static final String TAG = "ConnectivityManager.CallbackHandler"; private final ConnectivityManager mCm; + private static final boolean DBG = false; CallbackHandler(Looper looper, HashMap<NetworkRequest, NetworkCallback>callbackMap, AtomicInteger refCount, ConnectivityManager cm) { @@ -2147,7 +2298,7 @@ public class ConnectivityManager { @Override public void handleMessage(Message message) { - Log.d(TAG, "CM callback handler got msg " + message.what); + if (DBG) Log.d(TAG, "CM callback handler got msg " + message.what); NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class); Network network = (Network) getObject(message, Network.class); switch (message.what) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 523dfe1..c6de7a5 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -165,4 +165,9 @@ interface IConnectivityManager boolean setUnderlyingNetworksForVpn(in Network[] networks); void factoryReset(); + + void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger, + in IBinder binder, String srcAddr, int srcPort, String dstAddr); + + void stopKeepalive(in Network network, int slot); } diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java index 88fb014..2283004 100644 --- a/core/java/android/net/IpReachabilityMonitor.java +++ b/core/java/android/net/IpReachabilityMonitor.java @@ -18,6 +18,7 @@ package android.net; import com.android.internal.annotations.GuardedBy; +import android.content.Context; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties.ProvisioningChange; @@ -31,6 +32,7 @@ import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdaCacheInfo; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlMsgHdr; +import android.os.PowerManager; import android.os.SystemClock; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; @@ -74,6 +76,7 @@ public class IpReachabilityMonitor { } private final Object mLock = new Object(); + private final PowerManager.WakeLock mWakeLock; private final String mInterfaceName; private final int mInterfaceIndex; private final Callback mCallback; @@ -136,7 +139,8 @@ public class IpReachabilityMonitor { return returnValue; } - public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException { + public IpReachabilityMonitor(Context context, String ifName, Callback callback) + throws IllegalArgumentException { mInterfaceName = ifName; int ifIndex = -1; try { @@ -145,6 +149,8 @@ public class IpReachabilityMonitor { } catch (SocketException | NullPointerException e) { throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e); } + mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName); mCallback = callback; mNetlinkSocketObserver = new NetlinkSocketObserver(); mObserverThread = new Thread(mNetlinkSocketObserver); @@ -291,6 +297,17 @@ public class IpReachabilityMonitor { synchronized (mLock) { ipProbeList.addAll(mIpWatchList.keySet()); } + + if (!ipProbeList.isEmpty() && stillRunning()) { + // Keep the CPU awake long enough to allow all ARP/ND + // probes a reasonable chance at success. See b/23197666. + // + // The wakelock we use is (by default) refcounted, and this version + // of acquire(timeout) queues a release message to keep acquisitions + // and releases balanced. + mWakeLock.acquire(getProbeWakeLockDuration()); + } + for (InetAddress target : ipProbeList) { if (!stillRunning()) { break; @@ -299,6 +316,22 @@ public class IpReachabilityMonitor { } } + private long getProbeWakeLockDuration() { + // Ideally, this would be computed by examining the values of: + // + // /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit + // + // and: + // + // /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms + // + // For now, just make some assumptions. + final long numUnicastProbes = 3; + final long retransTimeMs = 1000; + final long gracePeriodMs = 500; + return (numUnicastProbes * retransTimeMs) + gracePeriodMs; + } + // TODO: simply the number of objects by making this extend Thread. private final class NetlinkSocketObserver implements Runnable { diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 808a882..20c2168 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -17,6 +17,7 @@ package android.net; import android.content.Context; +import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -25,6 +26,7 @@ import android.util.Log; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import android.net.ConnectivityManager.PacketKeepalive; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; @@ -143,17 +145,60 @@ public abstract class NetworkAgent extends Handler { */ public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9; - /** Sent by ConnectivityService to the NetworkAgent to inform the agent to pull + /** + * Sent by ConnectivityService to the NetworkAgent to inform the agent to pull * the underlying network connection for updated bandwidth information. */ public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10; /** + * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent + * periodically on the given interval. + * + * arg1 = the slot number of the keepalive to start + * arg2 = interval in seconds + * obj = KeepalivePacketData object describing the data to be sent + * + * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. + */ + public static final int CMD_START_PACKET_KEEPALIVE = BASE + 11; + + /** + * Requests that the specified keepalive packet be stopped. + * + * arg1 = slot number of the keepalive to stop. + * + * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. + */ + public static final int CMD_STOP_PACKET_KEEPALIVE = BASE + 12; + + /** + * Sent by the NetworkAgent to ConnectivityService to provide status on a packet keepalive + * request. This may either be the reply to a CMD_START_PACKET_KEEPALIVE, or an asynchronous + * error notification. + * + * This is also sent by KeepaliveTracker to the app's ConnectivityManager.PacketKeepalive to + * so that the app's PacketKeepaliveCallback methods can be called. + * + * arg1 = slot number of the keepalive + * arg2 = error code + */ + public static final int EVENT_PACKET_KEEPALIVE = BASE + 13; + + /** + * Sent by ConnectivityService to inform this network transport of signal strength thresholds + * that when crossed should trigger a system wakeup and a NetworkCapabilities update. + * + * obj = int[] describing signal strength thresholds. + */ + public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14; + + /** * Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid * automatically reconnecting to this network (e.g. via autojoin). Happens * when user selects "No" option on the "Stay connected?" dialog box. */ - public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 11; + public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15; public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, NetworkCapabilities nc, LinkProperties lp, int score) { @@ -249,6 +294,27 @@ public abstract class NetworkAgent extends Handler { saveAcceptUnvalidated(msg.arg1 != 0); break; } + case CMD_START_PACKET_KEEPALIVE: { + startPacketKeepalive(msg); + break; + } + case CMD_STOP_PACKET_KEEPALIVE: { + stopPacketKeepalive(msg); + break; + } + + case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: { + ArrayList<Integer> thresholds = + ((Bundle) msg.obj).getIntegerArrayList("thresholds"); + // TODO: Change signal strength thresholds API to use an ArrayList<Integer> + // rather than convert to int[]. + int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0]; + for (int i = 0; i < intThresholds.length; i++) { + intThresholds[i] = thresholds.get(i); + } + setSignalStrengthThresholds(intThresholds); + break; + } case CMD_PREVENT_AUTOMATIC_RECONNECT: { preventAutomaticReconnect(); break; @@ -257,13 +323,27 @@ public abstract class NetworkAgent extends Handler { } private void queueOrSendMessage(int what, Object obj) { + queueOrSendMessage(what, 0, 0, obj); + } + + private void queueOrSendMessage(int what, int arg1, int arg2) { + queueOrSendMessage(what, arg1, arg2, null); + } + + private void queueOrSendMessage(int what, int arg1, int arg2, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + msg.obj = obj; + queueOrSendMessage(msg); + } + + private void queueOrSendMessage(Message msg) { synchronized (mPreConnectedQueue) { if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(what, obj); + mAsyncChannel.sendMessage(msg); } else { - Message msg = Message.obtain(); - msg.what = what; - msg.obj = obj; mPreConnectedQueue.add(msg); } } @@ -378,6 +458,34 @@ public abstract class NetworkAgent extends Handler { } /** + * Requests that the network hardware send the specified packet at the specified interval. + */ + protected void startPacketKeepalive(Message msg) { + onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); + } + + /** + * Requests that the network hardware send the specified packet at the specified interval. + */ + protected void stopPacketKeepalive(Message msg) { + onPacketKeepaliveEvent(msg.arg1, PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED); + } + + /** + * Called by the network when a packet keepalive event occurs. + */ + public void onPacketKeepaliveEvent(int slot, int reason) { + queueOrSendMessage(EVENT_PACKET_KEEPALIVE, slot, reason); + } + + /** + * Called by ConnectivityService to inform this network transport of signal strength thresholds + * that when crossed should trigger a system wakeup and a NetworkCapabilities update. + */ + protected void setSignalStrengthThresholds(int[] thresholds) { + } + + /** * Called when the user asks to not stay connected to this network because it was found to not * provide Internet access. Usually followed by call to {@code unwanted}. The transport is * responsible for making sure the device does not automatically reconnect to the same network diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index d0e0cbe..3bd12c0 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -48,6 +48,7 @@ public final class NetworkCapabilities implements Parcelable { mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; mNetworkSpecifier = nc.mNetworkSpecifier; + mSignalStrength = nc.mSignalStrength; } } @@ -60,6 +61,7 @@ public final class NetworkCapabilities implements Parcelable { mNetworkCapabilities = mTransportTypes = 0; mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0; mNetworkSpecifier = null; + mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED; } /** @@ -184,6 +186,28 @@ public final class NetworkCapabilities implements Parcelable { private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL; /** + * Network capabilities that are expected to be mutable, i.e., can change while a particular + * network is connected. + */ + private static final long MUTABLE_CAPABILITIES = + // TRUSTED can change when user explicitly connects to an untrusted network in Settings. + // http://b/18206275 + (1 << NET_CAPABILITY_TRUSTED) | + (1 << NET_CAPABILITY_VALIDATED) | + (1 << NET_CAPABILITY_CAPTIVE_PORTAL); + + /** + * Network capabilities that are not allowed in NetworkRequests. This exists because the + * NetworkFactory / NetworkAgent model does not deal well with the situation where a + * capability's presence cannot be known in advance. If such a capability is requested, then we + * can get into a cycle where the NetworkFactory endlessly churns out NetworkAgents that then + * get immediately torn down because they do not have the requested capability. + */ + private static final long NON_REQUESTABLE_CAPABILITIES = + (1 << NET_CAPABILITY_VALIDATED) | + (1 << NET_CAPABILITY_CAPTIVE_PORTAL); + + /** * Capabilities that are set by default when the object is constructed. */ private static final long DEFAULT_CAPABILITIES = @@ -278,8 +302,31 @@ public final class NetworkCapabilities implements Parcelable { this.mNetworkCapabilities |= nc.mNetworkCapabilities; } - private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) { - return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities); + /** + * Convenience function that returns a human-readable description of the first mutable + * capability we find. Used to present an error message to apps that request mutable + * capabilities. + * + * @hide + */ + public String describeFirstNonRequestableCapability() { + if (hasCapability(NET_CAPABILITY_VALIDATED)) return "NET_CAPABILITY_VALIDATED"; + if (hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) return "NET_CAPABILITY_CAPTIVE_PORTAL"; + // This cannot happen unless the preceding checks are incomplete. + if ((mNetworkCapabilities & NON_REQUESTABLE_CAPABILITIES) != 0) { + return "unknown non-requestable capabilities " + Long.toHexString(mNetworkCapabilities); + } + if (mLinkUpBandwidthKbps != 0 || mLinkDownBandwidthKbps != 0) return "link bandwidth"; + if (hasSignalStrength()) return "signalStrength"; + return null; + } + + private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) { + long networkCapabilities = this.mNetworkCapabilities; + if (onlyImmutable) { + networkCapabilities = networkCapabilities & ~MUTABLE_CAPABILITIES; + } + return ((nc.mNetworkCapabilities & networkCapabilities) == networkCapabilities); } /** @hide */ @@ -287,6 +334,11 @@ public final class NetworkCapabilities implements Parcelable { return (nc.mNetworkCapabilities == this.mNetworkCapabilities); } + private boolean equalsNetCapabilitiesImmutable(NetworkCapabilities that) { + return ((this.mNetworkCapabilities & ~MUTABLE_CAPABILITIES) == + (that.mNetworkCapabilities & ~MUTABLE_CAPABILITIES)); + } + /** * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if all the capabilities it provides are * typically provided by restricted networks. @@ -555,26 +607,130 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Magic value that indicates no signal strength provided. A request specifying this value is + * always satisfied. + * + * @hide + */ + public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE; + + /** + * Signal strength. This is a signed integer, and higher values indicate better signal. + * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI. + */ + private int mSignalStrength; + + /** + * Sets the signal strength. This is a signed integer, with higher values indicating a stronger + * signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units + * reported by WifiManager. + * <p> + * Note that when used to register a network callback, this specifies the minimum acceptable + * signal strength. When received as the state of an existing network it specifies the current + * value. A value of code SIGNAL_STRENGTH_UNSPECIFIED} means no value when received and has no + * effect when requesting a callback. + * + * @param signalStrength the bearer-specific signal strength. + * @hide + */ + public void setSignalStrength(int signalStrength) { + mSignalStrength = signalStrength; + } + + /** + * Returns {@code true} if this object specifies a signal strength. + * + * @hide + */ + public boolean hasSignalStrength() { + return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED; + } + + /** + * Retrieves the signal strength. + * + * @return The bearer-specific signal strength. + * @hide + */ + public int getSignalStrength() { + return mSignalStrength; + } + + private void combineSignalStrength(NetworkCapabilities nc) { + this.mSignalStrength = Math.max(this.mSignalStrength, nc.mSignalStrength); + } + + private boolean satisfiedBySignalStrength(NetworkCapabilities nc) { + return this.mSignalStrength <= nc.mSignalStrength; + } + + private boolean equalsSignalStrength(NetworkCapabilities nc) { + return this.mSignalStrength == nc.mSignalStrength; + } + + /** * Combine a set of Capabilities to this one. Useful for coming up with the complete set - * {@hide} + * @hide */ public void combineCapabilities(NetworkCapabilities nc) { combineNetCapabilities(nc); combineTransportTypes(nc); combineLinkBandwidths(nc); combineSpecifiers(nc); + combineSignalStrength(nc); } /** - * Check if our requirements are satisfied by the given Capabilities. - * {@hide} + * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * @param onlyImmutable if {@code true}, do not consider mutable requirements such as link + * bandwidth, signal strength, or validation / captive portal status. + * + * @hide */ - public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { + private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) { return (nc != null && - satisfiedByNetCapabilities(nc) && + satisfiedByNetCapabilities(nc, onlyImmutable) && satisfiedByTransportTypes(nc) && - satisfiedByLinkBandwidths(nc) && - satisfiedBySpecifier(nc)); + (onlyImmutable || satisfiedByLinkBandwidths(nc)) && + satisfiedBySpecifier(nc) && + (onlyImmutable || satisfiedBySignalStrength(nc))); + } + + /** + * Check if our requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * + * @hide + */ + public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { + return satisfiedByNetworkCapabilities(nc, false); + } + + /** + * Check if our immutable requirements are satisfied by the given {@code NetworkCapabilities}. + * + * @param nc the {@code NetworkCapabilities} that may or may not satisfy our requirements. + * + * @hide + */ + public boolean satisfiedByImmutableNetworkCapabilities(NetworkCapabilities nc) { + return satisfiedByNetworkCapabilities(nc, true); + } + + /** + * Checks that our immutable capabilities are the same as those of the given + * {@code NetworkCapabilities}. + * + * @hide + */ + public boolean equalImmutableCapabilities(NetworkCapabilities nc) { + if (nc == null) return false; + return (equalsNetCapabilitiesImmutable(nc) && + equalsTransportTypes(nc) && + equalsSpecifier(nc)); } @Override @@ -584,6 +740,7 @@ public final class NetworkCapabilities implements Parcelable { return (equalsNetCapabilities(that) && equalsTransportTypes(that) && equalsLinkBandwidths(that) && + equalsSignalStrength(that) && equalsSpecifier(that)); } @@ -595,7 +752,8 @@ public final class NetworkCapabilities implements Parcelable { ((int)(mTransportTypes >> 32) * 7) + (mLinkUpBandwidthKbps * 11) + (mLinkDownBandwidthKbps * 13) + - (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17)); + (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17) + + (mSignalStrength * 19)); } @Override @@ -609,7 +767,9 @@ public final class NetworkCapabilities implements Parcelable { dest.writeInt(mLinkUpBandwidthKbps); dest.writeInt(mLinkDownBandwidthKbps); dest.writeString(mNetworkSpecifier); + dest.writeInt(mSignalStrength); } + public static final Creator<NetworkCapabilities> CREATOR = new Creator<NetworkCapabilities>() { @Override @@ -621,6 +781,7 @@ public final class NetworkCapabilities implements Parcelable { netCap.mLinkUpBandwidthKbps = in.readInt(); netCap.mLinkDownBandwidthKbps = in.readInt(); netCap.mNetworkSpecifier = in.readString(); + netCap.mSignalStrength = in.readInt(); return netCap; } @Override @@ -678,6 +839,8 @@ public final class NetworkCapabilities implements Parcelable { String specifier = (mNetworkSpecifier == null ? "" : " Specifier: <" + mNetworkSpecifier + ">"); - return "[" + transports + capabilities + upBand + dnBand + specifier + "]"; + String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : ""); + + return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]"; } } diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 5f46c73..cab88b9 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -169,7 +169,8 @@ public class NetworkFactory extends Handler { } } - private void handleAddRequest(NetworkRequest request, int score) { + @VisibleForTesting + protected void handleAddRequest(NetworkRequest request, int score) { NetworkRequestInfo n = mNetworkRequests.get(request.requestId); if (n == null) { if (DBG) log("got request " + request + " with score " + score); @@ -184,7 +185,8 @@ public class NetworkFactory extends Handler { evalRequest(n); } - private void handleRemoveRequest(NetworkRequest request) { + @VisibleForTesting + protected void handleRemoveRequest(NetworkRequest request) { NetworkRequestInfo n = mNetworkRequests.get(request.requestId); if (n != null) { mNetworkRequests.remove(request.requestId); diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index e184ec4..7da4818 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -191,6 +191,24 @@ public class NetworkRequest implements Parcelable { mNetworkCapabilities.setNetworkSpecifier(networkSpecifier); return this; } + + /** + * Sets the signal strength. This is a signed integer, with higher values indicating a + * stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same + * RSSI units reported by WifiManager. + * <p> + * Note that when used to register a network callback, this specifies the minimum acceptable + * signal strength. When received as the state of an existing network it specifies the + * current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when + * received and has no effect when requesting a callback. + * + * @param signalStrength the bearer-specific signal strength. + * @hide + */ + public Builder setSignalStrength(int signalStrength) { + mNetworkCapabilities.setSignalStrength(signalStrength); + return this; + } } // implement the Parcelable interface diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 4407c9d..78a9401 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.nfc.cardemulation; import java.io.IOException; diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java index ad34e61..a299479 100644 --- a/core/java/android/nfc/cardemulation/HostApduService.java +++ b/core/java/android/nfc/cardemulation/HostApduService.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.nfc.cardemulation; import android.annotation.SdkConstant; diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java index 0d01762..6a8aeee 100644 --- a/core/java/android/nfc/cardemulation/OffHostApduService.java +++ b/core/java/android/nfc/cardemulation/OffHostApduService.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.nfc.cardemulation; import android.annotation.SdkConstant; diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index cccc4be..1f3e9a7 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -101,6 +101,13 @@ public class BatteryManager { */ public static final String EXTRA_INVALID_CHARGER = "invalid_charger"; + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * Int value set to the maximum charging current supported by the charger in micro amperes. + * {@hide} + */ + public static final String EXTRA_MAX_CHARGING_CURRENT = "max_charging_current"; + // values for "status" field in the ACTION_BATTERY_CHANGED Intent public static final int BATTERY_STATUS_UNKNOWN = 1; public static final int BATTERY_STATUS_CHARGING = 2; diff --git a/core/java/android/os/BatteryProperties.java b/core/java/android/os/BatteryProperties.java index 8f5cf8b..29e868c 100644 --- a/core/java/android/os/BatteryProperties.java +++ b/core/java/android/os/BatteryProperties.java @@ -22,6 +22,7 @@ public class BatteryProperties implements Parcelable { public boolean chargerAcOnline; public boolean chargerUsbOnline; public boolean chargerWirelessOnline; + public int maxChargingCurrent; public int batteryStatus; public int batteryHealth; public boolean batteryPresent; @@ -37,6 +38,7 @@ public class BatteryProperties implements Parcelable { chargerAcOnline = other.chargerAcOnline; chargerUsbOnline = other.chargerUsbOnline; chargerWirelessOnline = other.chargerWirelessOnline; + maxChargingCurrent = other.maxChargingCurrent; batteryStatus = other.batteryStatus; batteryHealth = other.batteryHealth; batteryPresent = other.batteryPresent; @@ -55,6 +57,7 @@ public class BatteryProperties implements Parcelable { chargerAcOnline = p.readInt() == 1 ? true : false; chargerUsbOnline = p.readInt() == 1 ? true : false; chargerWirelessOnline = p.readInt() == 1 ? true : false; + maxChargingCurrent = p.readInt(); batteryStatus = p.readInt(); batteryHealth = p.readInt(); batteryPresent = p.readInt() == 1 ? true : false; @@ -68,6 +71,7 @@ public class BatteryProperties implements Parcelable { p.writeInt(chargerAcOnline ? 1 : 0); p.writeInt(chargerUsbOnline ? 1 : 0); p.writeInt(chargerWirelessOnline ? 1 : 0); + p.writeInt(maxChargingCurrent); p.writeInt(batteryStatus); p.writeInt(batteryHealth); p.writeInt(batteryPresent ? 1 : 0); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 4ad9d6d..8e86a53 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -463,12 +463,15 @@ public abstract class BatteryStats implements Parcelable { public abstract long getCpuPowerMaUs(int which); /** - * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed. + * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed for a + * given CPU cluster. + * @param cluster the index of the CPU cluster. * @param step the index of the CPU speed. This is not the actual speed of the CPU. * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. - * @see BatteryStats#getCpuSpeedSteps() + * @see PowerProfile.getNumCpuClusters() + * @see PowerProfile.getNumSpeedStepsInCpuCluster(int) */ - public abstract long getTimeAtCpuSpeed(int step, int which); + public abstract long getTimeAtCpuSpeed(int cluster, int step, int which); public static abstract class Sensor { /* @@ -2275,9 +2278,6 @@ public abstract class BatteryStats implements Parcelable { public abstract Map<String, ? extends Timer> getKernelWakelockStats(); - /** Returns the number of different speeds that the CPU can run at */ - public abstract int getCpuSpeedSteps(); - public abstract void writeToParcelWithoutUids(Parcel out, int flags); private final static void formatTimeRaw(StringBuilder out, long seconds) { diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index a87b88d..38037a6 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -53,6 +53,15 @@ public abstract class PowerManagerInternal { */ public static final int WAKEFULNESS_DOZING = 3; + + /** + * Power hint: The user is interacting with the device. The corresponding data field must be + * the expected duration of the fling, or 0 if unknown. + * + * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h + */ + public static final int POWER_HINT_INTERACTION = 2; + public static String wakefulnessToString(int wakefulness) { switch (wakefulness) { case WAKEFULNESS_ASLEEP: @@ -150,4 +159,5 @@ public abstract class PowerManagerInternal { public abstract void setFeature(int featureId, int data); public abstract int getFeature(int featureId); + } diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index 8a4bc31..5f84351 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -1198,6 +1198,37 @@ public interface IMountService extends IInterface { _data.recycle(); } } + + @Override + public void createNewUserDir(int userHandle, String path) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(userHandle); + _data.writeString(path); + mRemote.transact(Stub.TRANSACTION_createNewUserDir, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void deleteUserKey(int userHandle) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(userHandle); + mRemote.transact(Stub.TRANSACTION_deleteUserKey, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } } private static final String DESCRIPTOR = "IMountService"; @@ -1315,6 +1346,9 @@ public interface IMountService extends IInterface { static final int TRANSACTION_encryptWipeStorage = IBinder.FIRST_CALL_TRANSACTION + 61; + static final int TRANSACTION_createNewUserDir = IBinder.FIRST_CALL_TRANSACTION + 62; + static final int TRANSACTION_deleteUserKey = IBinder.FIRST_CALL_TRANSACTION + 63; + /** * Cast an IBinder object into an IMountService interface, generating a * proxy if needed. @@ -1879,6 +1913,21 @@ public interface IMountService extends IInterface { reply.writeNoException(); return true; } + case TRANSACTION_createNewUserDir: { + data.enforceInterface(DESCRIPTOR); + int userHandle = data.readInt(); + String path = data.readString(); + createNewUserDir(userHandle, path); + reply.writeNoException(); + return true; + } + case TRANSACTION_deleteUserKey: { + data.enforceInterface(DESCRIPTOR); + int userHandle = data.readInt(); + deleteUserKey(userHandle); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); } @@ -2196,4 +2245,19 @@ public interface IMountService extends IInterface { public String getPrimaryStorageUuid() throws RemoteException; public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) throws RemoteException; + + /** + * Creates the user data directory, possibly encrypted + * @param userHandle Handle of the user whose directory we are creating + * @param path Path at which to create the directory. + */ + public void createNewUserDir(int userHandle, String path) + throws RemoteException; + + /** + * Securely delete the user's encryption key + * @param userHandle Handle of the user whose key we are deleting + */ + public void deleteUserKey(int userHandle) + throws RemoteException; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index d1f3743..1d92453 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -960,6 +960,24 @@ public class StorageManager { } /** {@hide} */ + public void createNewUserDir(int userHandle, File path) { + try { + mMountService.createNewUserDir(userHandle, path.getAbsolutePath()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** {@hide} */ + public void deleteUserKey(int userHandle) { + try { + mMountService.deleteUserKey(userHandle); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** {@hide} */ public static File maybeTranslateEmulatedPathToInternal(File path) { final IMountService mountService = IMountService.Stub.asInterface( ServiceManager.getService("mount")); diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index c7ba607..f5221c6 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -130,6 +130,9 @@ public final class DocumentsContract { */ private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES); + /** {@hide} */ + public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui"; + /** * Constants related to a document, including {@link Cursor} column names * and flags. diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d92d3d0..8787215 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3993,7 +3993,6 @@ public final class Settings { DOCK_SOUNDS_ENABLED, // moved to global LOCKSCREEN_SOUNDS_ENABLED, SHOW_WEB_SUGGESTIONS, - NOTIFICATION_LIGHT_PULSE, SIP_CALL_OPTIONS, SIP_RECEIVE_CALLS, POINTER_SPEED, @@ -6596,6 +6595,22 @@ public final class Settings { public static final String THEME_PREV_BOOT_API_LEVEL = "theme_prev_boot_api_level"; /** + * Whether the camera launch gesture should be disabled. + * + * @hide + */ + public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled"; + + /** + * Whether the camera launch gesture to double tap the power button when the screen is off + * should be disabled. + * + * @hide + */ + public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED = + "camera_double_tap_power_gesture_disabled"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear @@ -6651,7 +6666,8 @@ public final class Settings { MOUNT_UMS_NOTIFY_ENABLED, SLEEP_TIMEOUT, DOUBLE_TAP_TO_WAKE, - ADVANCED_REBOOT + ADVANCED_REBOOT, + CAMERA_GESTURE_DISABLED, }; /** diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 1d284ea..7b2d299 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -16,7 +16,10 @@ package android.view; +import android.annotation.RequiresPermission; +import android.content.Context; import android.content.res.CompatibilityInfo; +import android.content.res.Resources; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; @@ -30,6 +33,8 @@ import android.util.Log; import java.util.Arrays; +import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM; + /** * Provides information about the size and density of a logical display. * <p> @@ -679,6 +684,49 @@ public final class Display { } /** + * Request the display applies a color transform. + * @hide + */ + @RequiresPermission(CONFIGURE_DISPLAY_COLOR_TRANSFORM) + public void requestColorTransform(ColorTransform colorTransform) { + mGlobal.requestColorTransform(mDisplayId, colorTransform.getId()); + } + + /** + * Returns the active color transform of this display + * @hide + */ + public ColorTransform getColorTransform() { + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.getColorTransform(); + } + } + + /** + * Returns the default color transform of this display + * @hide + */ + public ColorTransform getDefaultColorTransform() { + synchronized (this) { + updateDisplayInfoLocked(); + return mDisplayInfo.getDefaultColorTransform(); + } + } + + /** + * Gets the supported color transforms of this device. + * @hide + */ + public ColorTransform[] getSupportedColorTransforms() { + synchronized (this) { + updateDisplayInfoLocked(); + ColorTransform[] transforms = mDisplayInfo.supportedColorTransforms; + return Arrays.copyOf(transforms, transforms.length); + } + } + + /** * Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating * the phase offset of the VSYNC events provided by Choreographer relative to the * display refresh. For example, if Choreographer reports that the refresh occurred @@ -1057,4 +1105,89 @@ public final class Display { } }; } + + /** + * A color transform supported by a given display. + * + * @see Display#getSupportedColorTransforms() + * @hide + */ + public static final class ColorTransform implements Parcelable { + public static final ColorTransform[] EMPTY_ARRAY = new ColorTransform[0]; + + private final int mId; + private final int mColorTransform; + + public ColorTransform(int id, int colorTransform) { + mId = id; + mColorTransform = colorTransform; + } + + public int getId() { + return mId; + } + + public int getColorTransform() { + return mColorTransform; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof ColorTransform)) { + return false; + } + ColorTransform that = (ColorTransform) other; + return mId == that.mId + && mColorTransform == that.mColorTransform; + } + + @Override + public int hashCode() { + int hash = 1; + hash = hash * 17 + mId; + hash = hash * 17 + mColorTransform; + return hash; + } + + @Override + public String toString() { + return new StringBuilder("{") + .append("id=").append(mId) + .append(", colorTransform=").append(mColorTransform) + .append("}") + .toString(); + } + + @Override + public int describeContents() { + return 0; + } + + private ColorTransform(Parcel in) { + this(in.readInt(), in.readInt()); + } + + @Override + public void writeToParcel(Parcel out, int parcelableFlags) { + out.writeInt(mId); + out.writeInt(mColorTransform); + } + + @SuppressWarnings("hiding") + public static final Parcelable.Creator<ColorTransform> CREATOR + = new Parcelable.Creator<ColorTransform>() { + @Override + public ColorTransform createFromParcel(Parcel in) { + return new ColorTransform(in); + } + + @Override + public ColorTransform[] newArray(int size) { + return new ColorTransform[size]; + } + }; + } } diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 08e88ea..d43b962 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -169,6 +169,15 @@ public final class DisplayInfo implements Parcelable { */ public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY; + /** The active color transform. */ + public int colorTransformId; + + /** The default color transform. */ + public int defaultColorTransformId; + + /** The list of supported color transforms */ + public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY; + /** * The logical display density which is the basis for density-independent * pixels. @@ -279,6 +288,8 @@ public final class DisplayInfo implements Parcelable { && rotation == other.rotation && modeId == other.modeId && defaultModeId == other.defaultModeId + && colorTransformId == other.colorTransformId + && defaultColorTransformId == other.defaultColorTransformId && logicalDensityDpi == other.logicalDensityDpi && physicalXDpi == other.physicalXDpi && physicalYDpi == other.physicalYDpi @@ -317,6 +328,10 @@ public final class DisplayInfo implements Parcelable { modeId = other.modeId; defaultModeId = other.defaultModeId; supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); + colorTransformId = other.colorTransformId; + defaultColorTransformId = other.defaultColorTransformId; + supportedColorTransforms = Arrays.copyOf( + other.supportedColorTransforms, other.supportedColorTransforms.length); logicalDensityDpi = other.logicalDensityDpi; physicalXDpi = other.physicalXDpi; physicalYDpi = other.physicalYDpi; @@ -353,6 +368,13 @@ public final class DisplayInfo implements Parcelable { for (int i = 0; i < nModes; i++) { supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source); } + colorTransformId = source.readInt(); + defaultColorTransformId = source.readInt(); + int nColorTransforms = source.readInt(); + supportedColorTransforms = new Display.ColorTransform[nColorTransforms]; + for (int i = 0; i < nColorTransforms; i++) { + supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source); + } logicalDensityDpi = source.readInt(); physicalXDpi = source.readFloat(); physicalYDpi = source.readFloat(); @@ -390,6 +412,12 @@ public final class DisplayInfo implements Parcelable { for (int i = 0; i < supportedModes.length; i++) { supportedModes[i].writeToParcel(dest, flags); } + dest.writeInt(colorTransformId); + dest.writeInt(defaultColorTransformId); + dest.writeInt(supportedColorTransforms.length); + for (int i = 0; i < supportedColorTransforms.length; i++) { + supportedColorTransforms[i].writeToParcel(dest, flags); + } dest.writeInt(logicalDensityDpi); dest.writeFloat(physicalXDpi); dest.writeFloat(physicalYDpi); @@ -461,6 +489,24 @@ public final class DisplayInfo implements Parcelable { return result; } + public Display.ColorTransform getColorTransform() { + return findColorTransform(colorTransformId); + } + + public Display.ColorTransform getDefaultColorTransform() { + return findColorTransform(defaultColorTransformId); + } + + private Display.ColorTransform findColorTransform(int colorTransformId) { + for (int i = 0; i < supportedColorTransforms.length; i++) { + Display.ColorTransform colorTransform = supportedColorTransforms[i]; + if (colorTransform.getId() == colorTransformId) { + return colorTransform; + } + } + throw new IllegalStateException("Unable to locate color transform: " + colorTransformId); + } + public void getAppMetrics(DisplayMetrics outMetrics) { getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); } @@ -565,6 +611,12 @@ public final class DisplayInfo implements Parcelable { sb.append(defaultModeId); sb.append(", modes "); sb.append(Arrays.toString(supportedModes)); + sb.append(", colorTransformId "); + sb.append(colorTransformId); + sb.append(", defaultColorTransformId "); + sb.append(defaultColorTransformId); + sb.append(", supportedColorTransforms "); + sb.append(Arrays.toString(supportedColorTransforms)); sb.append(", rotation "); sb.append(rotation); sb.append(", density "); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 051707e..584fe76 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -490,6 +490,7 @@ public class SurfaceControl { public boolean secure; public long appVsyncOffsetNanos; public long presentationDeadlineNanos; + public int colorTransform; public PhysicalDisplayInfo() { } @@ -513,7 +514,8 @@ public class SurfaceControl { && yDpi == other.yDpi && secure == other.secure && appVsyncOffsetNanos == other.appVsyncOffsetNanos - && presentationDeadlineNanos == other.presentationDeadlineNanos; + && presentationDeadlineNanos == other.presentationDeadlineNanos + && colorTransform == other.colorTransform; } @Override @@ -531,6 +533,7 @@ public class SurfaceControl { secure = other.secure; appVsyncOffsetNanos = other.appVsyncOffsetNanos; presentationDeadlineNanos = other.presentationDeadlineNanos; + colorTransform = other.colorTransform; } // For debugging purposes @@ -539,7 +542,8 @@ public class SurfaceControl { return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, " + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure + ", appVsyncOffset " + appVsyncOffsetNanos - + ", bufferDeadline " + presentationDeadlineNanos + "}"; + + ", bufferDeadline " + presentationDeadlineNanos + + ", colorTransform " + colorTransform + "}"; } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 7d48a9a..db68c29 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -447,10 +447,11 @@ public class SurfaceView extends View { final boolean formatChanged = mFormat != mRequestedFormat; final boolean sizeChanged = mWidth != myWidth || mHeight != myHeight; final boolean visibleChanged = mVisible != mRequestedVisible; + final boolean layoutSizeChanged = getWidth() != mLayout.width || getHeight() != mLayout.height; if (force || creating || formatChanged || sizeChanged || visibleChanged || mLeft != mLocation[0] || mTop != mLocation[1] - || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) { + || mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded || layoutSizeChanged) { if (DEBUG) Log.i(TAG, "Changes: creating=" + creating + " format=" + formatChanged + " size=" + sizeChanged diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6e93a30..42402eb 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6621,6 +6621,19 @@ public final class ViewRootImpl implements ViewParent, return false; } + /** + * Force the window to report its next draw. + * <p> + * This method is only supposed to be used to speed up the interaction from SystemUI and window + * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE + * unless you fully understand this interaction. + * @hide + */ + public void setReportNextDraw() { + mReportNextDraw = true; + invalidate(); + } + void changeCanvasOpacity(boolean opaque) { Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque); if (mAttachInfo.mHardwareRenderer != null) { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index ed858e7..6e9a418 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2395,6 +2395,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te lp.itemId = mAdapter.getItemId(position); } lp.viewType = mAdapter.getItemViewType(position); + lp.isEnabled = mAdapter.isEnabled(position); if (lp != vlp) { child.setLayoutParams(lp); } @@ -2416,19 +2417,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } final int position = getPositionForView(host); - final ListAdapter adapter = getAdapter(); - - if ((position == INVALID_POSITION) || (adapter == null)) { + if (position == INVALID_POSITION || mAdapter == null) { // Cannot perform actions on invalid items. return false; } - if (!isEnabled() || !adapter.isEnabled(position)) { - // Cannot perform actions on disabled items. + if (position >= mAdapter.getCount()) { + // The position is no longer valid, likely due to a data set + // change. We could fail here for all data set changes, since + // there is a chance that the data bound to the view may no + // longer exist at the same position within the adapter, but + // it's more consistent with the standard touch interaction to + // click at whatever may have moved into that position. return false; } - final long id = getItemIdAtPosition(position); + final boolean isItemEnabled; + final ViewGroup.LayoutParams lp = host.getLayoutParams(); + if (lp instanceof AbsListView.LayoutParams) { + isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled; + } else { + isItemEnabled = false; + } + + if (!isEnabled() || !isItemEnabled) { + // Cannot perform actions on disabled items. + return false; + } switch (action) { case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { @@ -2445,11 +2460,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } return false; case AccessibilityNodeInfo.ACTION_CLICK: { if (isClickable()) { + final long id = getItemIdAtPosition(position); return performItemClick(host, position, id); } } return false; case AccessibilityNodeInfo.ACTION_LONG_CLICK: { if (isLongClickable()) { + final long id = getItemIdAtPosition(position); return performLongPress(host, position, id); } } return false; @@ -2469,13 +2486,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ public void onInitializeAccessibilityNodeInfoForItem( View view, int position, AccessibilityNodeInfo info) { - final ListAdapter adapter = getAdapter(); - if (position == INVALID_POSITION || adapter == null) { + if (position == INVALID_POSITION) { // The item doesn't exist, so there's not much we can do here. return; } - if (!isEnabled() || !adapter.isEnabled(position)) { + final boolean isItemEnabled; + final ViewGroup.LayoutParams lp = view.getLayoutParams(); + if (lp instanceof AbsListView.LayoutParams) { + isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled; + } else { + isItemEnabled = false; + } + + if (!isEnabled() || !isItemEnabled) { info.setEnabled(false); return; } @@ -6315,6 +6339,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ long itemId = -1; + /** Whether the adapter considers the item enabled. */ + boolean isEnabled; + public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } @@ -6340,6 +6367,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te encoder.addProperty("list:viewType", viewType); encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter); encoder.addProperty("list:forceAdd", forceAdd); + encoder.addProperty("list:isEnabled", isEnabled); } } diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index 0cc1b25..2cfefba 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -600,13 +600,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { } /** - * Get the position within the adapter's data set for the view, where view is a an adapter item - * or a descendant of an adapter item. + * Returns the position within the adapter's data set for the view, where + * view is a an adapter item or a descendant of an adapter item. + * <p> + * <strong>Note:</strong> The result of this method only reflects the + * position of the data bound to <var>view</var> during the most recent + * layout pass. If the adapter's data set has changed without a subsequent + * layout pass, the position returned by this method may not match the + * current position of the data within the adapter. * - * @param view an adapter item, or a descendant of an adapter item. This must be visible in this - * AdapterView at the time of the call. - * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION} - * if the view does not correspond to a list item (or it is not currently visible). + * @param view an adapter item, or a descendant of an adapter item. This + * must be visible in this AdapterView at the time of the call. + * @return the position within the adapter's data set of the view, or + * {@link #INVALID_POSITION} if the view does not correspond to a + * list item (or it is not currently visible) */ public int getPositionForView(View view) { View listItem = view; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index f994d4a..607e955 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1070,6 +1070,7 @@ public class GridView extends AbsListView { child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(0); + p.isEnabled = mAdapter.isEnabled(0); p.forceAdd = true; int childHeightSpec = getChildMeasureSpec( @@ -1480,6 +1481,7 @@ public class GridView extends AbsListView { p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); } p.viewType = mAdapter.getItemViewType(position); + p.isEnabled = mAdapter.isEnabled(position); if (recycled && !p.forceAdd) { attachViewToParent(child, where, p); diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index c5632ec..00d017f 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1200,6 +1200,7 @@ public class ListView extends AbsListView { child.setLayoutParams(p); } p.viewType = mAdapter.getItemViewType(position); + p.isEnabled = mAdapter.isEnabled(position); p.forceAdd = true; final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, @@ -1913,6 +1914,7 @@ public class ListView extends AbsListView { p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); } p.viewType = mAdapter.getItemViewType(position); + p.isEnabled = mAdapter.isEnabled(position); if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) { |