diff options
Diffstat (limited to 'core/java')
38 files changed, 1297 insertions, 126 deletions
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/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/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/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 6e29989..1f23c0a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -392,6 +392,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 +680,52 @@ 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 { + mService.addLockoutResetCallback( + new IFingerprintServiceLockoutResetCallback.Stub() { + + @Override + public void onLockoutReset(long deviceId) throws RemoteException { + mHandler.post(new Runnable() { + @Override + public void run() { + callback.onLockoutReset(); + } + }); + } + }); + } 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 +735,7 @@ public class FingerprintManager { super(looper); } + @Override public void handleMessage(android.os.Message msg) { switch(msg.what) { case MSG_ENROLL_RESULT: 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..c9a5d59 --- /dev/null +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl @@ -0,0 +1,28 @@ +/* + * 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 + */ +oneway interface IFingerprintServiceLockoutResetCallback { + 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 8e55736..d4e6c82 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -100,6 +100,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, @@ -1181,6 +1191,142 @@ 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; + + 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 diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 46c28a6..d4dd669 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -160,4 +160,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/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/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/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..bad94fc 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -468,6 +468,7 @@ public abstract class BatteryStats implements Parcelable { * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT. * @see BatteryStats#getCpuSpeedSteps() */ + @Deprecated public abstract long getTimeAtCpuSpeed(int step, int which); public static abstract class Sensor { diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java index fce09dd..9f71ce1 100644 --- a/core/java/android/os/storage/IMountService.java +++ b/core/java/android/os/storage/IMountService.java @@ -1180,6 +1180,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"; @@ -1295,6 +1326,9 @@ public interface IMountService extends IInterface { static final int TRANSACTION_benchmark = IBinder.FIRST_CALL_TRANSACTION + 59; static final int TRANSACTION_setDebugFlags = IBinder.FIRST_CALL_TRANSACTION + 60; + 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. @@ -1850,6 +1884,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); } @@ -2159,4 +2208,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/Settings.java b/core/java/android/provider/Settings.java index fe95864..78be3cd 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5712,6 +5712,13 @@ public final class Settings { public static final String ASSISTANT = "assistant"; /** + * Whether the camera launch gesture should be disabled. + * + * @hide + */ + public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled"; + + /** * This are the settings to be backed up. * * NOTE: Settings are backed up and restored in the order they appear @@ -5767,6 +5774,7 @@ public final class Settings { MOUNT_UMS_NOTIFY_ENABLED, SLEEP_TIMEOUT, DOUBLE_TAP_TO_WAKE, + CAMERA_GESTURE_DISABLED, }; /** 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/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 55493c3..6da0f63 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -29,6 +29,21 @@ public class MetricsLogger implements MetricsConstants { // Temporary constants go here, to await migration to MetricsConstants. // next value is 239; public static final int ACTION_ASSIST_LONG_PRESS = 239; + public static final int FINGERPRINT_ENROLLING = 240; + public static final int FINGERPRINT_FIND_SENSOR = 241; + public static final int FINGERPRINT_ENROLL_FINISH = 242; + public static final int FINGERPRINT_ENROLL_INTRO = 243; + public static final int FINGERPRINT_ENROLL_ONBOARD = 244; + public static final int FINGERPRINT_ENROLL_SIDECAR = 245; + public static final int FINGERPRINT_ENROLLING_SETUP = 246; + public static final int FINGERPRINT_FIND_SENSOR_SETUP = 247; + public static final int FINGERPRINT_ENROLL_FINISH_SETUP = 248; + public static final int FINGERPRINT_ENROLL_INTRO_SETUP = 249; + public static final int FINGERPRINT_ENROLL_ONBOARD_SETUP = 250; + public static final int ACTION_FINGERPRINT_ENROLL = 251; + public static final int ACTION_FINGERPRINT_AUTH = 252; + public static final int ACTION_FINGERPRINT_DELETE = 253; + public static final int ACTION_FINGERPRINT_RENAME = 254; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java index f178c8c..4f4d3e0 100644 --- a/core/java/com/android/internal/os/BatteryStatsHelper.java +++ b/core/java/com/android/internal/os/BatteryStatsHelper.java @@ -338,7 +338,7 @@ public final class BatteryStatsHelper { } if (mCpuPowerCalculator == null) { - mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile); + mCpuPowerCalculator = new CpuPowerCalculator(); } mCpuPowerCalculator.reset(); diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java index a3ef612..d62f7a6 100644 --- a/core/java/com/android/internal/os/CpuPowerCalculator.java +++ b/core/java/com/android/internal/os/CpuPowerCalculator.java @@ -23,54 +23,14 @@ public class CpuPowerCalculator extends PowerCalculator { private static final String TAG = "CpuPowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final double[] mPowerCpuNormal; - - /** - * Reusable array for calculations. - */ - private final long[] mSpeedStepTimes; - - public CpuPowerCalculator(PowerProfile profile) { - final int speedSteps = profile.getNumSpeedSteps(); - mPowerCpuNormal = new double[speedSteps]; - mSpeedStepTimes = new long[speedSteps]; - for (int p = 0; p < speedSteps; p++) { - mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p); - } - } - @Override public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { - final int speedSteps = mSpeedStepTimes.length; - - long totalTimeAtSpeeds = 0; - for (int step = 0; step < speedSteps; step++) { - mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType); - totalTimeAtSpeeds += mSpeedStepTimes[step]; - } - totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1); - app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000; - if (DEBUG && app.cpuTimeMs != 0) { - Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms"); - } - - double cpuPowerMaMs = 0; - for (int step = 0; step < speedSteps; step++) { - final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds; - final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step]; - if (DEBUG && ratio != 0) { - Log.d(TAG, "UID " + u.getUid() + ": CPU step #" - + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power=" - + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000))); - } - cpuPowerMaMs += cpuSpeedStepPower; - } - - if (DEBUG && cpuPowerMaMs != 0) { - Log.d(TAG, "UID " + u.getUid() + ": cpu total power=" - + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000))); + app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0); + if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) { + Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power=" + + BatteryStatsHelper.makemAh(app.cpuPowerMah)); } // Keep track of the package with highest drain. @@ -108,8 +68,5 @@ public class CpuPowerCalculator extends PowerCalculator { // Statistics may not have been gathered yet. app.cpuTimeMs = app.cpuFgTimeMs; } - - // Convert the CPU power to mAh - app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000); } } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index c1645c3..feed3903 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -69,5 +69,10 @@ oneway interface IStatusBar void showAssistDisclosure(); void startAssist(in Bundle args); + + /** + * Notifies the status bar that a camera launch gesture has been detected. + */ + void onCameraLaunchGestureDetected(); } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index dfb7c50..4e4552d 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -16,6 +16,7 @@ package com.android.internal.widget; +import android.app.trust.IStrongAuthTracker; import com.android.internal.widget.VerifyCredentialResponse; /** {@hide} */ @@ -35,4 +36,7 @@ interface ILockSettings { boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); + void registerStrongAuthTracker(in IStrongAuthTracker tracker); + void unregisterStrongAuthTracker(in IStrongAuthTracker tracker); + void requireStrongAuth(int strongAuthReason, int userId); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 86d11be..a3a01da 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -16,18 +16,19 @@ package com.android.internal.widget; -import android.Manifest; +import android.annotation.IntDef; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; +import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; -import android.bluetooth.BluetoothClass; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.pm.PackageManager; import android.os.AsyncTask; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -38,9 +39,12 @@ import android.os.storage.StorageManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import com.google.android.collect.Lists; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -228,7 +232,7 @@ public class LockPatternUtils { public void reportFailedPasswordAttempt(int userId) { getDevicePolicyManager().reportFailedPasswordAttempt(userId); getTrustManager().reportUnlockAttempt(false /* authenticated */, userId); - getTrustManager().reportRequireCredentialEntry(userId); + requireCredentialEntry(userId); } public void reportSuccessfulPasswordAttempt(int userId) { @@ -1163,10 +1167,32 @@ public class LockPatternUtils { } /** - * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int) + * Disable trust 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 requireCredentialEntry(int userId) { - getTrustManager().reportRequireCredentialEntry(userId); + requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId); + } + + /** + * Requests strong authentication for user {@param userId}. + * + * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. + * + * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating + * the reason for and the strength of the requested authentication. + * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} + */ + public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason, + int userId) { + try { + getLockSettings().requireStrongAuth(strongAuthReason, userId); + } catch (RemoteException e) { + Log.e(TAG, "Error while requesting strong auth: " + e); + } } private void onAfterChangingPassword(int userHandle) { @@ -1198,4 +1224,153 @@ public class LockPatternUtils { private boolean shouldEncryptWithCredentials(boolean defaultValue) { return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet(); } + + + public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) { + try { + getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub); + } catch (RemoteException e) { + throw new RuntimeException("Could not register StrongAuthTracker"); + } + } + + public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) { + try { + getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub); + } catch (RemoteException e) { + Log.e(TAG, "Could not unregister StrongAuthTracker", e); + } + } + + /** + * Tracks the global strong authentication state. + */ + public static class StrongAuthTracker { + + @IntDef(flag = true, + value = { STRONG_AUTH_NOT_REQUIRED, + STRONG_AUTH_REQUIRED_AFTER_BOOT, + STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, + STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST}) + @Retention(RetentionPolicy.SOURCE) + public @interface StrongAuthFlags {} + + /** + * Strong authentication is not required. + */ + public static final int STRONG_AUTH_NOT_REQUIRED = 0x0; + + /** + * Strong authentication is required because the user has not authenticated since boot. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1; + + /** + * Strong authentication is required because a device admin has temporarily requested it. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2; + + /** + * Strong authentication is required because the user has temporarily requested it. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4; + + /** + * Strong authentication is required because the user has been locked out after too many + * attempts. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8; + + public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT; + + final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray(); + + private final H mHandler; + + public StrongAuthTracker() { + this(Looper.myLooper()); + } + + /** + * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged} + * will be scheduled. + */ + public StrongAuthTracker(Looper looper) { + mHandler = new H(looper); + } + + /** + * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required, + * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong + * authentication is required. + * + * @param userId the user for whom the state is queried. + */ + public @StrongAuthFlags int getStrongAuthForUser(int userId) { + return mStrongAuthRequiredForUser.get(userId, DEFAULT); + } + + /** + * @return true if unlocking with trust alone is allowed for {@param userId} by the current + * strong authentication requirements. + */ + public boolean isTrustAllowedForUser(int userId) { + return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED; + } + + /** + * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the + * current strong authentication requirements. + */ + public boolean isFingerprintAllowedForUser(int userId) { + return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED; + } + + /** + * Called when the strong authentication requirements for {@param userId} changed. + */ + public void onStrongAuthRequiredChanged(int userId) { + } + + void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags, + int userId) { + + int oldValue = getStrongAuthForUser(userId); + if (strongAuthFlags != oldValue) { + if (strongAuthFlags == DEFAULT) { + mStrongAuthRequiredForUser.delete(userId); + } else { + mStrongAuthRequiredForUser.put(userId, strongAuthFlags); + } + onStrongAuthRequiredChanged(userId); + } + } + + + final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() { + @Override + public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags, + int userId) { + mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED, + strongAuthFlags, userId).sendToTarget(); + } + }; + + private class H extends Handler { + static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1; + + public H(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED: + handleStrongAuthRequiredChanged(msg.arg1, msg.arg2); + break; + } + } + }; + } } |
