summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt9
-rw-r--r--core/java/android/accounts/AccountManager.java31
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl6
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.aidl (renamed from core/java/android/app/timedetector/TimeSignal.aidl)2
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java137
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java6
-rw-r--r--core/java/android/app/timedetector/TimeSignal.java109
-rw-r--r--core/java/android/content/Intent.java3
-rw-r--r--core/java/android/hardware/biometrics/BiometricAuthenticator.java13
-rw-r--r--core/java/android/hardware/biometrics/BiometricConstants.java7
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java2
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java20
-rw-r--r--core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl58
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl8
-rw-r--r--core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl2
-rw-r--r--core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl2
-rw-r--r--core/java/android/hardware/face/FaceManager.java3
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl2
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java3
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl2
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl8
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl8
-rw-r--r--core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java59
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java14
-rw-r--r--services/core/java/com/android/server/BatteryService.java2
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java508
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceAuthenticator.java75
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java6
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java75
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java6
-rw-r--r--services/core/java/com/android/server/biometrics/iris/IrisAuthenticator.java68
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java17
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java4
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java40
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java8
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java43
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java6
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java1
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java19
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java253
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java88
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java5
-rw-r--r--tests/BootImageProfileTest/AndroidTest.xml4
-rw-r--r--tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java6
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java59
-rw-r--r--tools/aapt2/format/Container.cpp23
-rw-r--r--tools/aapt2/formats.md17
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java41
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSpecifier.java3
57 files changed, 1305 insertions, 799 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 295fef142c89..ad9a04d16a7e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4780,8 +4780,11 @@ package android.net.wifi {
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(android.os.WorkSource);
+ method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean startSoftAp(@Nullable android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startSubscriptionProvisioning(@NonNull android.net.wifi.hotspot2.OsuProvider, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.hotspot2.ProvisioningCallback);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void stopEasyConnectSession();
+ method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public boolean stopSoftAp();
+ method @RequiresPermission(anyOf={"android.permission.NETWORK_STACK", android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
@@ -4796,10 +4799,16 @@ package android.net.wifi {
field public static final String EXTRA_CHANGE_REASON = "changeReason";
field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
+ field public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
+ field public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
field public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
field public static final String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
field public static final String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
field public static final String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+ field public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0; // 0x0
+ field public static final int IFACE_IP_MODE_LOCAL_ONLY = 2; // 0x2
+ field public static final int IFACE_IP_MODE_TETHERED = 1; // 0x1
+ field public static final int IFACE_IP_MODE_UNSPECIFIED = -1; // 0xffffffff
field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
field public static final String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 26c2c0cfdd5d..f4e465ab3adb 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -563,6 +563,21 @@ public class AccountManager {
* account, or the AbstractAcccountAuthenticator managing the account did so or because the
* client shares a signature with the managing AbstractAccountAuthenticator.
*
+ * <div class="caution"><p><b>Caution: </b>This method returns personal and sensitive user data.
+ * If your app accesses, collects, uses, or shares personal and sensitive data, you must clearly
+ * disclose that fact to users. For apps published on Google Play, policies protecting user data
+ * require that you do the following:</p>
+ * <ul>
+ * <li>Disclose to the user how your app accesses, collects, uses, or shares personal and
+ * sensitive data. Learn more about
+ * <a href="https://play.google.com/about/privacy-security-deception/user-data/#!#personal-sensitive">acceptable
+ * disclosure and consent</a>.</li>
+ * <li>Provide a privacy policy that describes your use of this data on- and off-device.</li>
+ * </ul>
+ * <p>To learn more, visit the
+ * <a href="https://play.google.com/about/privacy-security-deception/user-data">Google Play
+ * Policy regarding user data</a>.</p></div>
+ *
* <p>
* It is safe to call this method from the main thread.
*
@@ -649,6 +664,22 @@ public class AccountManager {
* the account. For example, there are types corresponding to Google and Facebook. The exact
* string token to use will be published somewhere associated with the authenticator in
* question.
+ * </p>
+ *
+ * <div class="caution"><p><b>Caution: </b>This method returns personal and sensitive user data.
+ * If your app accesses, collects, uses, or shares personal and sensitive data, you must clearly
+ * disclose that fact to users. For apps published on Google Play, policies protecting user data
+ * require that you do the following:</p>
+ * <ul>
+ * <li>Disclose to the user how your app accesses, collects, uses, or shares personal and
+ * sensitive data. Learn more about
+ * <a href="https://play.google.com/about/privacy-security-deception/user-data/#!#personal-sensitive">acceptable
+ * disclosure and consent</a>.</li>
+ * <li>Provide a privacy policy that describes your use of this data on- and off-device.</li>
+ * </ul>
+ * <p>To learn more, visit the
+ * <a href="https://play.google.com/about/privacy-security-deception/user-data">Google Play
+ * Policy regarding user data</a>.</p></div>
*
* <p>
* It is safe to call this method from the main thread.
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index f624446a2027..ddc4932d6fec 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,10 +16,10 @@
package android.app.timedetector;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
/**
- * System private API to comunicate with time detector service.
+ * System private API to communicate with time detector service.
*
* <p>Used by parts of the Android system with signals associated with the device's time to provide
* information to the Time Detector Service.
@@ -32,5 +32,5 @@ import android.app.timedetector.TimeSignal;
* {@hide}
*/
interface ITimeDetectorService {
- void suggestTime(in TimeSignal timeSignal);
+ void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/TimeSignal.aidl b/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
index d2ec357555bc..f5e240549a9a 100644
--- a/core/java/android/app/timedetector/TimeSignal.aidl
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.aidl
@@ -16,4 +16,4 @@
package android.app.timedetector;
-parcelable TimeSignal; \ No newline at end of file
+parcelable PhoneTimeSuggestion;
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
new file mode 100644
index 000000000000..475a4aafd929
--- /dev/null
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 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.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a telephony source. The value consists of the number of milliseconds elapsed
+ * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
+ * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
+ * must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class PhoneTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
+ new Parcelable.Creator<PhoneTimeSuggestion>() {
+ public PhoneTimeSuggestion createFromParcel(Parcel in) {
+ return PhoneTimeSuggestion.createFromParcel(in);
+ }
+
+ public PhoneTimeSuggestion[] newArray(int size) {
+ return new PhoneTimeSuggestion[size];
+ }
+ };
+
+ private final int mPhoneId;
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
+
+ public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
+ mPhoneId = phoneId;
+ mUtcTime = Objects.requireNonNull(utcTime);
+ }
+
+ private static PhoneTimeSuggestion createFromParcel(Parcel in) {
+ int phoneId = in.readInt();
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPhoneId);
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ public int getPhoneId() {
+ return mPhoneId;
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
+ return mPhoneId == that.mPhoneId
+ && Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPhoneId, mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneTimeSuggestion{"
+ + "mPhoneId='" + mPhoneId + '\''
+ + ", mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 052050df8c9a..334e9582a145 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -45,12 +45,12 @@ public final class TimeDetector {
* signals are available such as those that come from more reliable sources or were
* determined more recently.
*/
- public void suggestTime(@NonNull TimeSignal timeSignal) {
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) {
- Log.d(TAG, "suggestTime called: " + timeSignal);
+ Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
}
try {
- mITimeDetectorService.suggestTime(timeSignal);
+ mITimeDetectorService.suggestPhoneTime(timeSuggestion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/timedetector/TimeSignal.java b/core/java/android/app/timedetector/TimeSignal.java
deleted file mode 100644
index b49426000d88..000000000000
--- a/core/java/android/app/timedetector/TimeSignal.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2018 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.timedetector;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.TimestampedValue;
-
-import java.util.Objects;
-
-/**
- * A time signal from a named source. The value consists of the number of milliseconds elapsed since
- * 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number was
- * established. The elapsed realtime clock is considered accurate but volatile, so time signals
- * must not be persisted across device resets.
- *
- * @hide
- */
-public final class TimeSignal implements Parcelable {
-
- public static final @android.annotation.NonNull Parcelable.Creator<TimeSignal> CREATOR =
- new Parcelable.Creator<TimeSignal>() {
- public TimeSignal createFromParcel(Parcel in) {
- return TimeSignal.createFromParcel(in);
- }
-
- public TimeSignal[] newArray(int size) {
- return new TimeSignal[size];
- }
- };
-
- public static final String SOURCE_ID_NITZ = "nitz";
-
- private final String mSourceId;
- private final TimestampedValue<Long> mUtcTime;
-
- public TimeSignal(String sourceId, TimestampedValue<Long> utcTime) {
- mSourceId = Objects.requireNonNull(sourceId);
- mUtcTime = Objects.requireNonNull(utcTime);
- }
-
- private static TimeSignal createFromParcel(Parcel in) {
- String sourceId = in.readString();
- TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
- return new TimeSignal(sourceId, utcTime);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mSourceId);
- dest.writeParcelable(mUtcTime, 0);
- }
-
- @NonNull
- public String getSourceId() {
- return mSourceId;
- }
-
- @NonNull
- public TimestampedValue<Long> getUtcTime() {
- return mUtcTime;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- TimeSignal that = (TimeSignal) o;
- return Objects.equals(mSourceId, that.mSourceId)
- && Objects.equals(mUtcTime, that.mUtcTime);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mSourceId, mUtcTime);
- }
-
- @Override
- public String toString() {
- return "TimeSignal{"
- + "mSourceId='" + mSourceId + '\''
- + ", mUtcTime=" + mUtcTime
- + '}';
- }
-}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2ecfc8e107b3..4e7e7132b7df 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2678,6 +2678,9 @@ public class Intent implements Parcelable, Cloneable {
* that application is first launched (that is the first time it is moved
* out of the stopped state). The data contains the name of the package.
*
+ * <p>When the application is first launched, the application itself doesn't receive this
+ * broadcast.</p>
+ *
* <p class="note">This is a protected intent that can only be sent
* by the system.
*/
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index 0ec812fe0350..698876b9c59e 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -36,23 +36,30 @@ public interface BiometricAuthenticator {
* @hide
*/
int TYPE_NONE = 0;
+
+ /**
+ * Constant representing credential (PIN, pattern, or password).
+ * @hide
+ */
+ int TYPE_CREDENTIAL = 1 << 0;
+
/**
* Constant representing fingerprint.
* @hide
*/
- int TYPE_FINGERPRINT = 1 << 0;
+ int TYPE_FINGERPRINT = 1 << 1;
/**
* Constant representing iris.
* @hide
*/
- int TYPE_IRIS = 1 << 1;
+ int TYPE_IRIS = 1 << 2;
/**
* Constant representing face.
* @hide
*/
- int TYPE_FACE = 1 << 2;
+ int TYPE_FACE = 1 << 3;
/**
* Container for biometric data
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index 27c04b407315..c8bf570e1bc8 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -134,6 +134,13 @@ public interface BiometricConstants {
int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
/**
+ * This constant is only used by SystemUI. It notifies SystemUI that authentication was paused
+ * because the authentication attempt was unsuccessful.
+ * @hide
+ */
+ int BIOMETRIC_PAUSED_REJECTED = 100;
+
+ /**
* @hide
*/
@UnsupportedAppUsage
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index cbe8a052db2f..9d427c8d8bab 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -137,7 +137,7 @@ public class BiometricManager {
public boolean hasEnrolledBiometrics(int userId) {
if (mService != null) {
try {
- return mService.hasEnrolledBiometrics(userId);
+ return mService.hasEnrolledBiometrics(userId, mContext.getOpPackageName());
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in hasEnrolledBiometrics(): " + e);
return false;
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index cf86e25112d2..9c51b5246749 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -26,6 +26,8 @@ import android.annotation.RequiresPermission;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.DialogInterface;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
@@ -339,9 +341,23 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
@Override
- public void onError(int error, String message) throws RemoteException {
+ public void onError(int modality, int error, int vendorCode) throws RemoteException {
mExecutor.execute(() -> {
- mAuthenticationCallback.onAuthenticationError(error, message);
+ String errorMessage;
+ switch (modality) {
+ case TYPE_FACE:
+ errorMessage = FaceManager.getErrorString(mContext, error, vendorCode);
+ break;
+
+ case TYPE_FINGERPRINT:
+ errorMessage = FingerprintManager.getErrorString(mContext, error,
+ vendorCode);
+ break;
+
+ default:
+ errorMessage = "";
+ }
+ mAuthenticationCallback.onAuthenticationError(error, errorMessage);
});
}
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
new file mode 100644
index 000000000000..987d19799644
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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.biometrics;
+
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.face.IFaceServiceReceiver;
+import android.hardware.face.Face;
+
+/**
+ * This interface encapsulates fingerprint, face, iris, etc. authenticators.
+ * Implementations of this interface are meant to be registered with BiometricService.
+ * @hide
+ */
+interface IBiometricAuthenticator {
+
+ // This method prepares the service to start authenticating, but doesn't start authentication.
+ // This is protected by the MANAGE_BIOMETRIC signature permission. This method should only be
+ // called from BiometricService. The additional uid, pid, userId arguments should be determined
+ // by BiometricService. To start authentication after the clients are ready, use
+ // startPreparedClient().
+ void prepareForAuthentication(boolean requireConfirmation, IBinder token, long sessionId,
+ int userId, IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
+ int cookie, int callingUid, int callingPid, int callingUserId);
+
+ // Starts authentication with the previously prepared client.
+ void startPreparedClient(int cookie);
+
+ // Same as above, with extra arguments.
+ void cancelAuthenticationFromService(IBinder token, String opPackageName,
+ int callingUid, int callingPid, int callingUserId, boolean fromClient);
+
+ // Determine if HAL is loaded and ready
+ boolean isHardwareDetected(String opPackageName);
+
+ // Determine if a user has at least one enrolled face
+ boolean hasEnrolledTemplates(int userId, String opPackageName);
+
+ // Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
+ void resetLockout(in byte [] token);
+
+ // Explicitly set the active user (for enrolling work profile)
+ void setActiveUser(int uid);
+}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 6a3bf38a97e1..06336a55ac5e 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -19,6 +19,7 @@ package android.hardware.biometrics;
import android.os.Bundle;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
+import android.hardware.biometrics.IBiometricAuthenticator;
/**
* Communication channel from BiometricPrompt and BiometricManager to BiometricService. The
@@ -40,7 +41,12 @@ interface IBiometricService {
int canAuthenticate(String opPackageName, int userId);
// Checks if any biometrics are enrolled.
- boolean hasEnrolledBiometrics(int userId);
+ boolean hasEnrolledBiometrics(int userId, String opPackageName);
+
+ // Registers an authenticator (e.g. face, fingerprint, iris).
+ // Id must be unique, whereas strength and modality don't need to be.
+ // TODO(b/123321528): Turn strength and modality into enums.
+ void registerAuthenticator(int id, int strength, int modality, IBiometricAuthenticator authenticator);
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
index 22ef33e86e17..c960049438f1 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl
@@ -25,7 +25,7 @@ oneway interface IBiometricServiceReceiver {
// Noties that authentication failed.
void onAuthenticationFailed();
// Notify BiometricPrompt that an error has occurred.
- void onError(int error, String message);
+ void onError(int modality, int error, int vendorCode);
// Notifies that a biometric has been acquired.
void onAcquired(int acquiredInfo, String message);
// Notifies that the SystemUI dialog has been dismissed.
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 66b6e896fc13..61310f302fe4 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -31,7 +31,7 @@ oneway interface IBiometricServiceReceiverInternal {
void onAuthenticationFailed();
// Notify BiometricService than an error has occured. Forward to the correct receiver depending
// on the cookie.
- void onError(int cookie, int error, String message);
+ void onError(int cookie, int modality, int error, int vendorCode);
// Notifies that a biometric has been acquired.
void onAcquired(int acquiredInfo, String message);
// Notifies that the SystemUI dialog has been dismissed.
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 12b285a0f0ab..55ebe285af1e 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -504,8 +504,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
public boolean isHardwareDetected() {
if (mService != null) {
try {
- long deviceId = 0; /* TODO: plumb hardware id to FPMS */
- return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
+ return mService.isHardwareDetected(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index b6a0afbf716c..68a4aef7af08 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -67,7 +67,7 @@ interface IFaceService {
List<Face> getEnrolledFaces(int userId, String opPackageName);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected(long deviceId, String opPackageName);
+ boolean isHardwareDetected(String opPackageName);
// Get a pre-enrollment authentication token
long generateChallenge(IBinder token);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index d0622c88b4ca..22f8590a4e97 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -691,8 +691,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
public boolean isHardwareDetected() {
if (mService != null) {
try {
- long deviceId = 0; /* TODO: plumb hardware id to FPMS */
- return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
+ return mService.isHardwareDetected(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index dd6b29d87d67..1a7e12856753 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -71,7 +71,7 @@ interface IFingerprintService {
List<Fingerprint> getEnrolledFingerprints(int groupId, String opPackageName);
// Determine if HAL is loaded and ready
- boolean isHardwareDetected(long deviceId, String opPackageName);
+ boolean isHardwareDetected(String opPackageName);
// Get a pre-enrollment authentication token
long preEnroll(IBinder token);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index d9e2ba3e0975..317469e58245 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -155,12 +155,12 @@ oneway interface IStatusBar
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName);
- // Used to notify the authentication dialog that a biometric has been authenticated or rejected
- void onBiometricAuthenticated(boolean authenticated, String failureReason);
+ // Used to notify the authentication dialog that a biometric has been authenticated
+ void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
void onBiometricHelp(String message);
- // Used to set a message - the dialog will dismiss after a certain amount of time
- void onBiometricError(int errorCode, String error);
+ // Used to show an error - the dialog will dismiss after a certain amount of time
+ void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication
void hideAuthenticationDialog();
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 659134adec78..499a4d2fb949 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -104,12 +104,12 @@ interface IStatusBarService
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver,
int biometricModality, boolean requireConfirmation, int userId, String opPackageName);
- // Used to notify the authentication dialog that a biometric has been authenticated or rejected
- void onBiometricAuthenticated(boolean authenticated, String failureReason);
+ // Used to notify the authentication dialog that a biometric has been authenticated
+ void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
void onBiometricHelp(String message);
- // Used to set a message - the dialog will dismiss after a certain amount of time
- void onBiometricError(int errorCode, String error);
+ // Used to show an error - the dialog will dismiss after a certain amount of time
+ void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication
void hideAuthenticationDialog();
}
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
new file mode 100644
index 000000000000..1b5ad8868a01
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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.timedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import org.junit.Test;
+
+public class PhoneTimeSuggestionTest {
+ private static final int PHONE_ID = 99999;
+
+ @Test
+ public void testEquals() {
+ PhoneTimeSuggestion one =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, one);
+
+ PhoneTimeSuggestion two =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, two);
+ assertEquals(two, one);
+
+ PhoneTimeSuggestion three =
+ new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+
+ // DebugInfo must not be considered in equals().
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+
+ @Test
+ public void testParcelable() {
+ PhoneTimeSuggestion one =
+ new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, roundTripParcelable(one));
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ one.addDebugInfo("This is debug info");
+ PhoneTimeSuggestion two = roundTripParcelable(one);
+ assertEquals(one.getDebugInfo(), two.getDebugInfo());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Parcelable> T roundTripParcelable(T one) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeTypedObject(one, 0);
+ parcel.setDataPosition(0);
+
+ T toReturn = (T) parcel.readTypedObject(PhoneTimeSuggestion.CREATOR);
+ parcel.recycle();
+ return toReturn;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index cdc2623d34fd..b75873100025 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -16,6 +16,9 @@
package com.android.systemui.biometrics;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
@@ -27,6 +30,8 @@ import android.hardware.biometrics.Authenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.face.FaceManager;
+import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -34,6 +39,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.WindowManager;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.systemui.SystemUI;
@@ -229,15 +235,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
@Override
- public void onBiometricAuthenticated(boolean authenticated, String failureReason) {
- if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated
- + " reason: " + failureReason);
-
- if (authenticated) {
- mCurrentDialog.onAuthenticationSucceeded();
- } else {
- mCurrentDialog.onAuthenticationFailed(failureReason);
- }
+ public void onBiometricAuthenticated() {
+ mCurrentDialog.onAuthenticationSucceeded();
}
@Override
@@ -247,16 +246,45 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mCurrentDialog.onHelp(message);
}
+ private String getErrorString(int modality, int error, int vendorCode) {
+ switch (modality) {
+ case TYPE_FACE:
+ return FaceManager.getErrorString(mContext, error, vendorCode);
+
+ case TYPE_FINGERPRINT:
+ return FingerprintManager.getErrorString(mContext, error, vendorCode);
+
+ default:
+ return "";
+ }
+ }
+
@Override
- public void onBiometricError(int errorCode, String error) {
- if (DEBUG) Log.d(TAG, "onBiometricError: " + errorCode + ", " + error);
+ public void onBiometricError(int modality, int error, int vendorCode) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
+ }
+
+ final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
+ || (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
+
+ // TODO(b/141025588): Create separate methods for handling hard and soft errors.
+ final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
+ || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
- final boolean isLockout = errorCode == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
- || errorCode == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
+ if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
mCurrentDialog.animateToCredentialUI();
+ } else if (isSoftError) {
+ final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
+ ? mContext.getString(R.string.biometric_not_recognized)
+ : getErrorString(modality, error, vendorCode);
+ if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
+ mCurrentDialog.onAuthenticationFailed(errorMessage);
} else {
- mCurrentDialog.onError(error);
+ final String errorMessage = getErrorString(modality, error, vendorCode);
+ if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
+ mCurrentDialog.onError(errorMessage);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c9dc08e78afb..34f543702d96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -261,9 +261,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
default void showAuthenticationDialog(Bundle bundle,
IBiometricServiceReceiverInternal receiver, int biometricModality,
boolean requireConfirmation, int userId, String opPackageName) { }
- default void onBiometricAuthenticated(boolean authenticated, String failureReason) { }
+ default void onBiometricAuthenticated() { }
default void onBiometricHelp(String message) { }
- default void onBiometricError(int errorCode, String error) { }
+ default void onBiometricError(int modality, int error, int vendorCode) { }
default void hideAuthenticationDialog() { }
/**
@@ -792,12 +792,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
@Override
- public void onBiometricAuthenticated(boolean authenticated, String failureReason) {
+ public void onBiometricAuthenticated() {
synchronized (mLock) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = authenticated;
- args.arg2 = failureReason;
- mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget();
+ mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget();
}
}
@@ -809,9 +806,13 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
@Override
- public void onBiometricError(int errorCode, String error) {
+ public void onBiometricError(int modality, int error, int vendorCode) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, errorCode, 0, error).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = modality;
+ args.argi2 = error;
+ args.argi3 = vendorCode;
+ mHandler.obtainMessage(MSG_BIOMETRIC_ERROR, args).sendToTarget();
}
}
@@ -1098,13 +1099,9 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
break;
}
case MSG_BIOMETRIC_AUTHENTICATED: {
- SomeArgs someArgs = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onBiometricAuthenticated(
- (boolean) someArgs.arg1 /* authenticated */,
- (String) someArgs.arg2 /* failureReason */);
+ mCallbacks.get(i).onBiometricAuthenticated();
}
- someArgs.recycle();
break;
}
case MSG_BIOMETRIC_HELP:
@@ -1113,9 +1110,15 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
break;
case MSG_BIOMETRIC_ERROR:
+ SomeArgs someArgs = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).onBiometricError(msg.arg1, (String) msg.obj);
+ mCallbacks.get(i).onBiometricError(
+ someArgs.argi1 /* modality */,
+ someArgs.argi2 /* error */,
+ someArgs.argi3 /* vendorCode */
+ );
}
+ someArgs.recycle();
break;
case MSG_BIOMETRIC_HIDE:
for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index e1eb3b0c81b2..b089b740fc47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -38,15 +38,18 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.biometrics.Authenticator;
+import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.face.FaceManager;
import android.os.Bundle;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper.RunWithLooper;
+import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -89,9 +92,9 @@ public class AuthControllerTest extends SysuiTestCase {
when(context.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
- .thenReturn(true);
+ .thenReturn(true);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
- .thenReturn(true);
+ .thenReturn(true);
when(mDialog1.getOpPackageName()).thenReturn("Dialog1");
when(mDialog2.getOpPackageName()).thenReturn("Dialog2");
@@ -170,20 +173,34 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testOnAuthenticationSucceededInvoked_whenSystemRequested() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
- mAuthController.onBiometricAuthenticated(true, null /* failureReason */);
+ mAuthController.onBiometricAuthenticated();
verify(mDialog1).onAuthenticationSucceeded();
}
@Test
- public void testOnAuthenticationFailedInvoked_whenSystemRequested() {
+ public void testOnAuthenticationFailedInvoked_whenBiometricRejected() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
- final String failureReason = "failure reason";
- mAuthController.onBiometricAuthenticated(false, failureReason);
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_NONE,
+ BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
+ 0 /* vendorCode */);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onAuthenticationFailed(captor.capture());
- assertEquals(captor.getValue(), failureReason);
+ assertEquals(captor.getValue(), mContext.getString(R.string.biometric_not_recognized));
+ }
+
+ @Test
+ public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() {
+ showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
+ final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
+ final int vendorCode = 0;
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(mDialog1).onAuthenticationFailed(captor.capture());
+
+ assertEquals(captor.getValue(), FaceManager.getErrorString(mContext, error, vendorCode));
}
@Test
@@ -199,27 +216,27 @@ public class AuthControllerTest extends SysuiTestCase {
}
@Test
- public void testOnErrorInvoked_whenSystemRequested() {
+ public void testOnErrorInvoked_whenSystemRequested() throws Exception {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
final int error = 1;
- final String errMessage = "error message";
- mAuthController.onBiometricError(error, errMessage);
+ final int vendorCode = 0;
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onError(captor.capture());
- assertEquals(captor.getValue(), errMessage);
+ assertEquals(captor.getValue(), FaceManager.getErrorString(mContext, error, vendorCode));
}
@Test
public void testErrorLockout_whenCredentialAllowed_AnimatesToCredentialUI() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
- final String errorString = "lockout";
+ final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
- mAuthController.onBiometricError(error, errorString);
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyString());
verify(mDialog1).animateToCredentialUI();
}
@@ -228,11 +245,11 @@ public class AuthControllerTest extends SysuiTestCase {
public void testErrorLockoutPermanent_whenCredentialAllowed_AnimatesToCredentialUI() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
- final String errorString = "lockout_permanent";
+ final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
- mAuthController.onBiometricError(error, errorString);
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyString());
verify(mDialog1).animateToCredentialUI();
}
@@ -241,12 +258,12 @@ public class AuthControllerTest extends SysuiTestCase {
public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
- final String errorString = "lockout";
+ final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
- mAuthController.onBiometricError(error, errorString);
- verify(mDialog1).onError(eq(errorString));
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
+ verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI();
}
@@ -254,12 +271,12 @@ public class AuthControllerTest extends SysuiTestCase {
public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() {
showDialog(Authenticator.TYPE_BIOMETRIC, BiometricPrompt.TYPE_FACE);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
- final String errorString = "lockout_permanent";
+ final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
- mAuthController.onBiometricError(error, errorString);
- verify(mDialog1).onError(eq(errorString));
+ mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
+ verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index eb198c6ad4f7..8c9ae71dc0f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -418,10 +418,9 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testOnBiometricAuthenticated() {
- String failureReason = "test_failure_reason";
- mCommandQueue.onBiometricAuthenticated(true /* authenticated */, failureReason);
+ mCommandQueue.onBiometricAuthenticated();
waitForIdleSync();
- verify(mCallbacks).onBiometricAuthenticated(eq(true), eq(failureReason));
+ verify(mCallbacks).onBiometricAuthenticated();
}
@Test
@@ -434,11 +433,12 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testOnBiometricError() {
- final int errorCode = 1;
- String errorMessage = "test_error_message";
- mCommandQueue.onBiometricError(errorCode, errorMessage);
+ final int modality = 1;
+ final int error = 2;
+ final int vendorCode = 3;
+ mCommandQueue.onBiometricError(modality, error, vendorCode);
waitForIdleSync();
- verify(mCallbacks).onBiometricError(eq(errorCode), eq(errorMessage));
+ verify(mCallbacks).onBiometricError(eq(modality), eq(error), eq(vendorCode));
}
@Test
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d18b4f64f039..a33fcd557369 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -720,6 +720,8 @@ public final class BatteryService extends SystemService {
event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
+ event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
+ event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 4f1db3c96faf..619c21e7646b 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -37,13 +37,12 @@ import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
-import android.hardware.face.FaceManager;
import android.hardware.face.IFaceService;
-import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintService;
import android.net.Uri;
import android.os.Binder;
@@ -68,6 +67,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
+import com.android.server.biometrics.face.FaceAuthenticator;
+import com.android.server.biometrics.fingerprint.FingerprintAuthenticator;
import java.util.ArrayList;
import java.util.HashMap;
@@ -95,11 +96,6 @@ public class BiometricService extends SystemService {
private static final int MSG_CANCEL_AUTHENTICATION = 10;
private static final int MSG_ON_AUTHENTICATION_TIMED_OUT = 11;
private static final int MSG_ON_DEVICE_CREDENTIAL_PRESSED = 12;
- private static final int[] FEATURE_ID = {
- TYPE_FINGERPRINT,
- TYPE_IRIS,
- TYPE_FACE
- };
/**
* Authentication either just called and we have not transitioned to the CALLED state, or
@@ -172,7 +168,7 @@ public class BiometricService extends SystemService {
byte[] mTokenEscrow;
// Waiting for SystemUI to complete animation
int mErrorEscrow;
- String mErrorStringEscrow;
+ int mVendorCodeEscrow;
// Timestamp when authentication started
private long mStartTimeMs;
@@ -219,19 +215,15 @@ public class BiometricService extends SystemService {
private final Injector mInjector;
@VisibleForTesting
final IBiometricService.Stub mImpl;
+ private final boolean mHasFeatureFace;
private final boolean mHasFeatureFingerprint;
private final boolean mHasFeatureIris;
- private final boolean mHasFeatureFace;
@VisibleForTesting
final SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
private final Random mRandom = new Random();
@VisibleForTesting
- IFingerprintService mFingerprintService;
- @VisibleForTesting
- IFaceService mFaceService;
- @VisibleForTesting
IStatusBarService mStatusBarService;
@VisibleForTesting
KeyStore mKeyStore;
@@ -262,7 +254,7 @@ public class BiometricService extends SystemService {
}
case MSG_ON_AUTHENTICATION_REJECTED: {
- handleAuthenticationRejected((String) msg.obj /* failureReason */);
+ handleAuthenticationRejected();
break;
}
@@ -270,8 +262,9 @@ public class BiometricService extends SystemService {
SomeArgs args = (SomeArgs) msg.obj;
handleOnError(
args.argi1 /* cookie */,
- args.argi2 /* error */,
- (String) args.arg1 /* message */);
+ args.argi2 /* modality */,
+ args.argi3 /* error */,
+ args.argi4 /* vendorCode */);
args.recycle();
break;
}
@@ -331,7 +324,12 @@ public class BiometricService extends SystemService {
}
case MSG_ON_AUTHENTICATION_TIMED_OUT: {
- handleAuthenticationTimedOut((String) msg.obj /* errorMessage */);
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleAuthenticationTimedOut(
+ args.argi1 /* modality */,
+ args.argi2 /* error */,
+ args.argi3 /* vendorCode */);
+ args.recycle();
break;
}
@@ -347,21 +345,23 @@ public class BiometricService extends SystemService {
}
};
- private final class AuthenticatorWrapper {
- final int mType;
- final BiometricAuthenticator mAuthenticator;
-
- AuthenticatorWrapper(int type, BiometricAuthenticator authenticator) {
- mType = type;
- mAuthenticator = authenticator;
- }
-
- int getType() {
- return mType;
- }
-
- BiometricAuthenticator getAuthenticator() {
- return mAuthenticator;
+ /**
+ * Wraps IBiometricAuthenticator implementation and stores information about the authenticator.
+ * TODO(b/141025588): Consider refactoring the tests to not rely on this implementation detail.
+ */
+ @VisibleForTesting
+ public static final class AuthenticatorWrapper {
+ public final int id;
+ public final int strength;
+ public final int modality;
+ public final IBiometricAuthenticator impl;
+
+ AuthenticatorWrapper(int id, int strength, int modality,
+ IBiometricAuthenticator impl) {
+ this.id = id;
+ this.strength = strength;
+ this.modality = modality;
+ this.impl = impl;
}
}
@@ -521,23 +521,28 @@ public class BiometricService extends SystemService {
@Override
public void onAuthenticationFailed()
throws RemoteException {
- String failureReason = getContext().getString(R.string.biometric_not_recognized);
- Slog.v(TAG, "onAuthenticationFailed: " + failureReason);
- mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED, failureReason).sendToTarget();
+ Slog.v(TAG, "onAuthenticationFailed");
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_REJECTED).sendToTarget();
}
@Override
- public void onError(int cookie, int error, String message) throws RemoteException {
+ public void onError(int cookie, int modality, int error, int vendorCode)
+ throws RemoteException {
// Determine if error is hard or soft error. Certain errors (such as TIMEOUT) are
// soft errors and we should allow the user to try authenticating again instead of
// dismissing BiometricPrompt.
if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) {
- mHandler.obtainMessage(MSG_ON_AUTHENTICATION_TIMED_OUT, message).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = modality;
+ args.argi2 = error;
+ args.argi3 = vendorCode;
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_TIMED_OUT, args).sendToTarget();
} else {
SomeArgs args = SomeArgs.obtain();
args.argi1 = cookie;
- args.argi2 = error;
- args.arg1 = message;
+ args.argi2 = modality;
+ args.argi3 = error;
+ args.argi4 = vendorCode;
mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget();
}
}
@@ -666,7 +671,8 @@ public class BiometricService extends SystemService {
final long ident = Binder.clearCallingIdentity();
int error;
try {
- final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
+ final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId,
+ opPackageName);
error = result.second;
} finally {
Binder.restoreCallingIdentity(ident);
@@ -675,22 +681,30 @@ public class BiometricService extends SystemService {
}
@Override
- public boolean hasEnrolledBiometrics(int userId) {
+ public boolean hasEnrolledBiometrics(int userId, String opPackageName) {
checkInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
- for (int i = 0; i < mAuthenticators.size(); i++) {
- if (mAuthenticators.get(i).mAuthenticator.hasEnrolledTemplates(userId)) {
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ if (authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
return true;
}
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
return false;
}
+ @Override
+ public void registerAuthenticator(int id, int strength, int modality,
+ IBiometricAuthenticator authenticator) {
+ mAuthenticators.add(new AuthenticatorWrapper(id, strength, modality, authenticator));
+ }
+
@Override // Binder call
public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
throws RemoteException {
@@ -710,9 +724,11 @@ public class BiometricService extends SystemService {
checkInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
- for (int i = 0; i < mAuthenticators.size(); i++) {
- mAuthenticators.get(i).getAuthenticator().setActiveUser(userId);
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ authenticator.impl.setActiveUser(userId);
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -723,11 +739,8 @@ public class BiometricService extends SystemService {
checkInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
- if (mFingerprintService != null) {
- mFingerprintService.resetTimeout(token);
- }
- if (mFaceService != null) {
- mFaceService.resetLockout(token);
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ authenticator.impl.resetLockout(token);
}
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -750,40 +763,69 @@ public class BiometricService extends SystemService {
}
}
+ /**
+ * Class for injecting dependencies into BiometricService.
+ * TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
+ */
@VisibleForTesting
- static class Injector {
- IActivityManager getActivityManagerService() {
+ public static class Injector {
+
+ @VisibleForTesting
+ public IActivityManager getActivityManagerService() {
return ActivityManager.getService();
}
- IStatusBarService getStatusBarService() {
+ @VisibleForTesting
+ public IStatusBarService getStatusBarService() {
return IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
}
- IFingerprintService getFingerprintService() {
- return IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+ /**
+ * Allows to mock FaceAuthenticator for testing.
+ */
+ @VisibleForTesting
+ public IBiometricAuthenticator getFingerprintAuthenticator() {
+ return new FingerprintAuthenticator(IFingerprintService.Stub.asInterface(
+ ServiceManager.getService(Context.FINGERPRINT_SERVICE)));
}
- IFaceService getFaceService() {
- return IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE));
+ /**
+ * Allows to mock FaceAuthenticator for testing.
+ */
+ @VisibleForTesting
+ public IBiometricAuthenticator getFaceAuthenticator() {
+ return new FaceAuthenticator(
+ IFaceService.Stub.asInterface(ServiceManager.getService(Context.FACE_SERVICE)));
}
- SettingObserver getSettingObserver(Context context, Handler handler,
+ /**
+ * Allows to mock SettingObserver for testing.
+ */
+ @VisibleForTesting
+ public SettingObserver getSettingObserver(Context context, Handler handler,
List<EnabledOnKeyguardCallback> callbacks) {
return new SettingObserver(context, handler, callbacks);
}
- KeyStore getKeyStore() {
+ @VisibleForTesting
+ public KeyStore getKeyStore() {
return KeyStore.getInstance();
}
- boolean isDebugEnabled(Context context, int userId) {
+ /**
+ * Allows to enable/disable debug logs.
+ */
+ @VisibleForTesting
+ public boolean isDebugEnabled(Context context, int userId) {
return Utils.isDebugEnabled(context, userId);
}
- void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
+ /**
+ * Allows to stub publishBinderService(...) for testing.
+ */
+ @VisibleForTesting
+ public void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
service.publishBinderService(Context.BIOMETRIC_SERVICE, impl);
}
}
@@ -812,9 +854,9 @@ public class BiometricService extends SystemService {
mEnabledOnKeyguardCallbacks);
final PackageManager pm = context.getPackageManager();
+ mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS);
- mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
try {
injector.getActivityManagerService().registerUserSwitchObserver(
@@ -833,26 +875,30 @@ public class BiometricService extends SystemService {
@Override
public void onStart() {
- // TODO: maybe get these on-demand
- if (mHasFeatureFingerprint) {
- mFingerprintService = mInjector.getFingerprintService();
- }
- if (mHasFeatureFace) {
- mFaceService = mInjector.getFaceService();
+ // TODO(b/141025588): remove this code block once AuthService is integrated.
+ {
+ if (mHasFeatureFace) {
+ try {
+ mImpl.registerAuthenticator(0, 0, TYPE_FACE, mInjector.getFaceAuthenticator());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ if (mHasFeatureFingerprint) {
+ try {
+ mImpl.registerAuthenticator(0, 0, TYPE_FINGERPRINT,
+ mInjector.getFingerprintAuthenticator());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ if (mHasFeatureIris) {
+ Slog.e(TAG, "Iris is not supported");
+ }
}
mKeyStore = mInjector.getKeyStore();
mStatusBarService = mInjector.getStatusBarService();
-
- // Cache the authenticators
- for (int featureId : FEATURE_ID) {
- if (hasFeature(featureId)) {
- AuthenticatorWrapper authenticator =
- new AuthenticatorWrapper(featureId, getAuthenticator(featureId));
- mAuthenticators.add(authenticator);
- }
- }
-
mInjector.publishBinderService(this, mImpl);
}
@@ -868,7 +914,7 @@ public class BiometricService extends SystemService {
* {@link BiometricAuthenticator#TYPE_FACE}
* and the error containing one of the {@link BiometricConstants} errors.
*/
- private Pair<Integer, Integer> checkAndGetBiometricModality(int userId) {
+ private Pair<Integer, Integer> checkAndGetBiometricModality(int userId, String opPackageName) {
// No biometric features, send error
if (mAuthenticators.isEmpty()) {
return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT);
@@ -886,23 +932,26 @@ public class BiometricService extends SystemService {
int modality = TYPE_NONE;
int firstHwAvailable = TYPE_NONE;
- for (AuthenticatorWrapper authenticatorWrapper : mAuthenticators) {
- modality = authenticatorWrapper.getType();
- BiometricAuthenticator authenticator = authenticatorWrapper.getAuthenticator();
- if (authenticator.isHardwareDetected()) {
- isHardwareDetected = true;
- if (firstHwAvailable == TYPE_NONE) {
- // Store the first one since we want to return the error in correct priority
- // order.
- firstHwAvailable = modality;
- }
- if (authenticator.hasEnrolledTemplates(userId)) {
- hasTemplatesEnrolled = true;
- if (isEnabledForApp(modality, userId)) {
- enabledForApps = true;
- break;
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ modality = authenticator.modality;
+ try {
+ if (authenticator.impl.isHardwareDetected(opPackageName)) {
+ isHardwareDetected = true;
+ if (firstHwAvailable == TYPE_NONE) {
+ // Store the first one since we want to return the error in correct priority
+ // order.
+ firstHwAvailable = modality;
+ }
+ if (authenticator.impl.hasEnrolledTemplates(userId, opPackageName)) {
+ hasTemplatesEnrolled = true;
+ if (isEnabledForApp(modality, userId)) {
+ enabledForApps = true;
+ break;
+ }
}
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
}
}
@@ -926,7 +975,7 @@ public class BiometricService extends SystemService {
}
private boolean isEnabledForApp(int modality, int userId) {
- switch(modality) {
+ switch (modality) {
case TYPE_FINGERPRINT:
return true;
case TYPE_IRIS:
@@ -939,47 +988,16 @@ public class BiometricService extends SystemService {
}
}
- private String getErrorString(int type, int error, int vendorCode) {
- switch (type) {
- case TYPE_FINGERPRINT:
- return FingerprintManager.getErrorString(getContext(), error, vendorCode);
- case TYPE_IRIS:
- Slog.w(TAG, "Modality not supported");
- return null; // not supported
- case TYPE_FACE:
- return FaceManager.getErrorString(getContext(), error, vendorCode);
- default:
- Slog.w(TAG, "Unable to get error string for modality: " + type);
- return null;
- }
- }
-
- private BiometricAuthenticator getAuthenticator(int type) {
- switch (type) {
- case TYPE_FINGERPRINT:
- return (FingerprintManager)
- getContext().getSystemService(Context.FINGERPRINT_SERVICE);
- case TYPE_IRIS:
- return null;
- case TYPE_FACE:
- return (FaceManager)
- getContext().getSystemService(Context.FACE_SERVICE);
- default:
- return null;
- }
- }
-
- private boolean hasFeature(int type) {
- switch (type) {
- case TYPE_FINGERPRINT:
- return mHasFeatureFingerprint;
- case TYPE_IRIS:
- return mHasFeatureIris;
- case TYPE_FACE:
- return mHasFeatureFace;
- default:
- return false;
+ private String getErrorString(int modality, int error, int vendorCode) {
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ if (authenticator.modality == modality) {
+ // TODO(b/141025588): Refactor IBiometricServiceReceiver.aidl#onError(...) to not
+ // ask for a String error message, but derive it from the error code instead.
+ return "";
+ }
}
+ Slog.w(TAG, "Unable to get error string for modality: " + modality);
+ return null;
}
private void logDialogDismissed(int reason) {
@@ -1081,14 +1099,14 @@ public class BiometricService extends SystemService {
// Notify SysUI that the biometric has been authenticated. SysUI already knows
// the implicit/explicit state and will react accordingly.
- mStatusBarService.onBiometricAuthenticated(true, null /* failureReason */);
+ mStatusBarService.onBiometricAuthenticated();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
}
- private void handleAuthenticationRejected(String failureReason) {
- Slog.v(TAG, "handleAuthenticationRejected: " + failureReason);
+ private void handleAuthenticationRejected() {
+ Slog.v(TAG, "handleAuthenticationRejected()");
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
@@ -1097,7 +1115,8 @@ public class BiometricService extends SystemService {
return;
}
- mStatusBarService.onBiometricAuthenticated(false, failureReason);
+ mStatusBarService.onBiometricError(TYPE_NONE,
+ BiometricConstants.BIOMETRIC_PAUSED_REJECTED, 0 /* vendorCode */);
// TODO: This logic will need to be updated if BP is multi-modal
if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
@@ -1112,8 +1131,9 @@ public class BiometricService extends SystemService {
}
}
- private void handleAuthenticationTimedOut(String message) {
- Slog.v(TAG, "handleAuthenticationTimedOut: " + message);
+ private void handleAuthenticationTimedOut(int modality, int error, int vendorCode) {
+ Slog.v(TAG, String.format("handleAuthenticationTimedOut(%d, %d, %d)", modality, error,
+ vendorCode));
try {
// Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
// after user dismissed/canceled dialog).
@@ -1122,14 +1142,14 @@ public class BiometricService extends SystemService {
return;
}
- mStatusBarService.onBiometricAuthenticated(false, message);
+ mStatusBarService.onBiometricError(modality, error, vendorCode);
mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
}
- private void handleOnError(int cookie, int error, String message) {
+ private void handleOnError(int cookie, int modality, int error, int vendorCode) {
Slog.d(TAG, "handleOnError: " + error + " cookie: " + cookie);
// Errors can either be from the current auth session or the pending auth session.
// The pending auth session may receive errors such as ERROR_LOCKOUT before
@@ -1140,7 +1160,7 @@ public class BiometricService extends SystemService {
try {
if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
mCurrentAuthSession.mErrorEscrow = error;
- mCurrentAuthSession.mErrorStringEscrow = message;
+ mCurrentAuthSession.mVendorCodeEscrow = vendorCode;
if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
final boolean errorLockout = error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
@@ -1148,20 +1168,20 @@ public class BiometricService extends SystemService {
if (mCurrentAuthSession.isAllowDeviceCredential() && errorLockout) {
// SystemUI handles transition from biometric to device credential.
mCurrentAuthSession.mState = STATE_SHOWING_DEVICE_CREDENTIAL;
- mStatusBarService.onBiometricError(error, message);
+ mStatusBarService.onBiometricError(modality, error, vendorCode);
} else {
mCurrentAuthSession.mState = STATE_ERROR_PENDING_SYSUI;
if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
mStatusBarService.hideAuthenticationDialog();
} else {
- mStatusBarService.onBiometricError(error, message);
+ mStatusBarService.onBiometricError(modality, error, vendorCode);
}
}
} else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
// In the "try again" state, we should forward canceled errors to
// the client and and clean up. The only error we should get here is
// ERROR_CANCELED due to another client kicking us out.
- mCurrentAuthSession.mClientReceiver.onError(error, message);
+ mCurrentAuthSession.mClientReceiver.onError(modality, error, vendorCode);
mStatusBarService.hideAuthenticationDialog();
mCurrentAuthSession = null;
} else if (mCurrentAuthSession.mState == STATE_SHOWING_DEVICE_CREDENTIAL) {
@@ -1197,7 +1217,7 @@ public class BiometricService extends SystemService {
mCurrentAuthSession.mUserId,
mCurrentAuthSession.mOpPackageName);
} else {
- mPendingAuthSession.mClientReceiver.onError(error, message);
+ mPendingAuthSession.mClientReceiver.onError(modality, error, vendorCode);
mPendingAuthSession = null;
}
} else {
@@ -1261,8 +1281,10 @@ public class BiometricService extends SystemService {
case BiometricPrompt.DISMISSED_REASON_USER_CANCEL:
mCurrentAuthSession.mClientReceiver.onError(
+ mCurrentAuthSession.mModality,
BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
- getContext().getString(R.string.biometric_error_user_canceled));
+ 0 /* vendorCode */
+ );
// Cancel authentication. Skip the token/package check since we are cancelling
// from system server. The interface is permission protected so this is fine.
cancelInternal(null /* token */, null /* package */, false /* fromClient */);
@@ -1270,8 +1292,11 @@ public class BiometricService extends SystemService {
case BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED:
case BiometricPrompt.DISMISSED_REASON_ERROR:
- mCurrentAuthSession.mClientReceiver.onError(mCurrentAuthSession.mErrorEscrow,
- mCurrentAuthSession.mErrorStringEscrow);
+ mCurrentAuthSession.mClientReceiver.onError(
+ mCurrentAuthSession.mModality,
+ mCurrentAuthSession.mErrorEscrow,
+ mCurrentAuthSession.mVendorCodeEscrow
+ );
break;
default:
@@ -1354,30 +1379,35 @@ public class BiometricService extends SystemService {
mPendingAuthSession = null;
mCurrentAuthSession.mState = STATE_AUTH_STARTED;
- try {
- int modality = TYPE_NONE;
- it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
- if (pair.getKey() == TYPE_FINGERPRINT) {
- mFingerprintService.startPreparedClient(pair.getValue());
- } else if (pair.getKey() == TYPE_IRIS) {
- Slog.e(TAG, "Iris unsupported");
- } else if (pair.getKey() == TYPE_FACE) {
- mFaceService.startPreparedClient(pair.getValue());
- } else {
- Slog.e(TAG, "Unknown modality: " + pair.getKey());
+ int modality = TYPE_NONE;
+ it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
+ boolean foundAuthenticator = false;
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ if (authenticator.modality == pair.getKey()) {
+ foundAuthenticator = true;
+ try {
+ authenticator.impl.startPreparedClient(pair.getValue());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
}
- modality |= pair.getKey();
}
+ if (!foundAuthenticator) {
+ Slog.e(TAG, "Unknown modality: " + pair.getKey());
+ }
+ modality |= pair.getKey();
+ }
- if (!continuing) {
+ if (!continuing) {
+ try {
mStatusBarService.showAuthenticationDialog(mCurrentAuthSession.mBundle,
mInternalReceiver, modality, requireConfirmation, userId,
mCurrentAuthSession.mOpPackageName);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
}
}
}
@@ -1387,7 +1417,8 @@ public class BiometricService extends SystemService {
int callingUid, int callingPid, int callingUserId) {
mHandler.post(() -> {
- final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
+ final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId,
+ opPackageName);
final int modality = result.first;
final int error = result.second;
@@ -1400,23 +1431,7 @@ public class BiometricService extends SystemService {
} else if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
// Check for errors, notify callback, and return
try {
- final String hardwareUnavailable =
- getContext().getString(R.string.biometric_error_hw_unavailable);
- switch (error) {
- case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
- receiver.onError(error, hardwareUnavailable);
- break;
- case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
- receiver.onError(error, hardwareUnavailable);
- break;
- case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
- receiver.onError(error,
- getErrorString(modality, error, 0 /* vendorCode */));
- break;
- default:
- Slog.e(TAG, "Unhandled error");
- break;
- }
+ receiver.onError(modality, error, 0 /* vendorCode */);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to send error", e);
}
@@ -1435,41 +1450,41 @@ public class BiometricService extends SystemService {
* modality/modalities to start authenticating with. authenticateInternal() should only be
* used for:
* 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is,
- * invoked, shortly after which BiometricPrompt is shown and authentication starts
+ * invoked, shortly after which BiometricPrompt is shown and authentication starts
* 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown
- * and the user has pressed "try again"
+ * and the user has pressed "try again"
*/
private void authenticateInternal(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
int callingUid, int callingPid, int callingUserId, int modality) {
- try {
- boolean requireConfirmation = bundle.getBoolean(
- BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
- if ((modality & TYPE_FACE) != 0) {
- // Check if the user has forced confirmation to be required in Settings.
- requireConfirmation = requireConfirmation
- || mSettingObserver.getFaceAlwaysRequireConfirmation(userId);
- }
- // Generate random cookies to pass to the services that should prepare to start
- // authenticating. Store the cookie here and wait for all services to "ack"
- // with the cookie. Once all cookies are received, we can show the prompt
- // and let the services start authenticating. The cookie should be non-zero.
- final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
- final int authenticators = bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED);
- Slog.d(TAG, "Creating auth session. Modality: " + modality
- + ", cookie: " + cookie
- + ", authenticators: " + authenticators);
- final HashMap<Integer, Integer> modalities = new HashMap<>();
-
- // If it's only device credential, we don't need to wait - LockSettingsService is
- // always ready to check credential (SystemUI invokes that path).
- if ((authenticators & ~Authenticator.TYPE_CREDENTIAL) != 0) {
- modalities.put(modality, cookie);
- }
- mPendingAuthSession = new AuthSession(modalities, token, sessionId, userId,
- receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
- modality, requireConfirmation);
+ boolean requireConfirmation = bundle.getBoolean(
+ BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
+ if ((modality & TYPE_FACE) != 0) {
+ // Check if the user has forced confirmation to be required in Settings.
+ requireConfirmation = requireConfirmation
+ || mSettingObserver.getFaceAlwaysRequireConfirmation(userId);
+ }
+ // Generate random cookies to pass to the services that should prepare to start
+ // authenticating. Store the cookie here and wait for all services to "ack"
+ // with the cookie. Once all cookies are received, we can show the prompt
+ // and let the services start authenticating. The cookie should be non-zero.
+ final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
+ final int authenticators = bundle.getInt(BiometricPrompt.KEY_AUTHENTICATORS_ALLOWED);
+ Slog.d(TAG, "Creating auth session. Modality: " + modality
+ + ", cookie: " + cookie
+ + ", authenticators: " + authenticators);
+ final HashMap<Integer, Integer> modalities = new HashMap<>();
+
+ // If it's only device credential, we don't need to wait - LockSettingsService is
+ // always ready to check credential (SystemUI invokes that path).
+ if ((authenticators & ~Authenticator.TYPE_CREDENTIAL) != 0) {
+ modalities.put(modality, cookie);
+ }
+ mPendingAuthSession = new AuthSession(modalities, token, sessionId, userId,
+ receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
+ modality, requireConfirmation);
+ try {
if (authenticators == Authenticator.TYPE_CREDENTIAL) {
mPendingAuthSession.mState = STATE_SHOWING_DEVICE_CREDENTIAL;
mCurrentAuthSession = mPendingAuthSession;
@@ -1484,19 +1499,10 @@ public class BiometricService extends SystemService {
mCurrentAuthSession.mOpPackageName);
} else {
mPendingAuthSession.mState = STATE_AUTH_CALLED;
- // No polymorphism :(
- if ((modality & TYPE_FINGERPRINT) != 0) {
- mFingerprintService.prepareForAuthentication(token, sessionId, userId,
- mInternalReceiver, opPackageName, cookie,
- callingUid, callingPid, callingUserId);
- }
- if ((modality & TYPE_IRIS) != 0) {
- Slog.w(TAG, "Iris unsupported");
- }
- if ((modality & TYPE_FACE) != 0) {
- mFaceService.prepareForAuthentication(requireConfirmation,
- token, sessionId, userId, mInternalReceiver, opPackageName,
- cookie, callingUid, callingPid, callingUserId);
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ authenticator.impl.prepareForAuthentication(requireConfirmation, token,
+ sessionId, userId, mInternalReceiver, opPackageName, cookie, callingUid,
+ callingPid, callingUserId);
}
}
} catch (RemoteException e) {
@@ -1517,11 +1523,10 @@ public class BiometricService extends SystemService {
try {
// Send error to client
mCurrentAuthSession.mClientReceiver.onError(
+ mCurrentAuthSession.mModality,
BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_user_canceled)
+ 0 /* vendorCode */
);
-
mCurrentAuthSession = null;
mStatusBarService.hideAuthenticationDialog();
} catch (RemoteException e) {
@@ -1537,30 +1542,25 @@ public class BiometricService extends SystemService {
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
- try {
- if (mCurrentAuthSession == null) {
- Slog.w(TAG, "Skipping cancelInternal");
- return;
- } else if (mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
- Slog.w(TAG, "Skipping cancelInternal, state: " + mCurrentAuthSession.mState);
- return;
- }
+ if (mCurrentAuthSession == null) {
+ Slog.w(TAG, "Skipping cancelInternal");
+ return;
+ } else if (mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+ Slog.w(TAG, "Skipping cancelInternal, state: " + mCurrentAuthSession.mState);
+ return;
+ }
- // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
- // drivers have canceled authentication.
- if ((mCurrentAuthSession.mModality & TYPE_FINGERPRINT) != 0) {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
- }
- if ((mCurrentAuthSession.mModality & TYPE_IRIS) != 0) {
- Slog.w(TAG, "Iris unsupported");
- }
- if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
- mFaceService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
+ // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
+ // drivers have canceled authentication.
+ for (AuthenticatorWrapper authenticator : mAuthenticators) {
+ if ((authenticator.modality & mCurrentAuthSession.mModality) != 0) {
+ try {
+ authenticator.impl.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId, fromClient);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to cancel authentication");
+ }
}
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to cancel authentication");
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/face/FaceAuthenticator.java
new file mode 100644
index 000000000000..5df5b29d58a8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/face/FaceAuthenticator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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 com.android.server.biometrics.face;
+
+import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.face.IFaceService;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * TODO(b/141025588): Add JavaDoc.
+ */
+public final class FaceAuthenticator extends IBiometricAuthenticator.Stub {
+ private final IFaceService mFaceService;
+
+ public FaceAuthenticator(IFaceService faceService) {
+ mFaceService = faceService;
+ }
+
+ @Override
+ public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
+ long sessionId, int userId, IBiometricServiceReceiverInternal wrapperReceiver,
+ String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
+ throws RemoteException {
+ mFaceService.prepareForAuthentication(requireConfirmation, token, sessionId, userId,
+ wrapperReceiver, opPackageName, cookie, callingUid, callingPid, callingUserId);
+ }
+
+ @Override
+ public void startPreparedClient(int cookie) throws RemoteException {
+ mFaceService.startPreparedClient(cookie);
+ }
+
+ @Override
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
+ int callingPid, int callingUserId, boolean fromClient) throws RemoteException {
+ mFaceService.cancelAuthenticationFromService(token, opPackageName, callingUid, callingPid,
+ callingUserId, fromClient);
+ }
+
+ @Override
+ public boolean isHardwareDetected(String opPackageName) throws RemoteException {
+ return mFaceService.isHardwareDetected(opPackageName);
+ }
+
+ @Override
+ public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
+ return mFaceService.hasEnrolledFaces(userId, opPackageName);
+ }
+
+ @Override
+ public void resetLockout(byte[] token) throws RemoteException {
+ mFaceService.resetLockout(token);
+ }
+
+ @Override
+ public void setActiveUser(int uid) throws RemoteException {
+ mFaceService.setActiveUser(uid);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 1b132120f709..a0c8e2325f77 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -20,6 +20,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.RESET_FACE_LOCKOUT;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import android.app.ActivityManager;
import android.app.AppOpsManager;
@@ -538,7 +539,7 @@ public class FaceService extends BiometricServiceBase {
// TODO: refactor out common code here
@Override // Binder call
- public boolean isHardwareDetected(long deviceId, String opPackageName) {
+ public boolean isHardwareDetected(String opPackageName) {
checkPermission(USE_BIOMETRIC_INTERNAL);
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
@@ -752,8 +753,7 @@ public class FaceService extends BiometricServiceBase {
public void onError(long deviceId, int error, int vendorCode, int cookie)
throws RemoteException {
if (getWrapperReceiver() != null) {
- getWrapperReceiver().onError(cookie, error,
- FaceManager.getErrorString(getContext(), error, vendorCode));
+ getWrapperReceiver().onError(cookie, TYPE_FACE, error, vendorCode);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java
new file mode 100644
index 000000000000..6150de151ccc
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintAuthenticator.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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 com.android.server.biometrics.fingerprint;
+
+import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.fingerprint.IFingerprintService;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * TODO(b/141025588): Add JavaDoc.
+ */
+public final class FingerprintAuthenticator extends IBiometricAuthenticator.Stub {
+ private final IFingerprintService mFingerprintService;
+
+ public FingerprintAuthenticator(IFingerprintService fingerprintService) {
+ mFingerprintService = fingerprintService;
+ }
+
+ @Override
+ public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
+ long sessionId, int userId, IBiometricServiceReceiverInternal wrapperReceiver,
+ String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
+ throws RemoteException {
+ mFingerprintService.prepareForAuthentication(token, sessionId, userId, wrapperReceiver,
+ opPackageName, cookie, callingUid, callingPid, callingUserId);
+ }
+
+ @Override
+ public void startPreparedClient(int cookie) throws RemoteException {
+ mFingerprintService.startPreparedClient(cookie);
+ }
+
+ @Override
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
+ int callingPid, int callingUserId, boolean fromClient) throws RemoteException {
+ mFingerprintService.cancelAuthenticationFromService(token, opPackageName, callingUid,
+ callingPid, callingUserId, fromClient);
+ }
+
+ @Override
+ public boolean isHardwareDetected(String opPackageName) throws RemoteException {
+ return mFingerprintService.isHardwareDetected(opPackageName);
+ }
+
+ @Override
+ public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
+ return mFingerprintService.hasEnrolledFingerprints(userId, opPackageName);
+ }
+
+ @Override
+ public void resetLockout(byte[] token) throws RemoteException {
+ mFingerprintService.resetTimeout(token);
+ }
+
+ @Override
+ public void setActiveUser(int uid) throws RemoteException {
+ mFingerprintService.setActiveUser(uid);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index d85af2eb0b32..44797ad97b37 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -22,6 +22,7 @@ import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import android.app.ActivityManager;
import android.app.AlarmManager;
@@ -350,7 +351,7 @@ public class FingerprintService extends BiometricServiceBase {
// TODO: refactor out common code here
@Override // Binder call
- public boolean isHardwareDetected(long deviceId, String opPackageName) {
+ public boolean isHardwareDetected(String opPackageName) {
if (!canUseBiometric(opPackageName, false /* foregroundOnly */,
Binder.getCallingUid(), Binder.getCallingPid(),
UserHandle.getCallingUserId())) {
@@ -480,8 +481,7 @@ public class FingerprintService extends BiometricServiceBase {
public void onError(long deviceId, int error, int vendorCode, int cookie)
throws RemoteException {
if (getWrapperReceiver() != null) {
- getWrapperReceiver().onError(cookie, error,
- FingerprintManager.getErrorString(getContext(), error, vendorCode));
+ getWrapperReceiver().onError(cookie, TYPE_FINGERPRINT, error, vendorCode);
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/iris/IrisAuthenticator.java
new file mode 100644
index 000000000000..c44b8e7227e3
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/iris/IrisAuthenticator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 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 com.android.server.biometrics.iris;
+
+import android.hardware.biometrics.IBiometricAuthenticator;
+import android.hardware.biometrics.IBiometricServiceReceiverInternal;
+import android.hardware.iris.IIrisService;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * TODO(b/141025588): Add JavaDoc.
+ */
+public final class IrisAuthenticator extends IBiometricAuthenticator.Stub {
+ private final IIrisService mIrisService;
+
+ public IrisAuthenticator(IIrisService irisService) {
+ mIrisService = irisService;
+ }
+
+ @Override
+ public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
+ long sessionId, int userId, IBiometricServiceReceiverInternal wrapperReceiver,
+ String opPackageName, int cookie, int callingUid, int callingPid, int callingUserId)
+ throws RemoteException {
+ }
+
+ @Override
+ public void startPreparedClient(int cookie) throws RemoteException {
+ }
+
+ @Override
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, int callingUid,
+ int callingPid, int callingUserId, boolean fromClient) throws RemoteException {
+ }
+
+ @Override
+ public boolean isHardwareDetected(String opPackageName) throws RemoteException {
+ return false;
+ }
+
+ @Override
+ public boolean hasEnrolledTemplates(int userId, String opPackageName) throws RemoteException {
+ return false;
+ }
+
+ @Override
+ public void resetLockout(byte[] token) throws RemoteException {
+ }
+
+ @Override
+ public void setActiveUser(int uid) throws RemoteException {
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 9e88d0c74df3..bb3388cc5b9a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -53,7 +53,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
-import android.app.AppOpsManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -1542,7 +1541,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
};
- final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
for (int i = 0; i < permissionCount; i++) {
final String permName = pkg.requestedPermissions.get(i);
final BasePermission bp;
@@ -1608,16 +1606,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// If this permission was granted by default, make sure it is.
if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+ // PermissionPolicyService will handle the app op for runtime permissions later.
grantRuntimePermissionInternal(permName, packageName, false,
Process.SYSTEM_UID, userId, delayingPermCallback);
- // Allow app op later as we are holding mPackages
- // PermissionPolicyService will handle the app op for foreground/background
- // permissions.
- String appOp = AppOpsManager.permissionToOp(permName);
- if (appOp != null) {
- mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
- AppOpsManager.MODE_ALLOWED));
- }
// If permission review is enabled the permissions for a legacy apps
// are represented as constantly granted runtime ones, so don't revoke.
} else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
@@ -4233,8 +4224,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
@Override
- public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
- @PermissionInfo.Protection int protectionLevel) {
+ public @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
+ @PermissionInfo.Protection int protection) {
ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
synchronized (PermissionManagerService.this.mLock) {
@@ -4244,7 +4235,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
BasePermission bp = mSettings.mPermissions.valueAt(i);
if (bp.perm != null && bp.perm.info != null
- && bp.protectionLevel == protectionLevel) {
+ && bp.perm.info.getProtection() == protection) {
matchingPermissions.add(bp.perm.info);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 04ec5ba04bb6..a807a7e6313c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -291,8 +291,8 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
/** Get all permission that have a certain protection level */
- public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtectionLevel(
- @PermissionInfo.Protection int protectionLevel);
+ public abstract @NonNull ArrayList<PermissionInfo> getAllPermissionWithProtection(
+ @PermissionInfo.Protection int protection);
/**
* Returns the delegate used to influence permission checking.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index b892360ed61e..9b9f93f7b5c4 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -48,12 +48,12 @@ import android.os.UserManagerInternal;
import android.permission.PermissionControllerManager;
import android.provider.Telephony;
import android.telecom.TelecomManager;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseLongArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
@@ -67,6 +67,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
@@ -144,7 +145,7 @@ public final class PermissionPolicyService extends SystemService {
};
final ArrayList<PermissionInfo> dangerousPerms =
- permManagerInternal.getAllPermissionWithProtectionLevel(
+ permManagerInternal.getAllPermissionWithProtection(
PermissionInfo.PROTECTION_DANGEROUS);
try {
@@ -152,7 +153,7 @@ public final class PermissionPolicyService extends SystemService {
for (int i = 0; i < numDangerousPerms; i++) {
PermissionInfo perm = dangerousPerms.get(i);
- if (perm.isRestricted() || perm.backgroundPermission != null) {
+ if (perm.isRuntime()) {
appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
}
if (perm.isSoftRestricted()) {
@@ -389,8 +390,7 @@ public final class PermissionPolicyService extends SystemService {
private final @NonNull PackageManager mPackageManager;
private final @NonNull AppOpsManager mAppOpsManager;
- /** All uid that need to be synchronized */
- private final @NonNull SparseIntArray mAllUids = new SparseIntArray();
+ private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos;
/**
* All ops that need to be flipped to allow.
@@ -428,6 +428,18 @@ public final class PermissionPolicyService extends SystemService {
mContext = context;
mPackageManager = context.getPackageManager();
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+
+ mRuntimePermissionInfos = new ArrayMap<>();
+ PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
+ PermissionManagerServiceInternal.class);
+ List<PermissionInfo> permissionInfos =
+ permissionManagerInternal.getAllPermissionWithProtection(
+ PermissionInfo.PROTECTION_DANGEROUS);
+ int permissionInfosSize = permissionInfos.size();
+ for (int i = 0; i < permissionInfosSize; i++) {
+ PermissionInfo permissionInfo = permissionInfos.get(i);
+ mRuntimePermissionInfos.put(permissionInfo.name, permissionInfo);
+ }
}
/**
@@ -489,7 +501,7 @@ public final class PermissionPolicyService extends SystemService {
* Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
*/
private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull String permissionName) {
- PermissionInfo permissionInfo = getPermissionInfo(permissionName);
+ PermissionInfo permissionInfo = mRuntimePermissionInfos.get(permissionName);
if (permissionInfo == null) {
return;
}
@@ -499,8 +511,7 @@ public final class PermissionPolicyService extends SystemService {
private void addPermissionAppOp(@NonNull PackageInfo packageInfo,
@NonNull PermissionInfo permissionInfo) {
- // TODO: Sync all permissions in the future.
- if (!permissionInfo.isRestricted() && permissionInfo.backgroundPermission == null) {
+ if (!permissionInfo.isRuntime()) {
return;
}
@@ -525,7 +536,7 @@ public final class PermissionPolicyService extends SystemService {
boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, permissionInfo);
if (shouldGrantAppOp) {
if (permissionInfo.backgroundPermission != null) {
- PermissionInfo backgroundPermissionInfo = getPermissionInfo(
+ PermissionInfo backgroundPermissionInfo = mRuntimePermissionInfos.get(
permissionInfo.backgroundPermission);
boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null
&& shouldGrantAppOp(packageInfo, backgroundPermissionInfo);
@@ -552,15 +563,6 @@ public final class PermissionPolicyService extends SystemService {
}
}
- @Nullable
- private PermissionInfo getPermissionInfo(@NonNull String permissionName) {
- try {
- return mPackageManager.getPermissionInfo(permissionName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo,
@NonNull PermissionInfo permissionInfo) {
String permissionName = permissionInfo.name;
@@ -638,8 +640,6 @@ public final class PermissionPolicyService extends SystemService {
return;
}
- mAllUids.put(pkg.applicationInfo.uid, pkg.applicationInfo.uid);
-
if (pkg.requestedPermissions == null) {
return;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 3c1a6afccda1..489c34359645 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -655,11 +655,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void onBiometricAuthenticated(boolean authenticated, String failureReason) {
+ public void onBiometricAuthenticated() {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.onBiometricAuthenticated(authenticated, failureReason);
+ mBar.onBiometricAuthenticated();
} catch (RemoteException ex) {
}
}
@@ -677,11 +677,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void onBiometricError(int errorCode, String error) {
+ public void onBiometricError(int modality, int error, int vendorCode) {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.onBiometricError(errorCode, error);
+ mBar.onBiometricError(modality, error, vendorCode);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 7bdc8a32815a..9dbbf16e7734 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.Slog;
import android.util.TimestampedValue;
@@ -48,9 +48,8 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
// @NonNull after initialize()
private Callback mCallback;
- // NITZ state.
- @Nullable private TimestampedValue<Long> mLastNitzTime;
-
+ // Last phone suggestion.
+ @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
// Information about the last time signal received: Used when toggling auto-time.
@Nullable private TimestampedValue<Long> mLastSystemClockTime;
@@ -65,46 +64,40 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
@Override
- public void suggestTime(@NonNull TimeSignal timeSignal) {
- if (!TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId())) {
- Slog.w(TAG, "Ignoring signal from unsupported source: " + timeSignal);
- return;
- }
-
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
// NITZ logic
- TimestampedValue<Long> newNitzUtcTime = timeSignal.getUtcTime();
- boolean nitzTimeIsValid = validateNewNitzTime(newNitzUtcTime, mLastNitzTime);
- if (!nitzTimeIsValid) {
+ boolean timeSuggestionIsValid =
+ validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
+ if (!timeSuggestionIsValid) {
return;
}
// Always store the last NITZ value received, regardless of whether we go on to use it to
// update the system clock. This is so that we can validate future NITZ signals.
- mLastNitzTime = newNitzUtcTime;
+ mLastPhoneSuggestion = timeSuggestion;
// System clock update logic.
// Historically, Android has sent a telephony broadcast only when setting the time using
// NITZ.
- final boolean sendNetworkBroadcast =
- TimeSignal.SOURCE_ID_NITZ.equals(timeSignal.getSourceId());
+ final boolean sendNetworkBroadcast = true;
- final TimestampedValue<Long> newUtcTime = newNitzUtcTime;
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
}
- private static boolean validateNewNitzTime(TimestampedValue<Long> newNitzUtcTime,
- TimestampedValue<Long> lastNitzTime) {
+ private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
+ @Nullable PhoneTimeSuggestion lastSuggestion) {
- if (lastNitzTime != null) {
- long referenceTimeDifference =
- TimestampedValue.referenceTimeDifference(newNitzUtcTime, lastNitzTime);
+ if (lastSuggestion != null) {
+ long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
+ newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
// Out of order or bogus.
Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+ " referenceTimeDifference=" + referenceTimeDifference
- + " lastNitzTime=" + lastNitzTime
- + " newNitzUtcTime=" + newNitzUtcTime);
+ + " lastSuggestion=" + lastSuggestion
+ + " newSuggestion=" + newSuggestion);
return false;
}
}
@@ -182,7 +175,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
@Override
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
- pw.println("mLastNitzTime=" + mLastNitzTime);
+ pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
pw.println("mLastSystemClockTimeSendNetworkBroadcast="
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 9c830003cab4..ee42279f7d50 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,7 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
@@ -96,14 +96,14 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
@Override
- public void suggestTime(@NonNull TimeSignal timeSignal) {
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
enforceSetTimePermission();
Objects.requireNonNull(timeSignal);
long idToken = Binder.clearCallingIdentity();
try {
synchronized (mStrategyLock) {
- mTimeDetectorStrategy.suggestTime(timeSignal);
+ mTimeDetectorStrategy.suggestPhoneTime(timeSignal);
}
} finally {
Binder.restoreCallingIdentity(idToken);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index e050865d96c7..7c2a945854f5 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,7 +18,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.TimestampedValue;
@@ -72,7 +72,7 @@ public interface TimeDetectorStrategy {
void initialize(@NonNull Callback callback);
/** Process the suggested time. */
- void suggestTime(@NonNull TimeSignal timeSignal);
+ void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionToggle(boolean enabled);
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 1bc36bbcd57c..887ece544d3e 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2086,7 +2086,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final TaskRecord task = r.getTaskRecord();
final ActivityStack stack = task.getStack();
- r.mLaunchTaskBehind = false;
mRecentTasks.add(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 12579e6b4058..b7d25c374a15 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -247,7 +247,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
"startRecentsActivity");
mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner,
this, mDefaultDisplay.mDisplayId,
- mStackSupervisor.mRecentTasks.getRecentTaskIds());
+ mStackSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity);
// If we updated the launch-behind state, update the visibility of the activities after
// we fetch the visible tasks to be controlled by the animation
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 9a58a68995fe..7a3e43b127f4 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -358,7 +358,8 @@ public class RecentsAnimationController implements DeathRecipient {
* because it may call cancelAnimation() which needs to properly clean up the controller
* in the window manager.
*/
- public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
+ public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds,
+ ActivityRecord targetActivity) {
mTargetActivityType = targetActivityType;
mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
@@ -400,16 +401,12 @@ public class RecentsAnimationController implements DeathRecipient {
}
// Adjust the wallpaper visibility for the showing target activity
- final ActivityRecord recentsComponentActivity =
- targetStack.getTopChild().getTopFullscreenActivity();
- if (recentsComponentActivity != null) {
- ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
- "setHomeApp(%s)", recentsComponentActivity.getName());
- mTargetActivityRecord = recentsComponentActivity;
- if (recentsComponentActivity.windowsCanBeWallpaperTarget()) {
- mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- mDisplayContent.setLayoutNeeded();
- }
+ ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+ "setHomeApp(%s)", targetActivity.getName());
+ mTargetActivityRecord = targetActivity;
+ if (targetActivity.windowsCanBeWallpaperTarget()) {
+ mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ mDisplayContent.setLayoutNeeded();
}
// Save the minimized home height
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e90f3da96409..63ce1b1c7ad7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2652,11 +2652,11 @@ public class WindowManagerService extends IWindowManager.Stub
void initializeRecentsAnimation(int targetActivityType,
IRecentsAnimationRunner recentsAnimationRunner,
RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId,
- SparseBooleanArray recentTaskIds) {
+ SparseBooleanArray recentTaskIds, ActivityRecord targetActivity) {
mRecentsAnimationController = new RecentsAnimationController(this, recentsAnimationRunner,
callbacks, displayId);
mRoot.getDisplayContent(displayId).mAppTransition.updateBooster();
- mRecentsAnimationController.initialize(targetActivityType, recentTaskIds);
+ mRecentsAnimationController.initialize(targetActivityType, recentTaskIds, targetActivity);
}
@VisibleForTesting
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 4aeeb0af1bf8..ec47a959de30 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -33,7 +33,6 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -43,17 +42,15 @@ import android.hardware.biometrics.Authenticator;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricAuthenticator;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IBiometricServiceReceiverInternal;
-import android.hardware.face.FaceManager;
-import android.hardware.face.IFaceService;
import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintService;
import android.os.Binder;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.security.KeyStore;
import androidx.test.InstrumentationRegistry;
@@ -68,8 +65,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
-
@SmallTest
public class BiometricServiceTest {
@@ -98,71 +93,33 @@ public class BiometricServiceTest {
@Mock
private PackageManager mPackageManager;
@Mock
- private AppOpsManager mAppOpsManager;
- @Mock
IBiometricServiceReceiver mReceiver1;
@Mock
IBiometricServiceReceiver mReceiver2;
@Mock
- FingerprintManager mFingerprintManager;
+ BiometricService.Injector mInjector;
@Mock
- FaceManager mFaceManager;
-
- private static class MockInjector extends BiometricService.Injector {
- @Override
- IActivityManager getActivityManagerService() {
- return mock(IActivityManager.class);
- }
-
- @Override
- IStatusBarService getStatusBarService() {
- return mock(IStatusBarService.class);
- }
-
- @Override
- IFingerprintService getFingerprintService() {
- return mock(IFingerprintService.class);
- }
-
- @Override
- IFaceService getFaceService() {
- return mock(IFaceService.class);
- }
-
- @Override
- BiometricService.SettingObserver getSettingObserver(Context context, Handler handler,
- List<BiometricService.EnabledOnKeyguardCallback> callbacks) {
- return mock(BiometricService.SettingObserver.class);
- }
-
- @Override
- KeyStore getKeyStore() {
- return mock(KeyStore.class);
- }
-
- @Override
- boolean isDebugEnabled(Context context, int userId) {
- return false;
- }
-
- @Override
- void publishBinderService(BiometricService service, IBiometricService.Stub impl) {
- // no-op for test
- }
- }
+ IBiometricAuthenticator mFingerprintAuthenticator;
+ @Mock
+ IBiometricAuthenticator mFaceAuthenticator;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
- when(mContext.getSystemService(Context.FINGERPRINT_SERVICE))
- .thenReturn(mFingerprintManager);
- when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(mFaceManager);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
when(mContext.getResources()).thenReturn(mResources);
+ when(mInjector.getActivityManagerService()).thenReturn(mock(IActivityManager.class));
+ when(mInjector.getStatusBarService()).thenReturn(mock(IStatusBarService.class));
+ when(mInjector.getFingerprintAuthenticator()).thenReturn(mFingerprintAuthenticator);
+ when(mInjector.getFaceAuthenticator()).thenReturn(mFaceAuthenticator);
+ when(mInjector.getSettingObserver(any(), any(), any())).thenReturn(
+ mock(BiometricService.SettingObserver.class));
+ when(mInjector.getKeyStore()).thenReturn(mock(KeyStore.class));
+ when(mInjector.isDebugEnabled(any(), anyInt())).thenReturn(false);
+
when(mResources.getString(R.string.biometric_error_hw_unavailable))
.thenReturn(ERROR_HW_UNAVAILABLE);
when(mResources.getString(R.string.biometric_not_recognized))
@@ -172,61 +129,69 @@ public class BiometricServiceTest {
}
@Test
- public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws Exception {
+ public void testAuthenticate_withoutHardware_returnsErrorHardwareNotPresent() throws
+ Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
.thenReturn(false);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)).thenReturn(false);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
waitForIdle();
verify(mReceiver1).onError(
- eq(BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT), eq(ERROR_HW_UNAVAILABLE));
+ eq(BiometricAuthenticator.TYPE_NONE),
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT),
+ eq(0 /* vendorCode */));
}
@Test
public void testAuthenticate_withoutEnrolled_returnsErrorNoBiometrics() throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
- when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
waitForIdle();
verify(mReceiver1).onError(
- eq(BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS), any());
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
+ eq(BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS),
+ eq(0 /* vendorCode */));
}
@Test
- public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws Exception {
+ public void testAuthenticate_whenHalIsDead_returnsErrorHardwareUnavailable() throws
+ Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
- when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(false);
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
waitForIdle();
verify(mReceiver1).onError(
- eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+ eq(BiometricAuthenticator.TYPE_NONE),
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE),
+ eq(0 /* vendorCode */));
}
@Test
public void testAuthenticateFace_respectsUserSetting()
throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
- when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
// Disabled in user settings receives onError
@@ -235,7 +200,9 @@ public class BiometricServiceTest {
false /* allowDeviceCredential */);
waitForIdle();
verify(mReceiver1).onError(
- eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE), eq(ERROR_HW_UNAVAILABLE));
+ eq(BiometricAuthenticator.TYPE_NONE),
+ eq(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE),
+ eq(0 /* vendorCode */));
// Enrolled, not disabled in settings, user requires confirmation in settings
resetReceiver();
@@ -245,8 +212,8 @@ public class BiometricServiceTest {
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
waitForIdle();
- verify(mReceiver1, never()).onError(anyInt(), any(String.class));
- verify(mBiometricService.mFaceService).prepareForAuthentication(
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
+ verify(mBiometricService.mAuthenticators.get(0).impl).prepareForAuthentication(
eq(true) /* requireConfirmation */,
any(IBinder.class),
anyLong() /* sessionId */,
@@ -265,7 +232,7 @@ public class BiometricServiceTest {
invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
false /* allowDeviceCredential */);
waitForIdle();
- verify(mBiometricService.mFaceService).prepareForAuthentication(
+ verify(mBiometricService.mAuthenticators.get(0).impl).prepareForAuthentication(
eq(false) /* requireConfirmation */,
any(IBinder.class),
anyLong() /* sessionId */,
@@ -281,7 +248,7 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
// Start testing the happy path
@@ -295,8 +262,9 @@ public class BiometricServiceTest {
// Invokes <Modality>Service#prepareForAuthentication
ArgumentCaptor<Integer> cookieCaptor = ArgumentCaptor.forClass(Integer.class);
- verify(mReceiver1, never()).onError(anyInt(), any(String.class));
- verify(mBiometricService.mFingerprintService).prepareForAuthentication(
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
+ verify(mBiometricService.mAuthenticators.get(0).impl).prepareForAuthentication(
+ anyBoolean() /* requireConfirmation */,
any(IBinder.class),
anyLong() /* sessionId */,
anyInt() /* userId */,
@@ -316,7 +284,7 @@ public class BiometricServiceTest {
BiometricService.STATE_AUTH_STARTED);
// startPreparedClient invoked
- verify(mBiometricService.mFingerprintService)
+ verify(mBiometricService.mAuthenticators.get(0).impl)
.startPreparedClient(cookieCaptor.getValue());
// StatusBar showBiometricDialog invoked
@@ -337,8 +305,7 @@ public class BiometricServiceTest {
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_AUTHENTICATED_PENDING_SYSUI);
// Notify SystemUI hardware authenticated
- verify(mBiometricService.mStatusBarService).onBiometricAuthenticated(
- eq(true) /* authenticated */, eq(null) /* failureReason */);
+ verify(mBiometricService.mStatusBarService).onBiometricAuthenticated();
// SystemUI sends callback with dismissed reason
mBiometricService.mInternalReceiver.onDialogDismissed(
@@ -355,7 +322,7 @@ public class BiometricServiceTest {
@Test
public void testAuthenticate_noBiometrics_credentialAllowed() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
- when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(false);
+ when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(false);
invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
true /* requireConfirmation */, true /* allowDeviceCredential */);
waitForIdle();
@@ -409,8 +376,10 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onAuthenticationFailed();
waitForIdle();
- verify(mBiometricService.mStatusBarService)
- .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+ verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_NONE),
+ eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED),
+ eq(0 /* vendorCode */));
verify(mReceiver1).onAuthenticationFailed();
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_AUTH_PAUSED);
@@ -426,15 +395,18 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onAuthenticationFailed();
waitForIdle();
- verify(mBiometricService.mStatusBarService)
- .onBiometricAuthenticated(eq(false), eq(ERROR_NOT_RECOGNIZED));
+ verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_NONE),
+ eq(BiometricConstants.BIOMETRIC_PAUSED_REJECTED),
+ eq(0 /* vendorCode */));
verify(mReceiver1).onAuthenticationFailed();
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_AUTH_STARTED);
}
@Test
- public void testErrorCanceled_whenAuthenticating_notifiesSystemUIAndClient() throws Exception {
+ public void testErrorCanceled_whenAuthenticating_notifiesSystemUIAndClient() throws
+ Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, false /* allowDeviceCredential */);
@@ -451,15 +423,15 @@ public class BiometricServiceTest {
BiometricService.STATE_AUTH_STARTED);
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
- BiometricConstants.BIOMETRIC_ERROR_CANCELED, ERROR_CANCELED);
+ BiometricAuthenticator.TYPE_FINGERPRINT,
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED, 0 /* vendorCode */);
waitForIdle();
// Auth session doesn't become null until SystemUI responds that the animation is completed
assertNotNull(mBiometricService.mCurrentAuthSession);
// ERROR_CANCELED is not sent until SystemUI responded that animation is completed
- verify(mReceiver1, never()).onError(
- anyInt(), anyString());
- verify(mReceiver2, never()).onError(anyInt(), any(String.class));
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
+ verify(mReceiver2, never()).onError(anyInt(), anyInt(), anyInt());
// SystemUI dialog closed
verify(mBiometricService.mStatusBarService).hideAuthenticationDialog();
@@ -469,8 +441,9 @@ public class BiometricServiceTest {
.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_SERVER_REQUESTED);
waitForIdle();
verify(mReceiver1).onError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
- eq(ERROR_CANCELED));
+ eq(0 /* vendorCode */));
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -482,14 +455,17 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
- ERROR_TIMEOUT);
+ 0 /* vendorCode */);
waitForIdle();
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_AUTH_PAUSED);
- verify(mBiometricService.mStatusBarService)
- .onBiometricAuthenticated(eq(false), eq(ERROR_TIMEOUT));
+ verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_FACE),
+ eq(BiometricConstants.BIOMETRIC_ERROR_TIMEOUT),
+ eq(0 /* vendorCode */));
// Timeout does not count as fail as per BiometricPrompt documentation.
verify(mReceiver1, never()).onAuthenticationFailed();
@@ -524,22 +500,25 @@ public class BiometricServiceTest {
public void testErrorFromHal_whenPaused_notifiesSystemUIAndClient() throws Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
- false /* requireCOnfirmation */, false /* allowDeviceCredential */);
+ false /* requireConfirmation */, false /* allowDeviceCredential */);
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
- ERROR_TIMEOUT);
+ 0 /* vendorCode */);
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- ERROR_CANCELED);
+ 0 /* vendorCode */);
waitForIdle();
// Client receives error immediately
verify(mReceiver1).onError(
+ eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_CANCELED),
- eq(ERROR_CANCELED));
+ eq(0 /* vendorCode */));
// Dialog is hidden immediately
verify(mBiometricService.mStatusBarService).hideAuthenticationDialog();
// Auth session is over
@@ -558,26 +537,29 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FINGERPRINT,
BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS,
- ERROR_UNABLE_TO_PROCESS);
+ 0 /* vendorCode */);
waitForIdle();
// Sends error to SystemUI and does not notify client yet
assertEquals(mBiometricService.mCurrentAuthSession.mState,
BiometricService.STATE_ERROR_PENDING_SYSUI);
verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
- eq(ERROR_UNABLE_TO_PROCESS));
+ eq(0 /* vendorCode */));
verify(mBiometricService.mStatusBarService, never()).hideAuthenticationDialog();
- verify(mReceiver1, never()).onError(anyInt(), anyString());
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
// SystemUI animation completed, client is notified, auth session is over
mBiometricService.mInternalReceiver
.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_ERROR);
waitForIdle();
verify(mReceiver1).onError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
- eq(ERROR_UNABLE_TO_PROCESS));
+ eq(0 /* vendorCode */));
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -590,8 +572,9 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForPendingSession(mBiometricService.mPendingAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
- ERROR_LOCKOUT);
+ 0 /* vendorCode */);
waitForIdle();
// Pending auth session becomes current auth session, since device credential should
@@ -622,8 +605,9 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForPendingSession(mBiometricService.mPendingAuthSession),
+ BiometricAuthenticator.TYPE_FINGERPRINT,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
- ERROR_LOCKOUT);
+ 0 /* vendorCode */);
waitForIdle();
// Error is sent to client
@@ -690,17 +674,18 @@ public class BiometricServiceTest {
assertEquals(BiometricService.STATE_SHOWING_DEVICE_CREDENTIAL,
mBiometricService.mCurrentAuthSession.mState);
- verify(mReceiver1, never()).onError(anyInt(), anyString());
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FINGERPRINT,
BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- ERROR_CANCELED);
+ 0 /* vendorCode */);
waitForIdle();
assertEquals(BiometricService.STATE_SHOWING_DEVICE_CREDENTIAL,
mBiometricService.mCurrentAuthSession.mState);
- verify(mReceiver1, never()).onError(anyInt(), anyString());
+ verify(mReceiver1, never()).onError(anyInt(), anyInt(), anyInt());
}
@Test
@@ -714,15 +699,17 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FINGERPRINT,
BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
- ERROR_LOCKOUT);
+ 0 /* vendorCode */);
waitForIdle();
assertEquals(BiometricService.STATE_SHOWING_DEVICE_CREDENTIAL,
mBiometricService.mCurrentAuthSession.mState);
verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_LOCKOUT),
- eq(ERROR_LOCKOUT));
+ eq(0 /* vendorCode */));
}
@Test
@@ -736,15 +723,17 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FINGERPRINT,
BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS,
- ERROR_UNABLE_TO_PROCESS);
+ 0 /* vendorCode */);
waitForIdle();
assertEquals(BiometricService.STATE_ERROR_PENDING_SYSUI,
mBiometricService.mCurrentAuthSession.mState);
verify(mBiometricService.mStatusBarService).onBiometricError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_PROCESS),
- eq(ERROR_UNABLE_TO_PROCESS));
+ eq(0 /* vendorCode */));
}
@Test
@@ -758,9 +747,10 @@ public class BiometricServiceTest {
.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
waitForIdle();
verify(mReceiver1).onError(
+ eq(BiometricAuthenticator.TYPE_FINGERPRINT),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
- eq(ERROR_USER_CANCELED));
- verify(mBiometricService.mFingerprintService).cancelAuthenticationFromService(
+ eq(0 /* vendorCode */));
+ verify(mBiometricService.mAuthenticators.get(0).impl).cancelAuthenticationFromService(
any(),
any(),
anyInt(),
@@ -778,13 +768,15 @@ public class BiometricServiceTest {
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
- ERROR_TIMEOUT);
+ 0 /* vendorCode */);
mBiometricService.mInternalReceiver.onDialogDismissed(
BiometricPrompt.DISMISSED_REASON_NEGATIVE);
waitForIdle();
- verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ verify(mBiometricService.mAuthenticators.get(0).impl,
+ never()).cancelAuthenticationFromService(
any(),
any(),
anyInt(),
@@ -794,20 +786,23 @@ public class BiometricServiceTest {
}
@Test
- public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws Exception {
+ public void testDismissedReasonUserCancel_whilePaused_doesntInvokeHalCancel() throws
+ Exception {
setupAuthForOnly(BiometricAuthenticator.TYPE_FACE);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, false /* allowDeviceCredential */);
mBiometricService.mInternalReceiver.onError(
getCookieForCurrentSession(mBiometricService.mCurrentAuthSession),
+ BiometricAuthenticator.TYPE_FACE,
BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
- ERROR_TIMEOUT);
+ 0 /* vendorCode */);
mBiometricService.mInternalReceiver.onDialogDismissed(
BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
waitForIdle();
- verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ verify(mBiometricService.mAuthenticators.get(0).impl,
+ never()).cancelAuthenticationFromService(
any(),
any(),
anyInt(),
@@ -830,7 +825,8 @@ public class BiometricServiceTest {
waitForIdle();
// doesn't send cancel to HAL
- verify(mBiometricService.mFaceService, never()).cancelAuthenticationFromService(
+ verify(mBiometricService.mAuthenticators.get(0).impl,
+ never()).cancelAuthenticationFromService(
any(),
any(),
anyInt(),
@@ -838,8 +834,9 @@ public class BiometricServiceTest {
anyInt(),
anyBoolean());
verify(mReceiver1).onError(
+ eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
- eq(ERROR_USER_CANCELED));
+ eq(0 /* vendorCode */));
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -863,7 +860,7 @@ public class BiometricServiceTest {
// Helper methods
- private void setupAuthForOnly(int modality) {
+ private void setupAuthForOnly(int modality) throws RemoteException {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
.thenReturn(false);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
@@ -871,17 +868,17 @@ public class BiometricServiceTest {
if (modality == BiometricAuthenticator.TYPE_FINGERPRINT) {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
.thenReturn(true);
- when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ when(mFingerprintAuthenticator.isHardwareDetected(any())).thenReturn(true);
} else if (modality == BiometricAuthenticator.TYPE_FACE) {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
- when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
- when(mFaceManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceAuthenticator.hasEnrolledTemplates(anyInt(), any())).thenReturn(true);
+ when(mFaceAuthenticator.isHardwareDetected(any())).thenReturn(true);
} else {
fail("Unknown modality: " + modality);
}
- mBiometricService = new BiometricService(mContext, new MockInjector());
+ mBiometricService = new BiometricService(mContext, mInjector);
mBiometricService.onStart();
when(mBiometricService.mSettingObserver.getFaceEnabledForApps(anyInt())).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index 9e000770fe42..d79795593456 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.icu.util.Calendar;
import android.icu.util.GregorianCalendar;
@@ -45,6 +45,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
.setActualTimeUtc(2018, 1, 1, 12, 0, 0)
.build();
+ private static final int ARBITRARY_PHONE_ID = 123456;
+
private Script mScript;
@Before
@@ -53,30 +55,32 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestTime_nitz_timeDetectionEnabled() {
+ public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
+ PhoneTimeSuggestion timeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
final int clockIncrement = 1000;
long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
mScript.simulateTimePassing(clockIncrement)
- .simulateTimeSignalReceived(timeSignal)
+ .simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
}
@Test
- public void testSuggestTime_systemClockThreshold() {
+ public void testSuggestPhoneTime_systemClockThreshold() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThresholdMillis = 1000;
mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThresholdMillis)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
final int clockIncrement = 100;
// Increment the the device clocks to simulate the passage of time.
@@ -86,7 +90,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
// Send the first time signal. It should be used.
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
// Now send another time signal, but one that is too similar to the last one and should be
@@ -95,9 +99,9 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + underThresholdMillis);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulateTimePassing(clockIncrement)
- .simulateTimeSignalReceived(timeSignal2)
+ .simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now send another time signal, but one that is on the threshold and so should be used.
@@ -105,42 +109,44 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
- TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
+ PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimePassing(clockIncrement);
long expectSystemClockMillis3 =
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
- mScript.simulateTimeSignalReceived(timeSignal3)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
}
@Test
- public void testSuggestTime_nitz_timeDetectionDisabled() {
+ public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(false);
- TimeSignal timeSignal = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- mScript.simulateTimeSignalReceived(timeSignal)
+ PhoneTimeSuggestion timeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
- public void testSuggestTime_nitz_invalidNitzReferenceTimesIgnored() {
+ public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(scenario)
.pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(true);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Initialize the strategy / device with a time set from NITZ.
mScript.simulateTimePassing(100);
long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
// The UTC time increment should be larger than the system clock update threshold so we
@@ -152,8 +158,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
- mScript.simulateTimeSignalReceived(timeSignal2)
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Now supply a new signal that has an obviously bogus reference time : substantially in the
@@ -162,8 +168,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis);
- TimeSignal timeSignal3 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime3);
- mScript.simulateTimeSignalReceived(timeSignal3)
+ PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking();
// Just to prove validUtcTimeMillis is valid.
@@ -172,13 +178,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
validReferenceTimeMillis, validUtcTimeMillis);
long expectedSystemClockMillis4 =
TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
- TimeSignal timeSignal4 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime4);
- mScript.simulateTimeSignalReceived(timeSignal4)
+ PhoneTimeSuggestion timeSuggestion4 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
}
@Test
- public void testSuggestTime_timeDetectionToggled() {
+ public void testSuggestPhoneTime_timeDetectionToggled() {
Scenario scenario = SCENARIO_1;
final int clockIncrementMillis = 100;
final int systemClockUpdateThreshold = 2000;
@@ -186,15 +192,16 @@ public class SimpleTimeZoneDetectorStrategyTest {
.pokeThresholds(systemClockUpdateThreshold)
.pokeTimeDetectionEnabled(false);
- TimeSignal timeSignal1 = scenario.createTimeSignalForActual(TimeSignal.SOURCE_ID_NITZ);
- TimestampedValue<Long> utcTime1 = timeSignal1.getUtcTime();
+ PhoneTimeSuggestion timeSuggestion1 =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ TimestampedValue<Long> utcTime1 = timeSuggestion1.getUtcTime();
// Simulate time passing.
mScript.simulateTimePassing(clockIncrementMillis);
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
- mScript.simulateTimeSignalReceived(timeSignal1)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasNotSetAndResetCallTracking();
// Simulate more time passing.
@@ -216,7 +223,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
- TimeSignal timeSignal2 = new TimeSignal(TimeSignal.SOURCE_ID_NITZ, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -226,7 +233,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
- mScript.simulateTimeSignalReceived(timeSignal2)
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
// Turn on auto time detection.
@@ -234,17 +241,6 @@ public class SimpleTimeZoneDetectorStrategyTest {
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
}
- @Test
- public void testSuggestTime_unknownSource() {
- Scenario scenario = SCENARIO_1;
- mScript.pokeFakeClocks(scenario)
- .pokeTimeDetectionEnabled(true);
-
- TimeSignal timeSignal = scenario.createTimeSignalForActual("unknown");
- mScript.simulateTimeSignalReceived(timeSignal)
- .verifySystemClockWasNotSetAndResetCallTracking();
- }
-
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -407,8 +403,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mFakeCallback.peekSystemClockMillis();
}
- Script simulateTimeSignalReceived(TimeSignal timeSignal) {
- mSimpleTimeDetectorStrategy.suggestTime(timeSignal);
+ Script simulatePhoneTimeSuggestion(PhoneTimeSuggestion timeSuggestion) {
+ mSimpleTimeDetectorStrategy.suggestPhoneTime(timeSuggestion);
return this;
}
@@ -466,10 +462,10 @@ public class SimpleTimeZoneDetectorStrategyTest {
return mActualTimeMillis;
}
- TimeSignal createTimeSignalForActual(String sourceId) {
+ PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
TimestampedValue<Long> time = new TimestampedValue<>(
mInitialDeviceRealtimeMillis, mActualTimeMillis);
- return new TimeSignal(sourceId, time);
+ return new PhoneTimeSuggestion(phoneId, time);
}
static class Builder {
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 45fef764482f..37da01824e88 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -28,7 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.timedetector.TimeSignal;
+import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
import android.util.TimestampedValue;
@@ -67,10 +67,10 @@ public class TimeDetectorServiceTest {
public void testStubbedCall_withoutPermission() {
doThrow(new SecurityException("Mock"))
.when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeSignal timeSignal = createNitzTimeSignal();
+ PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
try {
- mTimeDetectorService.suggestTime(timeSignal);
+ mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
} finally {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME), anyString());
@@ -78,15 +78,15 @@ public class TimeDetectorServiceTest {
}
@Test
- public void testSuggestTime() {
+ public void testSuggestPhoneTime() {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
- TimeSignal timeSignal = createNitzTimeSignal();
- mTimeDetectorService.suggestTime(timeSignal);
+ PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
+ mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
verify(mMockContext)
.enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
- mStubbedTimeDetectorStrategy.verifySuggestTimeCalled(timeSignal);
+ mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
}
@Test
@@ -115,15 +115,16 @@ public class TimeDetectorServiceTest {
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
}
- private static TimeSignal createNitzTimeSignal() {
+ private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
+ int phoneId = 1234;
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
- return new TimeSignal(TimeSignal.SOURCE_ID_NITZ, timeValue);
+ return new PhoneTimeSuggestion(phoneId, timeValue);
}
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
- private TimeSignal mLastSuggestedTime;
+ private PhoneTimeSuggestion mLastPhoneSuggestion;
private Boolean mLastAutoTimeDetectionToggle;
private boolean mDumpCalled;
@@ -132,9 +133,9 @@ public class TimeDetectorServiceTest {
}
@Override
- public void suggestTime(TimeSignal timeSignal) {
+ public void suggestPhoneTime(PhoneTimeSuggestion timeSuggestion) {
resetCallTracking();
- mLastSuggestedTime = timeSignal;
+ mLastPhoneSuggestion = timeSuggestion;
}
@Override
@@ -150,13 +151,13 @@ public class TimeDetectorServiceTest {
}
void resetCallTracking() {
- mLastSuggestedTime = null;
+ mLastPhoneSuggestion = null;
mLastAutoTimeDetectionToggle = null;
mDumpCalled = false;
}
- void verifySuggestTimeCalled(TimeSignal expectedSignal) {
- assertEquals(expectedSignal, mLastSuggestedTime);
+ void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
+ assertEquals(expectedSignal, mLastPhoneSuggestion);
}
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index fff77f56d7c8..702600402d8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -152,7 +152,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
hiddenActivity.setHidden(true);
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
// Ensure that we are animating the target activity as well
assertTrue(mController.isAnimatingTask(homeActivity.getTask()));
@@ -181,7 +181,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeAppWindow);
mController.startAnimation();
// Ensure that we are animating the app and wallpaper target
@@ -210,7 +210,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
mDisplayContent.getConfiguration().windowConfiguration.setRotation(
mDisplayContent.getRotation());
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
mController.startAnimation();
// Cancel the animation and ensure the controller is still running
@@ -242,7 +242,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
doReturn(true).when(mDisplayContent.mWallpaperController).isWallpaperVisible();
// Start and finish the animation
- mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray());
+ mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity);
mController.startAnimation();
// Reset at this point since we may remove adapters that couldn't be created
reset(mController);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index ebedde7d4460..839ddb2038ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -78,7 +78,7 @@ public class RecentsAnimationTest extends ActivityTestsBase {
mRecentsAnimationController = mock(RecentsAnimationController.class);
mService.mWindowManager.setRecentsAnimationController(mRecentsAnimationController);
doNothing().when(mService.mWindowManager).initializeRecentsAnimation(
- anyInt(), any(), any(), anyInt(), any());
+ anyInt(), any(), any(), anyInt(), any(), any());
doReturn(true).when(mService.mWindowManager).canStartRecentsAnimation();
final RecentTasks recentTasks = mService.getRecentTasks();
@@ -385,7 +385,8 @@ public class RecentsAnimationTest extends ActivityTestsBase {
return null;
}).when(mService.mWindowManager).initializeRecentsAnimation(
anyInt() /* targetActivityType */, any() /* recentsAnimationRunner */,
- any() /* callbacks */, anyInt() /* displayId */, any() /* recentTaskIds */);
+ any() /* callbacks */, anyInt() /* displayId */, any() /* recentTaskIds */,
+ any() /* targetActivity */);
}
Intent recentsIntent = new Intent();
diff --git a/tests/BootImageProfileTest/AndroidTest.xml b/tests/BootImageProfileTest/AndroidTest.xml
index c13200778c4b..b4f2663585cc 100644
--- a/tests/BootImageProfileTest/AndroidTest.xml
+++ b/tests/BootImageProfileTest/AndroidTest.xml
@@ -22,8 +22,8 @@
<!-- we need this magic flag, otherwise it always reboots and breaks the selinux -->
<option name="force-skip-system-props" value="true" />
- <option name="run-command" value="setprop dalvik.vm.profilesystemserver true" />
- <option name="run-command" value="setprop dalvik.vm.profilebootclasspath true" />
+ <option name="run-command" value="device_config put runtime_native_boot profilesystemserver true" />
+ <option name="run-command" value="device_config put runtime_native_boot profilebootclasspath true" />
<!-- Profiling does not pick up the above changes we restart the shell -->
<option name="run-command" value="stop" />
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index fe1d9d26c7e7..ccdd452b3f1e 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -46,9 +46,11 @@ public class BootImageProfileTest implements IDeviceTest {
*/
@Test
public void testProperties() throws Exception {
- String res = mTestDevice.getProperty("dalvik.vm.profilebootclasspath");
+ String res = mTestDevice.getProperty(
+ "persist.device_config.runtime_native_boot.profilebootclasspath");
assertTrue("profile boot class path not enabled", res != null && res.equals("true"));
- res = mTestDevice.getProperty("dalvik.vm.profilesystemserver");
+ res = mTestDevice.getProperty(
+ "persist.device_config.runtime_native_boot.profilesystemserver");
assertTrue("profile system server not enabled", res != null && res.equals("true"));
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index db5e7f8d337f..cdc21ef8f971 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -158,18 +158,6 @@ public class StagedRollbackTest {
assertThat(rollback.getCommittedSessionId()).isNotEqualTo(-1);
}
- @Test
- public void resetNetworkStack() throws Exception {
- RollbackManager rm = RollbackUtils.getRollbackManager();
- String networkStack = getNetworkStackPackageName();
-
- rm.expireRollbackForPackage(networkStack);
- Uninstall.packages(networkStack);
-
- assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
- networkStack)).isNull();
- }
-
/**
* Stage install ModuleMetadata package to simulate a Mainline module update.
*/
@@ -210,43 +198,35 @@ public class StagedRollbackTest {
@Test
public void testNetworkFailedRollback_Phase1() throws Exception {
- resetNetworkStack();
- }
-
- @Test
- public void testNetworkFailedRollback_Phase2() throws Exception {
- assertNetworkStackRollbackAvailable();
- }
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ String networkStack = getNetworkStackPackageName();
- @Test
- public void testNetworkFailedRollback_Phase3() throws Exception {
- assertNoNetworkStackRollbackCommitted();
- }
+ rm.expireRollbackForPackage(networkStack);
+ Uninstall.packages(networkStack);
- @Test
- public void testNetworkFailedRollback_Phase4() throws Exception {
- assertNetworkStackRollbackCommitted();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ networkStack)).isNull();
}
@Test
- public void assertNetworkStackRollbackAvailable() throws Exception {
+ public void testNetworkFailedRollback_Phase2() throws Exception {
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
getNetworkStackPackageName())).isNotNull();
}
@Test
- public void assertNetworkStackRollbackCommitted() throws Exception {
+ public void testNetworkFailedRollback_Phase3() throws Exception {
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- getNetworkStackPackageName())).isNotNull();
+ getNetworkStackPackageName())).isNull();
}
@Test
- public void assertNoNetworkStackRollbackCommitted() throws Exception {
+ public void testNetworkFailedRollback_Phase4() throws Exception {
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
- getNetworkStackPackageName())).isNull();
+ getNetworkStackPackageName())).isNotNull();
}
private String getNetworkStackPackageName() {
@@ -294,17 +274,28 @@ public class StagedRollbackTest {
@Test
public void testNetworkPassedDoesNotRollback_Phase1() throws Exception {
- resetNetworkStack();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ String networkStack = getNetworkStackPackageName();
+
+ rm.expireRollbackForPackage(networkStack);
+ Uninstall.packages(networkStack);
+
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ networkStack)).isNull();
}
@Test
public void testNetworkPassedDoesNotRollback_Phase2() throws Exception {
- assertNetworkStackRollbackAvailable();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ getNetworkStackPackageName())).isNotNull();
}
@Test
public void testNetworkPassedDoesNotRollback_Phase3() throws Exception {
- assertNoNetworkStackRollbackCommitted();
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+ getNetworkStackPackageName())).isNull();
}
@Nullable
diff --git a/tools/aapt2/format/Container.cpp b/tools/aapt2/format/Container.cpp
index f1890488276c..9cef7b3d2ce3 100644
--- a/tools/aapt2/format/Container.cpp
+++ b/tools/aapt2/format/Container.cpp
@@ -30,6 +30,7 @@ namespace aapt {
constexpr const static uint32_t kContainerFormatMagic = 0x54504141u;
constexpr const static uint32_t kContainerFormatVersion = 1u;
+constexpr const static size_t kPaddingAlignment = 4u;
ContainerWriter::ContainerWriter(ZeroCopyOutputStream* out, size_t entry_count)
: out_(out), total_entry_count_(entry_count), current_entry_count_(0u) {
@@ -49,11 +50,17 @@ ContainerWriter::ContainerWriter(ZeroCopyOutputStream* out, size_t entry_count)
}
}
-inline static void WritePadding(int padding, CodedOutputStream* out) {
- if (padding < 4) {
- const uint32_t zero = 0u;
- out->WriteRaw(&zero, padding);
- }
+inline static size_t CalculatePaddingForAlignment(size_t size) {
+ size_t overage = size % kPaddingAlignment;
+ return overage == 0 ? 0 : kPaddingAlignment - overage;
+}
+
+inline static void WritePadding(size_t padding, CodedOutputStream* out) {
+ CHECK(padding < kPaddingAlignment);
+ const uint32_t zero = 0u;
+ static_assert(sizeof(zero) >= kPaddingAlignment, "Not enough source bytes for padding");
+
+ out->WriteRaw(&zero, padding);
}
bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) {
@@ -70,7 +77,7 @@ bool ContainerWriter::AddResTableEntry(const pb::ResourceTable& table) {
// Write the aligned size.
const ::google::protobuf::uint64 size = table.ByteSize();
- const int padding = 4 - (size % 4);
+ const int padding = CalculatePaddingForAlignment(size);
coded_out.WriteLittleEndian64(size);
// Write the table.
@@ -103,9 +110,9 @@ bool ContainerWriter::AddResFileEntry(const pb::internal::CompiledFile& file,
// Write the aligned size.
const ::google::protobuf::uint32 header_size = file.ByteSize();
- const int header_padding = 4 - (header_size % 4);
+ const int header_padding = CalculatePaddingForAlignment(header_size);
const ::google::protobuf::uint64 data_size = in->TotalSize();
- const int data_padding = 4 - (data_size % 4);
+ const int data_padding = CalculatePaddingForAlignment(data_size);
coded_out.WriteLittleEndian64(kResFileEntryHeaderSize + header_size + header_padding + data_size +
data_padding);
diff --git a/tools/aapt2/formats.md b/tools/aapt2/formats.md
index bb31a005ef42..25a0e798dea2 100644
--- a/tools/aapt2/formats.md
+++ b/tools/aapt2/formats.md
@@ -23,7 +23,7 @@ boundary, so if a previous entry ends unaligned, padding must be inserted.
| Size (in bytes) | Field | Description |
|:----------------|:---------------|:----------------------------------------------------------------------------------------------------------|
| `4` | `entry_type` | The type of the entry. This can be one of two types: `RES_TABLE (0x00000000)` or `RES_FILE (0x00000001)`. |
-| `8` | `entry_length` | The length of the data that follows. |
+| `8` | `entry_length` | The length of the data that follows. Do not use if `entry_type` is `RES_FILE`; this value may be wrong. |
| `entry_length` | `data` | The payload. The contents of this varies based on the `entry_type`. |
If the `entry_type` is equal to `RES_TABLE (0x00000000)`, the `data` field contains a serialized
@@ -32,13 +32,14 @@ If the `entry_type` is equal to `RES_TABLE (0x00000000)`, the `data` field conta
If the `entry_type` is equal to `RES_FILE (0x00000001)`, the `data` field contains the following:
-| Size (in bytes) | Field | Description |
-|:----------------|:---------------|:----------------------------------------------------------------------------------------------------------|
-| `4` | `header_size` | The size of the `header` field. |
-| `8` | `data_size` | The size of the `data` field. |
-| `header_size` | `header` | The serialized Protobuf message [aapt.pb.internal.CompiledFile](ResourcesInternal.proto). |
-| `x` | `padding` | Up to 4 bytes of zeros, if padding is necessary to align the `data` field on a 32-bit boundary. |
-| `data_size` | `data` | The payload, which is determined by the `type` field in the `aapt.pb.internal.CompiledFile`. This can be a PNG file, binary XML, or [aapt.pb.XmlNode](Resources.proto). |
+| Size (in bytes) | Field | Description |
+|:----------------|:-----------------|:----------------------------------------------------------------------------------------------------------|
+| `4` | `header_size` | The size of the `header` field. |
+| `8` | `data_size` | The size of the `data` field. |
+| `header_size` | `header` | The serialized Protobuf message [aapt.pb.internal.CompiledFile](ResourcesInternal.proto). |
+| `x` | `header_padding` | Up to 3 bytes of zeros, if padding is necessary to align the `data` field on a 32-bit boundary. |
+| `data_size` | `data` | The payload, which is determined by the `type` field in the `aapt.pb.internal.CompiledFile`. This can be a PNG file, binary XML, or [aapt.pb.XmlNode](Resources.proto). |
+| `y` | `data_padding` | Up to 3 bytes of zeros, if `data_size` is not a multiple of 4. |
## AAPT2 Static Library Format (extension `.sapk`)
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index dd9ee3b4d793..04b073be28e2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -38,6 +38,7 @@ import android.net.DhcpInfo;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.NetworkStack;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
@@ -533,7 +534,9 @@ public class WifiManager {
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_INTERFACE_NAME = "wifi_ap_interface_name";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_INTERFACE_NAME =
+ "android.net.wifi.extra.WIFI_AP_INTERFACE_NAME";
/**
* The intended ip mode for this softap.
* @see #IFACE_IP_MODE_TETHERED
@@ -541,7 +544,8 @@ public class WifiManager {
*
* @hide
*/
- public static final String EXTRA_WIFI_AP_MODE = "wifi_ap_mode";
+ @SystemApi
+ public static final String EXTRA_WIFI_AP_MODE = "android.net.wifi.extra.WIFI_AP_MODE";
/** @hide */
@IntDef(flag = false, prefix = { "WIFI_AP_STATE_" }, value = {
@@ -647,6 +651,7 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
public static final int IFACE_IP_MODE_UNSPECIFIED = -1;
/**
@@ -656,6 +661,7 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
/**
@@ -665,6 +671,7 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
public static final int IFACE_IP_MODE_TETHERED = 1;
/**
@@ -674,6 +681,7 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
/**
@@ -2661,16 +2669,21 @@ public class WifiManager {
/**
* Call allowing ConnectivityService to update WifiService with interface mode changes.
*
- * The possible modes include: {@link #IFACE_IP_MODE_TETHERED},
- * {@link #IFACE_IP_MODE_LOCAL_ONLY},
- * {@link #IFACE_IP_MODE_CONFIGURATION_ERROR}
- *
- * @param ifaceName String name of the updated interface
- * @param mode int representing the new mode
+ * @param ifaceName String name of the updated interface, or null to represent all interfaces
+ * @param mode int representing the new mode, one of:
+ * {@link #IFACE_IP_MODE_TETHERED},
+ * {@link #IFACE_IP_MODE_LOCAL_ONLY},
+ * {@link #IFACE_IP_MODE_CONFIGURATION_ERROR},
+ * {@link #IFACE_IP_MODE_UNSPECIFIED}
*
* @hide
*/
- public void updateInterfaceIpState(String ifaceName, int mode) {
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
try {
IWifiManager iWifiManager = getIWifiManager();
if (iWifiManager == null) {
@@ -2693,6 +2706,11 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
IWifiManager iWifiManager = getIWifiManager();
@@ -2710,6 +2728,11 @@ public class WifiManager {
*
* @hide
*/
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
public boolean stopSoftAp() {
try {
IWifiManager iWifiManager = getIWifiManager();
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 6c2d7ff882d3..ba9dd37398a1 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -157,7 +157,8 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
*/
public @NonNull Builder setBssidPattern(
@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
- checkNotNull(baseAddress, mask);
+ checkNotNull(baseAddress);
+ checkNotNull(mask);
mBssidPatternMatcher = Pair.create(baseAddress, mask);
return this;
}