Merge "AudioSystem: disable verbose volume logging"
diff --git a/api/current.txt b/api/current.txt
index 8ec2f5a..32747e7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26035,6 +26035,7 @@
public static final class MediaSession2.Builder {
ctor public MediaSession2.Builder(@NonNull android.content.Context);
method @NonNull public android.media.MediaSession2 build();
+ method @NonNull public android.media.MediaSession2.Builder setExtras(@Nullable android.os.Bundle);
method @NonNull public android.media.MediaSession2.Builder setId(@NonNull String);
method @NonNull public android.media.MediaSession2.Builder setSessionActivity(@Nullable android.app.PendingIntent);
method @NonNull public android.media.MediaSession2.Builder setSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaSession2.SessionCallback);
@@ -26397,6 +26398,7 @@
public final class Session2Token implements android.os.Parcelable {
ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
method public int describeContents();
+ method @Nullable public android.os.Bundle getExtras();
method @NonNull public String getPackageName();
method @Nullable public String getServiceName();
method public int getType();
@@ -29356,7 +29358,7 @@
method public android.os.ParcelFileDescriptor establish();
method public android.net.VpnService.Builder setBlocking(boolean);
method public android.net.VpnService.Builder setConfigureIntent(android.app.PendingIntent);
- method public android.net.VpnService.Builder setHttpProxy(android.net.ProxyInfo);
+ method public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);
method public android.net.VpnService.Builder setMetered(boolean);
method public android.net.VpnService.Builder setMtu(int);
method public android.net.VpnService.Builder setSession(String);
@@ -51205,8 +51207,8 @@
method public int getScaledHoverSlop();
method public int getScaledMaximumDrawingCacheSize();
method public int getScaledMaximumFlingVelocity();
- method public int getScaledMinScalingSpan();
method public int getScaledMinimumFlingVelocity();
+ method public int getScaledMinimumScalingSpan();
method public int getScaledOverflingDistance();
method public int getScaledOverscrollDistance();
method public int getScaledPagingTouchSlop();
@@ -51980,16 +51982,16 @@
method public boolean hasInsets();
method public boolean hasStableInsets();
method public boolean hasSystemWindowInsets();
- method @NonNull public android.view.WindowInsets inset(int, int, int, int);
+ method @NonNull public android.view.WindowInsets inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
method public boolean isConsumed();
method public boolean isRound();
method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(int, int, int, int);
method @Deprecated @NonNull public android.view.WindowInsets replaceSystemWindowInsets(android.graphics.Rect);
}
- public static class WindowInsets.Builder {
+ public static final class WindowInsets.Builder {
ctor public WindowInsets.Builder();
- ctor public WindowInsets.Builder(android.view.WindowInsets);
+ ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
method @NonNull public android.view.WindowInsets build();
method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
diff --git a/api/system-current.txt b/api/system-current.txt
index 17ea2e1..b5d9f3c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3455,6 +3455,7 @@
method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes);
method public void clearAudioServerStateCallback();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies();
method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
@@ -3647,6 +3648,7 @@
method @NonNull public android.media.AudioAttributes getAudioAttributesForProductStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy);
method @Nullable public android.media.audiopolicy.AudioProductStrategy getById(int);
method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes);
+ method @Nullable public android.media.audiopolicy.AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull android.media.AudioAttributes);
method public java.util.Iterator<android.media.audiopolicy.AudioProductStrategy> iterator();
method public int size();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -4849,7 +4851,8 @@
ctor public WifiScanner.ScanSettings();
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
- field @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean ignoreLocationSettings;
+ field public boolean hideFromAppOps;
+ field public boolean ignoreLocationSettings;
field public int maxPeriodInMs;
field public int maxScansToCache;
field public int numBssidsPerScan;
@@ -9239,7 +9242,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -9272,7 +9275,7 @@
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index f76cc71..1089761 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -684,7 +684,6 @@
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static String getWALSyncMode();
- method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}
@@ -741,6 +740,13 @@
field public static final android.os.Parcelable.Creator<android.hardware.display.AmbientBrightnessDayStats> CREATOR;
}
+ public class AmbientDisplayConfiguration {
+ ctor public AmbientDisplayConfiguration(android.content.Context);
+ method public boolean alwaysOnAvailable();
+ method public boolean alwaysOnAvailableForUser(int);
+ method public boolean alwaysOnEnabled(int);
+ }
+
public final class BrightnessChangeEvent implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -1991,6 +1997,7 @@
field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
+ field public static final String DOZE_ALWAYS_ON = "doze_always_on";
field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
field public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
@@ -2381,7 +2388,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsDownloadServiceBase extends android.os.Binder {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -2414,7 +2421,7 @@
method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
+ public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index de42398..1dd68df 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -285,7 +285,7 @@
CategorySize category_size = 10028;
ProcStats proc_stats = 10029;
BatteryVoltage battery_voltage = 10030;
- NumBiometricsEnrolled num_fingerprints_enrolled = 10031;
+ NumFingerprintsEnrolled num_fingerprints_enrolled = 10031;
DiskIo disk_io = 10032;
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
@@ -302,7 +302,7 @@
BatteryCycleCount battery_cycle_count = 10045;
DebugElapsedClock debug_elapsed_clock = 10046;
DebugFailingElapsedClock debug_failing_elapsed_clock = 10047;
- NumBiometricsEnrolled num_faces_enrolled = 10048;
+ NumFacesEnrolled num_faces_enrolled = 10048;
RoleHolder role_holder = 10049;
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
@@ -4127,15 +4127,27 @@
*
* Pulled from StatsCompanionService, which queries <Biometric>Manager.
*/
-message NumBiometricsEnrolled {
+message NumFingerprintsEnrolled {
// The associated user. Eg: 0 for owners, 10+ for others.
// Defined in android/os/UserHandle.java
optional int32 user = 1;
// Number of fingerprints registered to that user.
- optional int32 num_enrolled = 2;
+ optional int32 num_fingerprints_enrolled = 2;
}
/**
+ * Pulls the number of faces for each user.
+ *
+ * Pulled from StatsCompanionService, which queries <Biometric>Manager.
+ */
+message NumFacesEnrolled {
+ // The associated user. Eg: 0 for owners, 10+ for others.
+ // Defined in android/os/UserHandle.java
+ optional int32 user = 1;
+ // Number of faces registered to that user.
+ optional int32 num_faces_enrolled = 2;
+}
+/**
* A mapping of role holder -> role
*/
message RoleHolder {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index dc8863a..de0f2bc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2391,7 +2391,6 @@
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
}
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
mEnterAnimationComplete = false;
}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index e5df2c7..a6bf501 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -221,7 +221,10 @@
}
};
- public static PasswordMetrics computeForPassword(@NonNull String password) {
+ /**
+ * Returns the {@code PasswordMetrics} for a given password
+ */
+ public static PasswordMetrics computeForPassword(@NonNull byte[] password) {
// Analyse the characters used
int letters = 0;
int upperCase = 0;
@@ -229,9 +232,9 @@
int numeric = 0;
int symbols = 0;
int nonLetter = 0;
- final int length = password.length();
+ final int length = password.length;
for (int i = 0; i < length; i++) {
- switch (categoryChar(password.charAt(i))) {
+ switch (categoryChar((char) password[i])) {
case CHAR_LOWER_CASE:
letters++;
lowerCase++;
@@ -296,7 +299,7 @@
return false;
}
- /*
+ /**
* Returns the maximum length of a sequential characters. A sequence is defined as
* monotonically increasing characters with a constant interval or the same character repeated.
*
@@ -310,19 +313,19 @@
* maxLengthSequence(";;;;") == 4 (anything that repeats)
* maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits)
*
- * @param string the pass
+ * @param bytes the pass
* @return the number of sequential letters or digits
*/
- public static int maxLengthSequence(@NonNull String string) {
- if (string.length() == 0) return 0;
- char previousChar = string.charAt(0);
+ public static int maxLengthSequence(@NonNull byte[] bytes) {
+ if (bytes.length == 0) return 0;
+ char previousChar = (char) bytes[0];
@CharacterCatagory int category = categoryChar(previousChar); //current sequence category
int diff = 0; //difference between two consecutive characters
boolean hasDiff = false; //if we are currently targeting a sequence
int maxLength = 0; //maximum length of a sequence already found
int startSequence = 0; //where the current sequence started
- for (int current = 1; current < string.length(); current++) {
- char currentChar = string.charAt(current);
+ for (int current = 1; current < bytes.length; current++) {
+ char currentChar = (char) bytes[current];
@CharacterCatagory int categoryCurrent = categoryChar(currentChar);
int currentDiff = (int) currentChar - (int) previousChar;
if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) {
@@ -341,7 +344,7 @@
}
previousChar = currentChar;
}
- maxLength = Math.max(maxLength, string.length() - startSequence);
+ maxLength = Math.max(maxLength, bytes.length - startSequence);
return maxLength;
}
diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
index 8ea1db2..a269072 100644
--- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
+++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java
@@ -40,8 +40,7 @@
private static final String TAG = "SQLiteCompatibilityWalFlags";
private static volatile boolean sInitialized;
- private static volatile boolean sFlagsSet;
- private static volatile boolean sCompatibilityWalSupported;
+ private static volatile boolean sLegacyCompatibilityWalEnabled;
private static volatile String sWALSyncMode;
private static volatile long sTruncateSize = -1;
// This flag is used to avoid recursive initialization due to circular dependency on Settings
@@ -54,18 +53,9 @@
* @hide
*/
@VisibleForTesting
- public static boolean areFlagsSet() {
+ public static boolean isLegacyCompatibilityWalEnabled() {
initIfNeeded();
- return sFlagsSet;
- }
-
- /**
- * @hide
- */
- @VisibleForTesting
- public static boolean isCompatibilityWalSupported() {
- initIfNeeded();
- return sCompatibilityWalSupported;
+ return sLegacyCompatibilityWalEnabled;
}
/**
@@ -74,6 +64,14 @@
@VisibleForTesting
public static String getWALSyncMode() {
initIfNeeded();
+ // The configurable WAL sync mode should only ever be used if the legacy compatibility
+ // WAL is enabled. It should *not* have any effect if app developers explicitly turn on
+ // WAL for their database using setWriteAheadLoggingEnabled. Throwing an exception here
+ // adds an extra layer of checking that we never use it in the wrong place.
+ if (!sLegacyCompatibilityWalEnabled) {
+ throw new IllegalStateException("isLegacyCompatibilityWalEnabled() == false");
+ }
+
return sWALSyncMode;
}
@@ -131,13 +129,12 @@
sInitialized = true;
return;
}
- sCompatibilityWalSupported = parser.getBoolean("compatibility_wal_supported",
- SQLiteGlobal.isCompatibilityWalSupported());
+ sLegacyCompatibilityWalEnabled = parser.getBoolean(
+ "legacy_compatibility_wal_enabled", false);
sWALSyncMode = parser.getString("wal_syncmode", SQLiteGlobal.getWALSyncMode());
sTruncateSize = parser.getInt("truncate_size", -1);
- Log.i(TAG, "Read compatibility WAL flags: compatibility_wal_supported="
- + sCompatibilityWalSupported + ", wal_syncmode=" + sWALSyncMode);
- sFlagsSet = true;
+ Log.i(TAG, "Read compatibility WAL flags: legacy_compatibility_wal_enabled="
+ + sLegacyCompatibilityWalEnabled + ", wal_syncmode=" + sWALSyncMode);
sInitialized = true;
}
@@ -148,8 +145,7 @@
@TestApi
public static void reset() {
sInitialized = false;
- sFlagsSet = false;
- sCompatibilityWalSupported = false;
+ sLegacyCompatibilityWalEnabled = false;
sWALSyncMode = null;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 3c8e236..3844794 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -300,12 +300,13 @@
(mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
// Use compatibility WAL unless an app explicitly set journal/synchronous mode
// or DISABLE_COMPATIBILITY_WAL flag is set
- final boolean useCompatibilityWal = mConfiguration.useCompatibilityWal();
- if (walEnabled || useCompatibilityWal) {
+ final boolean isCompatibilityWalEnabled =
+ mConfiguration.isLegacyCompatibilityWalEnabled();
+ if (walEnabled || isCompatibilityWalEnabled) {
setJournalMode("WAL");
if (mConfiguration.syncMode != null) {
setSyncMode(mConfiguration.syncMode);
- } else if (useCompatibilityWal && SQLiteCompatibilityWalFlags.areFlagsSet()) {
+ } else if (isCompatibilityWalEnabled) {
setSyncMode(SQLiteCompatibilityWalFlags.getWALSyncMode());
} else {
setSyncMode(SQLiteGlobal.getWALSyncMode());
@@ -504,7 +505,7 @@
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
& (SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING
- | SQLiteDatabase.DISABLE_COMPATIBILITY_WAL)) != 0;
+ | SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL)) != 0;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index dbc1766..852f8f2 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -321,7 +321,7 @@
// We should do in-place switching when transitioning from compatibility WAL
// to rollback journal. Otherwise transient connection state will be lost
boolean onlyCompatWalChanged = (mConfiguration.openFlags ^ configuration.openFlags)
- == SQLiteDatabase.DISABLE_COMPATIBILITY_WAL;
+ == SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL;
if (!onlyCompatWalChanged && mConfiguration.openFlags != configuration.openFlags) {
// If we are changing open flags and WAL mode at the same time, then
@@ -1113,19 +1113,18 @@
if (directories != null) {
directories.add(new File(mConfiguration.path).getParent());
}
+ boolean isCompatibilityWalEnabled = mConfiguration.isLegacyCompatibilityWalEnabled();
printer.println("Connection pool for " + mConfiguration.path + ":");
printer.println(" Open: " + mIsOpen);
printer.println(" Max connections: " + mMaxConnectionPoolSize);
printer.println(" Total execution time: " + mTotalExecutionTimeCounter);
printer.println(" Configuration: openFlags=" + mConfiguration.openFlags
- + ", useCompatibilityWal=" + mConfiguration.useCompatibilityWal()
+ + ", isLegacyCompatibilityWalEnabled=" + isCompatibilityWalEnabled
+ ", journalMode=" + TextUtils.emptyIfNull(mConfiguration.journalMode)
+ ", syncMode=" + TextUtils.emptyIfNull(mConfiguration.syncMode));
- if (SQLiteCompatibilityWalFlags.areFlagsSet()) {
- printer.println(" Compatibility WAL settings: compatibility_wal_supported="
- + SQLiteCompatibilityWalFlags
- .isCompatibilityWalSupported() + ", wal_syncmode="
+ if (isCompatibilityWalEnabled) {
+ printer.println(" Compatibility WAL enabled: wal_syncmode="
+ SQLiteCompatibilityWalFlags.getWALSyncMode());
}
if (mConfiguration.isLookasideConfigSet()) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index ae456af..dffbd89 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -266,12 +266,17 @@
*/
public static final int ENABLE_WRITE_AHEAD_LOGGING = 0x20000000;
+
+ // Note: The below value was only used on Android Pie.
+ // public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
+
/**
- * Open flag: Flag for {@link #openDatabase} to disable Compatibility WAL when opening database.
+ * Open flag: Flag for {@link #openDatabase} to enable the legacy Compatibility WAL when opening
+ * database.
*
* @hide
*/
- public static final int DISABLE_COMPATIBILITY_WAL = 0x40000000;
+ public static final int ENABLE_LEGACY_COMPATIBILITY_WAL = 0x80000000;
/**
* Absolute max value that can be set by {@link #setMaxSqlCacheSize(int)}.
@@ -309,10 +314,8 @@
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
mConfigurationLocked.journalMode = journalMode;
mConfigurationLocked.syncMode = syncMode;
- if (!SQLiteGlobal.isCompatibilityWalSupported() || (
- SQLiteCompatibilityWalFlags.areFlagsSet() && !SQLiteCompatibilityWalFlags
- .isCompatibilityWalSupported())) {
- mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
+ if (SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled()) {
+ mConfigurationLocked.openFlags |= ENABLE_LEGACY_COMPATIBILITY_WAL;
}
}
@@ -2123,15 +2126,18 @@
throwIfNotOpenLocked();
final int oldFlags = mConfigurationLocked.openFlags;
- final boolean walDisabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0;
- final boolean compatibilityWalDisabled = (oldFlags & DISABLE_COMPATIBILITY_WAL) != 0;
- if (walDisabled && compatibilityWalDisabled) {
+ final boolean walEnabled = (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ final boolean compatibilityWalEnabled =
+ (oldFlags & ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
+ // WAL was never enabled for this database, so there's nothing left to do.
+ if (!walEnabled && !compatibilityWalEnabled) {
return;
}
+ // If an app explicitly disables WAL, it takes priority over any directive
+ // to use the legacy "compatibility WAL" mode.
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
- // If an app explicitly disables WAL, compatibility mode should be disabled too
- mConfigurationLocked.openFlags |= DISABLE_COMPATIBILITY_WAL;
+ mConfigurationLocked.openFlags &= ~ENABLE_LEGACY_COMPATIBILITY_WAL;
try {
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 48f1021..fcdaf0a 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -17,6 +17,7 @@
package android.database.sqlite;
import android.annotation.UnsupportedAppUsage;
+
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -197,9 +198,9 @@
return path.equalsIgnoreCase(MEMORY_DB_PATH);
}
- boolean useCompatibilityWal() {
+ boolean isLegacyCompatibilityWalEnabled() {
return journalMode == null && syncMode == null
- && (openFlags & SQLiteDatabase.DISABLE_COMPATIBILITY_WAL) == 0;
+ && (openFlags & SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL) != 0;
}
private static String stripPathForLogs(String path) {
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index ff286fd..d796003 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -91,16 +91,6 @@
}
/**
- * Returns true if compatibility WAL mode is supported. In this mode, only
- * database journal mode is changed. Connection pool will use at most one connection.
- */
- public static boolean isCompatibilityWalSupported() {
- return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
- Resources.getSystem().getBoolean(
- com.android.internal.R.bool.db_compatibility_wal_supported));
- }
-
- /**
* Gets the journal size limit in bytes.
*/
public static int getJournalSizeLimit() {
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 0e869c8..8163c4d 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -202,8 +202,9 @@
}
mOpenParamsBuilder.setWriteAheadLoggingEnabled(enabled);
}
+
// Compatibility WAL is disabled if an app disables or enables WAL
- mOpenParamsBuilder.addOpenFlags(SQLiteDatabase.DISABLE_COMPATIBILITY_WAL);
+ mOpenParamsBuilder.removeOpenFlags(SQLiteDatabase.ENABLE_LEGACY_COMPATIBILITY_WAL);
}
}
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
similarity index 82%
rename from core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
rename to core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 87e048c..b122f19 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -11,11 +11,12 @@
* 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
+ * limitations under the License.
*/
-package com.android.internal.hardware;
+package android.hardware.display;
+import android.annotation.TestApi;
import android.content.Context;
import android.os.Build;
import android.os.SystemProperties;
@@ -24,16 +25,25 @@
import com.android.internal.R;
+/**
+ * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display.
+ *
+ * {@hide}
+ */
+@TestApi
public class AmbientDisplayConfiguration {
private final Context mContext;
private final boolean mAlwaysOnByDefault;
+ /** {@hide} */
+ @TestApi
public AmbientDisplayConfiguration(Context context) {
mContext = context;
mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled);
}
+ /** {@hide} */
public boolean enabled(int user) {
return pulseOnNotificationEnabled(user)
|| pulseOnLongPressEnabled(user)
@@ -41,67 +51,83 @@
|| wakeScreenGestureEnabled(user);
}
+ /** {@hide} */
public boolean pulseOnNotificationEnabled(int user) {
- return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user) && pulseOnNotificationAvailable();
+ return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user)
+ && pulseOnNotificationAvailable();
}
+ /** {@hide} */
public boolean pulseOnNotificationAvailable() {
return ambientDisplayAvailable();
}
+ /** {@hide} */
public boolean pickupGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_PICK_UP_GESTURE, user)
&& dozePickupSensorAvailable();
}
+ /** {@hide} */
public boolean dozePickupSensorAvailable() {
return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup);
}
+ /** {@hide} */
public boolean tapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user)
&& tapSensorAvailable();
}
+ /** {@hide} */
public boolean tapSensorAvailable() {
return !TextUtils.isEmpty(tapSensorType());
}
+ /** {@hide} */
public boolean doubleTapGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user)
&& doubleTapSensorAvailable();
}
+ /** {@hide} */
public boolean doubleTapSensorAvailable() {
return !TextUtils.isEmpty(doubleTapSensorType());
}
+ /** {@hide} */
public boolean wakeScreenGestureAvailable() {
return mContext.getResources()
.getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
}
+ /** {@hide} */
public boolean wakeScreenGestureEnabled(int user) {
return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_SCREEN_GESTURE, user)
&& wakeScreenGestureAvailable();
}
+ /** {@hide} */
public long getWakeLockScreenDebounce() {
return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce);
}
+ /** {@hide} */
public String doubleTapSensorType() {
return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType);
}
+ /** {@hide} */
public String tapSensorType() {
return mContext.getResources().getString(R.string.config_dozeTapSensorType);
}
+ /** {@hide} */
public String longPressSensorType() {
return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
}
+ /** {@hide} */
public boolean pulseOnLongPressEnabled(int user) {
return pulseOnLongPressAvailable() && boolSettingDefaultOff(
Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user);
@@ -111,28 +137,49 @@
return !TextUtils.isEmpty(longPressSensorType());
}
+ /**
+ * Returns if Always-on-Display functionality is enabled on the display for a specified user.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnEnabled(int user) {
return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0)
&& alwaysOnAvailable() && !accessibilityInversionEnabled(user);
}
+ /**
+ * Returns if Always-on-Display functionality is available on the display.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnAvailable() {
return (alwaysOnDisplayDebuggingEnabled() || alwaysOnDisplayAvailable())
&& ambientDisplayAvailable();
}
+ /**
+ * Returns if Always-on-Display functionality is available on the display for a specified user.
+ *
+ * {@hide}
+ */
+ @TestApi
public boolean alwaysOnAvailableForUser(int user) {
return alwaysOnAvailable() && !accessibilityInversionEnabled(user);
}
+ /** {@hide} */
public String ambientDisplayComponent() {
return mContext.getResources().getString(R.string.config_dozeComponent);
}
+ /** {@hide} */
public boolean accessibilityInversionEnabled(int user) {
return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user);
}
+ /** {@hide} */
public boolean ambientDisplayAvailable() {
return !TextUtils.isEmpty(ambientDisplayComponent());
}
@@ -145,7 +192,6 @@
return SystemProperties.getBoolean("debug.doze.aod", false) && Build.IS_DEBUGGABLE;
}
-
private boolean boolSettingDefaultOn(String name, int user) {
return boolSetting(name, user, 1);
}
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 90dccb5..45860b3 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -23,8 +23,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.RoSystemProperties;
-import com.android.org.conscrypt.Conscrypt;
-import com.android.org.conscrypt.OpenSSLContextImpl;
+import com.android.org.conscrypt.ClientSessionContext;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.SSLClientSessionCache;
@@ -33,6 +32,8 @@
import java.net.Socket;
import java.net.SocketException;
import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@@ -40,6 +41,7 @@
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
@@ -251,11 +253,12 @@
private SSLSocketFactory makeSocketFactory(
KeyManager[] keyManagers, TrustManager[] trustManagers) {
try {
- OpenSSLContextImpl sslContext = (OpenSSLContextImpl) Conscrypt.newPreferredSSLContextSpi();
- sslContext.engineInit(keyManagers, trustManagers, null);
- sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
- return sslContext.engineGetSocketFactory();
- } catch (KeyManagementException e) {
+ SSLContext sslContext = SSLContext.getInstance("TLS", "AndroidOpenSSL");
+ sslContext.init(keyManagers, trustManagers, null);
+ ((ClientSessionContext) sslContext.getClientSessionContext())
+ .setPersistentCache(mSessionCache);
+ return sslContext.getSocketFactory();
+ } catch (KeyManagementException | NoSuchAlgorithmException | NoSuchProviderException e) {
Log.wtf(TAG, e);
return (SSLSocketFactory) SSLSocketFactory.getDefault(); // Fallback
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 784f233..ebb1ae4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -19,6 +19,7 @@
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -512,7 +513,7 @@
* Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
* and it is possible that some apps will ignore it.
*/
- public Builder setHttpProxy(ProxyInfo proxyInfo) {
+ public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) {
mConfig.proxyInfo = proxyInfo;
return this;
}
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index da03895..330bde5 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -16,11 +16,14 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
@@ -45,6 +48,24 @@
* keep a reference to the FileObserver instance from some other live object.</p>
*/
public abstract class FileObserver {
+ /** @hide */
+ @IntDef(flag = true, value = {
+ ACCESS,
+ MODIFY,
+ ATTRIB,
+ CLOSE_WRITE,
+ CLOSE_NOWRITE,
+ OPEN,
+ MOVED_FROM,
+ MOVED_TO,
+ CREATE,
+ DELETE,
+ DELETE_SELF,
+ MOVE_SELF
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NotifyEventType {}
+
/** Event type: Data was read from a file */
public static final int ACCESS = 0x00000001;
/** Event type: Data was written to a file */
@@ -71,6 +92,7 @@
public static final int MOVE_SELF = 0x00000800;
/** Event mask: All valid event types, combined */
+ @NotifyEventType
public static final int ALL_EVENTS = ACCESS | MODIFY | ATTRIB | CLOSE_WRITE
| CLOSE_NOWRITE | OPEN | MOVED_FROM | MOVED_TO | DELETE | CREATE
| DELETE_SELF | MOVE_SELF;
@@ -90,7 +112,8 @@
observe(m_fd);
}
- public int[] startWatching(List<File> files, int mask, FileObserver observer) {
+ public int[] startWatching(List<File> files,
+ @NotifyEventType int mask, FileObserver observer) {
final int count = files.size();
final String[] paths = new String[count];
for (int i = 0; i < count; ++i) {
@@ -118,7 +141,7 @@
stopWatching(m_fd, descriptors);
}
- public void onEvent(int wfd, int mask, String path) {
+ public void onEvent(int wfd, @NotifyEventType int mask, String path) {
// look up our observer, fixing up the map if necessary...
FileObserver observer = null;
@@ -144,7 +167,8 @@
private native int init();
private native void observe(int fd);
- private native void startWatching(int fd, String[] paths, int mask, int[] wfds);
+ private native void startWatching(int fd, String[] paths,
+ @NotifyEventType int mask, int[] wfds);
private native void stopWatching(int fd, int[] wfds);
}
@@ -197,7 +221,7 @@
* @deprecated use {@link #FileObserver(File, int)} instead.
*/
@Deprecated
- public FileObserver(String path, int mask) {
+ public FileObserver(String path, @NotifyEventType int mask) {
this(new File(path), mask);
}
@@ -209,7 +233,7 @@
* @param file The file or directory to monitor
* @param mask The event or events (added together) to watch for
*/
- public FileObserver(@NonNull File file, int mask) {
+ public FileObserver(@NonNull File file, @NotifyEventType int mask) {
this(Arrays.asList(file), mask);
}
@@ -220,7 +244,7 @@
* @param files The files or directories to monitor
* @param mask The event or events (added together) to watch for
*/
- public FileObserver(@NonNull List<File> files, int mask) {
+ public FileObserver(@NonNull List<File> files, @NotifyEventType int mask) {
mFiles = files;
mMask = mask;
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 868a36b..ce28c30 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -197,6 +197,7 @@
*/
@SystemApi
public interface MediaNative {
+ /** The flag namespace for media native features. */
String NAMESPACE = "media_native";
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8acdc8c..0d7e00f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7483,6 +7483,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final String DOZE_ALWAYS_ON = "doze_always_on";
private static final Validator DOZE_ALWAYS_ON_VALIDATOR = BOOLEAN_VALIDATOR;
@@ -11416,7 +11417,7 @@
/**
* Feature flag to enable or disable the activity starts logging feature.
* Type: int (0 for false, 1 for true)
- * Default: 0
+ * Default: 1
* @hide
*/
public static final String ACTIVITY_STARTS_LOGGING_ENABLED
@@ -14200,10 +14201,24 @@
* Configuration flags for SQLite Compatibility WAL. Encoded as a key-value list, separated
* by commas. E.g.: compatibility_wal_supported=true, wal_syncmode=OFF
*
- * Supported keys:
- * compatibility_wal_supported (boolean)
- * wal_syncmode (String)
- * truncate_size (int)
+ * Supported keys:<br/>
+ * <li>
+ * <ul> {@code legacy_compatibility_wal_enabled} : A {code boolean} flag that determines
+ * whether or not "compatibility WAL" mode is enabled by default. This is a legacy flag
+ * and is honoured on Android Q and higher. This flag will be removed in a future release.
+ * </ul>
+ * <ul> {@code wal_syncmode} : A {@code String} representing the synchronization mode to use
+ * when WAL is enabled, either via {@code legacy_compatibility_wal_enabled} or using the
+ * obsolete {@code compatibility_wal_supported} flag.
+ * </ul>
+ * <ul> {@code truncate_size} : A {@code int} flag that specifies the truncate size of the
+ * WAL journal.
+ * </ul>
+ * <ul> {@code compatibility_wal_supported} : A {code boolean} flag that specifies whether
+ * the legacy "compatibility WAL" mode is enabled by default. This flag is obsolete and is
+ * only supported on Android Pie.
+ * </ul>
+ * </li>
*
* @hide
*/
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 3e8002f..60daddd 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -156,6 +156,17 @@
}
/**
+ * Called when a display config changed event is received.
+ *
+ * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
+ * timebase.
+ * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
+ * @param configId The new config Id
+ */
+ public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ }
+
+ /**
* Schedules a single vertical sync pulse to be delivered when the next
* display frame begins.
*/
@@ -182,4 +193,11 @@
private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
onHotplug(timestampNanos, physicalDisplayId, connected);
}
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ onConfigChanged(timestampNanos, physicalDisplayId, configId);
+ }
+
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index dd88e3c..50ef91f 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -20,6 +20,7 @@
import static android.view.InsetsState.INSET_SIDE_LEFT;
import static android.view.InsetsState.INSET_SIDE_RIGHT;
import static android.view.InsetsState.INSET_SIDE_TOP;
+import static android.view.InsetsState.toPublicType;
import android.annotation.Nullable;
import android.graphics.Insets;
@@ -33,6 +34,7 @@
import android.view.InsetsState.InsetSide;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetType;
+import android.view.WindowInsetsAnimationListener.InsetsAnimation;
import android.view.WindowManager.LayoutParams;
import com.android.internal.annotations.VisibleForTesting;
@@ -66,8 +68,12 @@
private final Supplier<SyncRtSurfaceTransactionApplier> mTransactionApplierSupplier;
private final InsetsController mController;
private final WindowInsetsAnimationListener.InsetsAnimation mAnimation;
+ private final Rect mFrame;
private Insets mCurrentInsets;
private Insets mPendingInsets;
+ private boolean mFinished;
+ private boolean mCancelled;
+ private int mFinishedShownTypes;
@VisibleForTesting
public InsetsAnimationControlImpl(SparseArray<InsetsSourceConsumer> consumers, Rect frame,
@@ -86,6 +92,7 @@
null /* typeSideMap */);
mShownInsets = calculateInsets(mInitialInsetsState, frame, consumers, true /* shown */,
mTypeSideMap);
+ mFrame = new Rect(frame);
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mConsumers);
// TODO: Check for controllability first and wait for IME if needed.
@@ -119,12 +126,26 @@
@Override
public void changeInsets(Insets insets) {
+ if (mFinished) {
+ throw new IllegalStateException(
+ "Can't change insets on an animation that is finished.");
+ }
+ if (mCancelled) {
+ throw new IllegalStateException(
+ "Can't change insets on an animation that is cancelled.");
+ }
mPendingInsets = sanitize(insets);
mController.scheduleApplyChangeInsets();
}
@VisibleForTesting
- public void applyChangeInsets(InsetsState state) {
+ /**
+ * @return Whether the finish callback of this animation should be invoked.
+ */
+ public boolean applyChangeInsets(InsetsState state) {
+ if (mCancelled) {
+ return false;
+ }
final Insets offset = Insets.subtract(mShownInsets, mPendingInsets);
ArrayList<SurfaceParams> params = new ArrayList<>();
if (offset.left != 0) {
@@ -144,13 +165,40 @@
SyncRtSurfaceTransactionApplier applier = mTransactionApplierSupplier.get();
applier.scheduleApply(params.toArray(new SurfaceParams[params.size()]));
mCurrentInsets = mPendingInsets;
+ if (mFinished) {
+ mController.notifyFinished(this, mFinishedShownTypes);
+ }
+ return mFinished;
}
@Override
public void finish(int shownTypes) {
- // TODO
+ if (mCancelled) {
+ return;
+ }
+ InsetsState state = new InsetsState(mController.getState());
+ for (int i = mConsumers.size() - 1; i >= 0; i--) {
+ InsetsSourceConsumer consumer = mConsumers.valueAt(i);
+ boolean visible = (shownTypes & toPublicType(consumer.getType())) != 0;
+ state.getSource(consumer.getType()).setVisible(visible);
+ }
+ Insets insets = getInsetsFromState(state, mFrame, null /* typeSideMap */);
+ changeInsets(insets);
+ mFinished = true;
+ mFinishedShownTypes = shownTypes;
+ }
- mController.dispatchAnimationFinished(mAnimation);
+ @VisibleForTesting
+ public void onCancelled() {
+ if (mFinished) {
+ return;
+ }
+ mCancelled = true;
+ mListener.onCancelled();
+ }
+
+ InsetsAnimation getAnimation() {
+ return mAnimation;
}
private Insets calculateInsets(InsetsState state, Rect frame,
@@ -225,4 +273,3 @@
}
}
}
-
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 2586000..08f2e8d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -17,6 +17,8 @@
package android.view;
import static android.view.InsetsState.TYPE_IME;
+import static android.view.InsetsState.toPublicType;
+import static android.view.WindowInsets.Type.all;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -99,6 +101,7 @@
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
private final ArrayList<InsetsAnimationControlImpl> mAnimationControls = new ArrayList<>();
+ private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
private WindowInsets mLastInsets;
private boolean mAnimCallbackScheduled;
@@ -107,7 +110,6 @@
private final Rect mLastLegacyContentInsets = new Rect();
private final Rect mLastLegacyStableInsets = new Rect();
- private ObjectAnimator mAnimator;
private @AnimationDirection int mAnimationDirection;
private int mPendingTypesToShow;
@@ -122,19 +124,29 @@
return;
}
+ mTmpFinishedControls.clear();
InsetsState state = new InsetsState(mState, true /* copySources */);
for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
- mAnimationControls.get(i).applyChangeInsets(state);
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if (mAnimationControls.get(i).applyChangeInsets(state)) {
+ mTmpFinishedControls.add(control);
+ }
}
+
WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode,
null /* typeSideMap */);
mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
+
+ for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
+ dispatchAnimationFinished(mTmpFinishedControls.get(i).getAnimation());
+ }
};
}
- void onFrameChanged(Rect frame) {
+ @VisibleForTesting
+ public void onFrameChanged(Rect frame) {
if (mFrame.equals(frame)) {
return;
}
@@ -279,7 +291,8 @@
// nothing to animate.
return;
}
- // TODO: Check whether we already have a controller.
+ cancelExistingControllers(types);
+
final ArraySet<Integer> internalTypes = mState.toInternalType(types);
final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
@@ -321,7 +334,7 @@
// Show request
switch(consumer.requestShow(fromIme)) {
case ShowResult.SHOW_IMMEDIATELY:
- typesReady |= InsetsState.toPublicType(TYPE_IME);
+ typesReady |= InsetsState.toPublicType(consumer.getType());
break;
case ShowResult.SHOW_DELAYED:
isReady = false;
@@ -365,6 +378,36 @@
return typesReady;
}
+ private void cancelExistingControllers(@InsetType int types) {
+ for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if ((control.getTypes() & types) != 0) {
+ cancelAnimation(control);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public void notifyFinished(InsetsAnimationControlImpl controller, int shownTypes) {
+ mAnimationControls.remove(controller);
+ hideDirectly(controller.getTypes() & ~shownTypes);
+ showDirectly(controller.getTypes() & shownTypes);
+ }
+
+ void notifyControlRevoked(InsetsSourceConsumer consumer) {
+ for (int i = mAnimationControls.size() - 1; i >= 0; i--) {
+ InsetsAnimationControlImpl control = mAnimationControls.get(i);
+ if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
+ cancelAnimation(control);
+ }
+ }
+ }
+
+ private void cancelAnimation(InsetsAnimationControlImpl control) {
+ control.onCancelled();
+ mAnimationControls.remove(control);
+ }
+
private void applyLocalVisibilityOverride() {
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer controller = mSourceConsumers.valueAt(i);
@@ -455,8 +498,13 @@
}
WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
+
+ private WindowInsetsAnimationController mController;
+ private ObjectAnimator mAnimator;
+
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
+ mController = controller;
if (show) {
showDirectly(types);
} else {
@@ -474,10 +522,6 @@
: ANIMATION_DURATION_HIDE_MS);
mAnimator.setInterpolator(INTERPOLATOR);
mAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- onAnimationFinish();
- }
@Override
public void onAnimationEnd(Animator animation) {
@@ -488,15 +532,15 @@
}
@Override
- public void onCancelled() {}
+ public void onCancelled() {
+ mAnimator.cancel();
+ }
private void onAnimationFinish() {
mAnimationDirection = DIRECTION_NONE;
+ mController.finish(show ? types : 0);
}
};
- // TODO: Instead of clearing this here, properly wire up
- // InsetsAnimationControlImpl.finish() to remove this from mAnimationControls.
- mAnimationControls.clear();
// Show/hide animations always need to be relative to the display frame, in order that shown
// and hidden state insets are correct.
@@ -522,10 +566,7 @@
*/
@VisibleForTesting
public void cancelExistingAnimation() {
- mAnimationDirection = DIRECTION_NONE;
- if (mAnimator != null) {
- mAnimator.cancel();
- }
+ cancelExistingControllers(all());
}
void dump(String prefix, PrintWriter pw) {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index eab83ce..1383463 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -77,6 +77,9 @@
if (applyLocalVisibilityOverride()) {
mController.notifyVisibilityChanged();
}
+ if (mSourceControl == null) {
+ mController.notifyControlRevoked(this);
+ }
}
@VisibleForTesting
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index c24b8b2..7c69cfd 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -201,7 +201,7 @@
mListener = listener;
final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2;
- mMinSpan = viewConfiguration.getScaledMinScalingSpan();
+ mMinSpan = viewConfiguration.getScaledMinimumScalingSpan();
mHandler = handler;
// Quick scale is enabled by default after JB_MR2
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ee91c85..ea7f31d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -158,6 +158,8 @@
IBinder displayToken, long numFrames, long timestamp);
private static native int nativeGetActiveConfig(IBinder displayToken);
private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
+ private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
+ int[] allowedConfigs);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
@@ -1522,6 +1524,20 @@
/**
* @hide
*/
+ public static boolean setAllowedDisplayConfigs(IBinder displayToken, int[] allowedConfigs) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+ if (allowedConfigs == null) {
+ throw new IllegalArgumentException("allowedConfigs must not be null");
+ }
+
+ return nativeSetAllowedDisplayConfigs(displayToken, allowedConfigs);
+ }
+
+ /**
+ * @hide
+ */
public static int[] getDisplayColorModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1a9d3a0..7afdc70 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10968,7 +10968,7 @@
}
void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
- if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) {
+ if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) {
mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation);
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index c030ac2..81e9c13 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -979,7 +979,7 @@
* @throws IllegalStateException if this method is called on a ViewConfiguration that was
* instantiated using a constructor with no Context parameter.
*/
- public int getScaledMinScalingSpan() {
+ public int getScaledMinimumScalingSpan() {
if (!mConstructedWithContext) {
throw new IllegalStateException("Min scaling span cannot be determined when this "
+ "method is called on a ViewConfiguration that was instantiated using a "
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index c1536ae..135a891 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -28,6 +28,7 @@
import static android.view.WindowInsets.Type.indexOf;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
@@ -700,7 +701,8 @@
* @return the inset insets
*/
@NonNull
- public WindowInsets inset(int left, int top, int right, int bottom) {
+ public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
+ @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
Preconditions.checkArgumentNonnegative(left);
Preconditions.checkArgumentNonnegative(top);
Preconditions.checkArgumentNonnegative(right);
@@ -794,7 +796,7 @@
/**
* Builder for WindowInsets.
*/
- public static class Builder {
+ public static final class Builder {
private final Insets[] mTypeInsetsMap;
private final Insets[] mTypeMaxInsetsMap;
@@ -821,7 +823,7 @@
*
* @param insets the instance to initialize from.
*/
- public Builder(WindowInsets insets) {
+ public Builder(@NonNull WindowInsets insets) {
mTypeInsetsMap = insets.mTypeInsetsMap.clone();
mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index a6129b0..f44c331 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -312,7 +312,7 @@
* @return The view that is currently selected, if it happens to be in the
* range that we draw.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillDown(int pos, int nextTop) {
View selectedView = null;
@@ -412,7 +412,7 @@
*
* @return The view that is currently selected
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillUp(int pos, int nextBottom) {
View selectedView = null;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2aa019b..2f44d6e 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -782,7 +782,7 @@
* @return The view that is currently selected, if it happens to be in the
* range that we draw.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillDown(int pos, int nextTop) {
View selectedView = null;
@@ -817,7 +817,7 @@
*
* @return The view that is currently selected
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillUp(int pos, int nextBottom) {
View selectedView = null;
@@ -1490,7 +1490,7 @@
* @return The selected view, or null if the selected view is outside the
* visible area.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private View fillSpecific(int position, int top) {
boolean tempIsSelected = position == mSelectedPosition;
View temp = makeAndAddView(position, top, true, mListPadding.left, tempIsSelected);
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 2c78be7..bab4787 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -568,7 +568,7 @@
}
/**
- * Aggregated data by uid/class/method to be sent through WestWorld.
+ * Aggregated data by uid/class/method to be sent through statsd.
*/
public static class ExportedCallStat {
public int callingUid;
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 9a77802..1c5816c 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -36,17 +36,17 @@
boolean getBoolean(in String key, in boolean defaultValue, in int userId);
long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
- void setLockCredential(in String credential, int type, in String savedCredential, int requestedQuality, int userId);
+ void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
void resetKeyStore(int userId);
- VerifyCredentialResponse checkCredential(in String credential, int type, int userId,
+ VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
in ICheckCredentialProgressCallback progressCallback);
- VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId);
- VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId);
+ VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId);
+ VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
- byte[] getHashFactor(String currentCredential, int userId);
- void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword);
+ byte[] getHashFactor(in byte[] currentCredential, int userId);
+ void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword);
boolean getSeparateProfileChallengeEnabled(int userId);
void registerStrongAuthTracker(in IStrongAuthTracker tracker);
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index 586ece0..bda3b57 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -150,12 +150,33 @@
* @param challenge The challenge to verify against the pattern.
* @param userId The user to check against the pattern.
* @param callback The callback to be invoked with the verification result.
+ *
+ * @deprecated Pass the password as a byte array.
*/
+ @Deprecated
public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
final String password,
final long challenge,
final int userId,
final OnVerifyCallback callback) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return verifyPassword(utils, passwordBytes, challenge, userId, callback);
+ }
+
+ /**
+ * Verify a password asynchronously.
+ *
+ * @param utils The LockPatternUtils instance to use.
+ * @param password The password to check.
+ * @param challenge The challenge to verify against the pattern.
+ * @param userId The user to check against the pattern.
+ * @param callback The callback to be invoked with the verification result.
+ */
+ public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
+ final byte[] password,
+ final long challenge,
+ final int userId,
+ final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
private int mThrottleTimeout;
@@ -188,7 +209,7 @@
* @param callback The callback to be invoked with the verification result.
*/
public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils,
- final String password,
+ final byte[] password,
final boolean isPattern,
final long challenge,
final int userId,
@@ -222,18 +243,36 @@
* @param password The password to check.
* @param userId The user to check against the pattern.
* @param callback The callback to be invoked with the check result.
+ * @deprecated Pass passwords as byte[]
*/
+ @Deprecated
public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
final String password,
final int userId,
final OnCheckCallback callback) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return checkPassword(utils, passwordBytes, userId, callback);
+ }
+
+ /**
+ * Checks a password asynchronously.
+ *
+ * @param utils The LockPatternUtils instance to use.
+ * @param passwordBytes The password to check.
+ * @param userId The user to check against the pattern.
+ * @param callback The callback to be invoked with the check result.
+ */
+ public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
+ final byte[] passwordBytes,
+ final int userId,
+ final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
private int mThrottleTimeout;
@Override
protected Boolean doInBackground(Void... args) {
try {
- return utils.checkPassword(password, userId, callback::onEarlyMatched);
+ return utils.checkPassword(passwordBytes, userId, callback::onEarlyMatched);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return false;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 8d3c482..17ed2a0 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -67,6 +67,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.StringJoiner;
@@ -356,7 +357,7 @@
null /* componentName */, userId);
}
- private byte[] verifyCredential(String credential, int type, long challenge, int userId)
+ private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId)
throws RequestThrottledException {
try {
VerifyCredentialResponse response = getLockSettings().verifyCredential(credential,
@@ -373,7 +374,7 @@
}
}
- private boolean checkCredential(String credential, int type, int userId,
+ private boolean checkCredential(byte[] credential, int type, int userId,
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
try {
@@ -404,7 +405,7 @@
public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
throws RequestThrottledException {
throwIfCalledOnMainThread();
- return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
+ return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge,
userId);
}
@@ -429,7 +430,7 @@
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
throwIfCalledOnMainThread();
- return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,
+ return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId,
progressCallback);
}
@@ -442,7 +443,7 @@
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPassword(String password, long challenge, int userId)
+ public byte[] verifyPassword(byte[] password, long challenge, int userId)
throws RequestThrottledException {
throwIfCalledOnMainThread();
return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId);
@@ -458,7 +459,7 @@
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge,
+ public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge,
int userId) throws RequestThrottledException {
throwIfCalledOnMainThread();
try {
@@ -480,22 +481,53 @@
}
/**
+ *
* Check to see if a password matches the saved password. If no password exists,
* always returns true.
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
public boolean checkPassword(String password, int userId) throws RequestThrottledException {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ return checkPassword(passwordBytes, userId, null /* progressCallback */);
+ }
+
+
+ /**
+ *
+ * Check to see if a password matches the saved password. If no password exists,
+ * always returns true.
+ * @param password The password to check.
+ * @return Whether the password matches the stored one.
+ */
+ public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException {
return checkPassword(password, userId, null /* progressCallback */);
}
+ // TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api
+ /* *
+ * Check to see if a password matches the saved password. If no password exists,
+ * always returns true.
+ * @param password The password to check.
+ * @return Whether the password matches the stored one.
+ */
+ public boolean checkPassword(String password, int userId,
+ @Nullable CheckCredentialProgressCallback progressCallback)
+ throws RequestThrottledException {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ throwIfCalledOnMainThread();
+ return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback);
+
+ }
+
/**
* Check to see if a password matches the saved password. If no password exists,
* always returns true.
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
- public boolean checkPassword(String password, int userId,
+
+ public boolean checkPassword(byte[] password, int userId,
@Nullable CheckCredentialProgressCallback progressCallback)
throws RequestThrottledException {
throwIfCalledOnMainThread();
@@ -519,7 +551,7 @@
* Returns the password history hash factor, needed to check new password against password
* history with {@link #checkPasswordHistory(String, byte[], int)}
*/
- public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) {
+ public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) {
try {
return getLockSettings().getHashFactor(currentPassword, userId);
} catch (RemoteException e) {
@@ -537,8 +569,8 @@
* {@link ILockSettings#getHashFactor}
* @return Whether the password matches any in the history.
*/
- public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) {
- if (TextUtils.isEmpty(passwordToCheck)) {
+ public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) {
+ if (passwordToCheck == null || passwordToCheck.length == 0) {
Log.e(TAG, "checkPasswordHistory: empty password");
return false;
}
@@ -639,13 +671,13 @@
/**
* Clear any lock pattern or password.
*/
- public void clearLock(String savedCredential, int userHandle) {
+ public void clearLock(byte[] savedCredential, int userHandle) {
final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
try{
- getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential,
- PASSWORD_QUALITY_UNSPECIFIED, userHandle);
+ getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
+ savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
} catch (Exception e) {
Log.e(TAG, "Failed to clear lock", e);
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
@@ -704,10 +736,11 @@
/**
* Save a lock pattern.
* @param pattern The new pattern to save.
- * @param savedPattern The previously saved pattern, converted to String format
+ * @param savedPattern The previously saved pattern, converted to byte[] format
* @param userId the user whose pattern is to be saved.
*/
- public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
+ public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
+ int userId) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
@@ -717,12 +750,12 @@
+ MIN_LOCK_PATTERN_SIZE + " dots long.");
}
- final String stringPattern = patternToString(pattern);
+ final byte[] bytePattern = patternToByteArray(pattern);
final int currentQuality = getKeyguardStoredPasswordQuality(userId);
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
try {
- getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN,
- savedPattern, PASSWORD_QUALITY_SOMETHING, userId);
+ getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
+ PASSWORD_QUALITY_SOMETHING, userId);
} catch (Exception e) {
Log.e(TAG, "Couldn't save lock pattern", e);
setKeyguardStoredPasswordQuality(currentQuality, userId);
@@ -734,7 +767,7 @@
if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
} else {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern);
}
}
@@ -806,7 +839,7 @@
}
/** Update the encryption password if it is enabled **/
- private void updateEncryptionPassword(final int type, final String password) {
+ private void updateEncryptionPassword(final int type, final byte[] password) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
@@ -825,7 +858,9 @@
protected Void doInBackground(Void... dummy) {
IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
try {
- storageManager.changeEncryptionPassword(type, password);
+ // TODO(b/120484642): This is a location where we still use a String for vold
+ String passwordString = password != null ? new String(password) : null;
+ storageManager.changeEncryptionPassword(type, passwordString);
} catch (RemoteException e) {
Log.e(TAG, "Error changing encryption password", e);
}
@@ -842,14 +877,34 @@
* @param savedPassword The previously saved lock password, or null if none
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
* @param userHandle The userId of the user to change the password for
+ *
+ * @deprecated Pass password as a byte array
*/
+ @Deprecated
public void saveLockPassword(String password, String savedPassword, int requestedQuality,
int userHandle) {
+ byte[] passwordBytes = password != null ? password.getBytes() : null;
+ byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
+ saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
+ }
+
+ /**
+ * Save a lock password. Does not ensure that the password is as good
+ * as the requested mode, but will adjust the mode to be as good as the
+ * password.
+ * @param password The password to save
+ * @param savedPassword The previously saved lock password, or null if none
+ * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
+ * android.content.ComponentName)}
+ * @param userHandle The userId of the user to change the password for
+ */
+ public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
+ int userHandle) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
- if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
+ if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must not be null and at least "
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
}
@@ -864,8 +919,8 @@
computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality),
userHandle);
try {
- getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD,
- savedPassword, requestedQuality, userHandle);
+ getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
+ requestedQuality, userHandle);
} catch (Exception e) {
Log.e(TAG, "Unable to save lock password", e);
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
@@ -882,7 +937,7 @@
* Update device encryption password if calling user is USER_SYSTEM and device supports
* encryption.
*/
- private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) {
+ private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) {
// Update the device encryption password.
if (userHandle == UserHandle.USER_SYSTEM
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
@@ -902,8 +957,8 @@
* Store the hash of the *current* password in the password history list, if device policy
* enforces password history requirement.
*/
- private void updatePasswordHistory(String password, int userHandle) {
- if (TextUtils.isEmpty(password)) {
+ private void updatePasswordHistory(byte[] password, int userHandle) {
+ if (password == null || password.length == 0) {
Log.e(TAG, "checkPasswordHistory: empty password");
return;
}
@@ -982,7 +1037,7 @@
* if DevicePolicyManager has a stronger quality requirement. This value will be written
* to PASSWORD_TYPE_KEY.
*/
- private int computePasswordQuality(int type, String credential, int requestedQuality) {
+ private int computePasswordQuality(int type, byte[] credential, int requestedQuality) {
final int quality;
if (type == CREDENTIAL_TYPE_PASSWORD) {
int computedQuality = PasswordMetrics.computeForPassword(credential).quality;
@@ -1005,7 +1060,7 @@
* true
*/
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
- String managedUserPassword) {
+ byte[] managedUserPassword) {
if (!isManagedProfile(userHandle)) {
return;
}
@@ -1069,15 +1124,28 @@
* Deserialize a pattern.
* @param string The pattern serialized with {@link #patternToString}
* @return The pattern.
+ * @deprecated Pass patterns as byte[] and use byteArrayToPattern
*/
+ @Deprecated
public static List<LockPatternView.Cell> stringToPattern(String string) {
if (string == null) {
return null;
}
+ return byteArrayToPattern(string.getBytes());
+ }
+
+ /**
+ * Deserialize a pattern.
+ * @param bytes The pattern serialized with {@link #patternToByteArray}
+ * @return The pattern.
+ */
+ public static List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
+ if (bytes == null) {
+ return null;
+ }
List<LockPatternView.Cell> result = Lists.newArrayList();
- final byte[] bytes = string.getBytes();
for (int i = 0; i < bytes.length; i++) {
byte b = (byte) (bytes[i] - '1');
result.add(LockPatternView.Cell.of(b / 3, b % 3));
@@ -1089,10 +1157,22 @@
* Serialize a pattern.
* @param pattern The pattern.
* @return The pattern in string form.
+ * @deprecated Use patternToByteArray instead.
*/
+ @Deprecated
public static String patternToString(List<LockPatternView.Cell> pattern) {
+ return new String(patternToByteArray(pattern));
+ }
+
+
+ /**
+ * Serialize a pattern.
+ * @param pattern The pattern.
+ * @return The pattern in byte array form.
+ */
+ public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {
if (pattern == null) {
- return "";
+ return new byte[0];
}
final int patternSize = pattern.size();
@@ -1101,21 +1181,24 @@
LockPatternView.Cell cell = pattern.get(i);
res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');
}
- return new String(res);
+ return res;
}
- public static String patternStringToBaseZero(String pattern) {
- if (pattern == null) {
- return "";
+ /**
+ * Transform a pattern byte array to base zero form.
+ * @param bytes pattern byte array.
+ * @return The pattern in base zero form.
+ */
+ public static byte[] patternByteArrayToBaseZero(byte[] bytes) {
+ if (bytes == null) {
+ return new byte[0];
}
- final int patternSize = pattern.length();
-
+ final int patternSize = bytes.length;
byte[] res = new byte[patternSize];
- final byte[] bytes = pattern.getBytes();
for (int i = 0; i < patternSize; i++) {
res[i] = (byte) (bytes[i] - '1');
}
- return new String(res);
+ return res;
}
/*
@@ -1169,13 +1252,18 @@
*
* @return the hash of the pattern in a byte array.
*/
- public String legacyPasswordToHash(String password, int userId) {
- if (password == null) {
+ public String legacyPasswordToHash(byte[] password, int userId) {
+ if (password == null || password.length == 0) {
return null;
}
try {
- byte[] saltedPassword = (password + getSalt(userId)).getBytes();
+ // Previously the password was passed as a String with the following code:
+ // byte[] saltedPassword = (password + getSalt(userId)).getBytes();
+ // The code below creates the identical digest preimage using byte arrays:
+ byte[] salt = getSalt(userId).getBytes();
+ byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, password.length, salt.length);
byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword);
byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword);
@@ -1184,6 +1272,7 @@
System.arraycopy(md5, 0, combined, sha1.length, md5.length);
final char[] hexEncoded = HexEncoding.encode(combined);
+ Arrays.fill(saltedPassword, (byte) 0);
return new String(hexEncoded);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError("Missing digest algorithm: ", e);
@@ -1193,14 +1282,19 @@
/**
* Hash the password for password history check purpose.
*/
- private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) {
- if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) {
+ private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) {
+ if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) {
return null;
}
try {
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
sha256.update(hashFactor);
- sha256.update((passwordToHash + getSalt(userId)).getBytes());
+ byte[] salt = getSalt(userId).getBytes();
+ byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length
+ + salt.length);
+ System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length);
+ sha256.update(saltedPassword);
+ Arrays.fill(saltedPassword, (byte) 0);
return new String(HexEncoding.encode(sha256.digest()));
} catch (NoSuchAlgorithmException e) {
throw new AssertionError("Missing digest algorithm: ", e);
@@ -1633,7 +1727,7 @@
* @param userId The user who's lock credential to be changed
* @return {@code true} if the operation is successful.
*/
- public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality,
+ public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality,
long tokenHandle, byte[] token, int userId) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -1641,13 +1735,13 @@
}
LockSettingsInternal localService = getLockSettingsInternal();
if (type != CREDENTIAL_TYPE_NONE) {
- if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) {
+ if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) {
throw new IllegalArgumentException("password must not be null and at least "
+ "of length " + MIN_LOCK_PASSWORD_SIZE);
}
final int quality = computePasswordQuality(type, credential, requestedQuality);
- if (!localService.setLockCredentialWithToken(credential, type, tokenHandle,
- token, quality, userId)) {
+ if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token,
+ quality, userId)) {
return false;
}
setKeyguardStoredPasswordQuality(quality, userId);
@@ -1656,11 +1750,11 @@
updatePasswordHistory(credential, userId);
onAfterChangingPassword(userId);
} else {
- if (!TextUtils.isEmpty(credential)) {
+ if (!(credential == null || credential.length == 0)) {
throw new IllegalArgumentException("password must be emtpy for NONE type");
}
- if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE,
- tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
+ if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle,
+ token, PASSWORD_QUALITY_UNSPECIFIED, userId)) {
return false;
}
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId);
@@ -1891,4 +1985,22 @@
return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
}
+
+ /**
+ * Converts a CharSequence to a byte array without requiring a toString(), which creates an
+ * additional copy.
+ *
+ * @param chars The CharSequence to convert
+ * @return A byte array representing the input
+ */
+ public static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 25a5a07..4b26990 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1273,8 +1273,10 @@
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
+ byte[] patternBytes = LockPatternUtils.patternToByteArray(mPattern);
+ String patternString = patternBytes != null ? new String(patternBytes) : null;
return new SavedState(superState,
- LockPatternUtils.patternToString(mPattern),
+ patternString,
mPatternDisplayMode.ordinal(),
mInputEnabled, mInStealthMode, mEnableHapticFeedback);
}
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 9de9ef7..90397df 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -49,7 +49,11 @@
*/
public abstract boolean isEscrowTokenActive(long handle, int userId);
- public abstract boolean setLockCredentialWithToken(String credential, int type,
+ /**
+ * Set the lock credential.
+ * @return true if password is set.
+ */
+ public abstract boolean setLockCredentialWithToken(byte[] credential, int type,
long tokenHandle, byte[] token, int requestedQuality, int userId);
public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId);
diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp
index a18e80a..d7d31e5 100644
--- a/core/jni/android_media_AudioProductStrategies.cpp
+++ b/core/jni/android_media_AudioProductStrategies.cpp
@@ -194,12 +194,34 @@
return jStatus;
}
+static jint
+android_media_AudioSystem_getProductStrategyFromAudioAttributes(JNIEnv *env, jobject clazz,
+ jobject jAudioAttributes)
+{
+ JNIAudioAttributeHelper::UniqueAaPtr attributes = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env,
+ jAudioAttributes,
+ attributes.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return jStatus;
+ }
+ product_strategy_t psId;
+ status_t status = AudioSystem::getProductStrategyFromAudioAttributes(
+ AudioAttributes(*attributes.get()), psId);
+ if (status != NO_ERROR) {
+ return nativeToJavaStatus(status);
+ }
+ return psId;
+}
+
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
{"native_list_audio_product_strategies", "(Ljava/util/ArrayList;)I",
(void *)android_media_AudioSystem_listAudioProductStrategies},
+ {"native_get_product_strategies_from_audio_attributes", "(Landroid/media/AudioAttributes;)I",
+ (void *)android_media_AudioSystem_getProductStrategyFromAudioAttributes},
};
int register_android_media_AudioProductStrategies(JNIEnv *env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 191472d..8d702d1 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -41,6 +41,7 @@
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
+ jmethodID dispatchConfigChanged;
} gDisplayEventReceiverClassInfo;
@@ -61,6 +62,8 @@
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) override;
};
@@ -114,6 +117,23 @@
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
+void NativeDisplayEventReceiver::dispatchConfigChanged(nsecs_t timestamp,
+ PhysicalDisplayId displayId,
+ int32_t configId) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
+ if (receiverObj.get()) {
+ ALOGV("receiver %p ~ Invoking config changed handler.", this);
+ env->CallVoidMethod(receiverObj.get(),
+ gDisplayEventReceiverClassInfo.dispatchConfigChanged,
+ timestamp, displayId, configId);
+ ALOGV("receiver %p ~ Returned from config changed handler.", this);
+ }
+
+ mMessageQueue->raiseAndClearException(env, "dispatchConfigChanged");
+}
+
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject messageQueueObj, jint vsyncSource) {
@@ -180,6 +200,8 @@
gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
+ gDisplayEventReceiverClassInfo.dispatchConfigChanged = GetMethodIDOrDie(env,
+ gDisplayEventReceiverClassInfo.clazz, "dispatchConfigChanged", "(JJI)V");
return res;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 4069e95..4c25fd4 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -698,6 +698,25 @@
return configArray;
}
+static jboolean nativeSetAllowedDisplayConfigs(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jintArray configArray) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == nullptr) return JNI_FALSE;
+
+ std::vector<int32_t> allowedConfigs;
+ jsize configArraySize = env->GetArrayLength(configArray);
+ allowedConfigs.reserve(configArraySize);
+
+ jint* configArrayElements = env->GetIntArrayElements(configArray, 0);
+ for (int i = 0; i < configArraySize; i++) {
+ allowedConfigs.push_back(configArrayElements[i]);
+ }
+ env->ReleaseIntArrayElements(configArray, configArrayElements, 0);
+
+ size_t result = SurfaceComposerClient::setAllowedDisplayConfigs(token, allowedConfigs);
+ return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
@@ -1194,6 +1213,8 @@
(void*)nativeGetActiveConfig },
{"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
(void*)nativeSetActiveConfig },
+ {"nativeSetAllowedDisplayConfigs", "(Landroid/os/IBinder;[I)Z",
+ (void*)nativeSetAllowedDisplayConfigs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7443c36..2ccb01a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1240,6 +1240,8 @@
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
+ } else {
+ ALOGD("Forked child process %d", pid);
}
// We blocked SIGCHLD prior to a fork, we unblock it here.
diff --git a/core/res/res/drawable/ic_qs_battery_saver.xml b/core/res/res/drawable/ic_qs_battery_saver.xml
index 89b2569..93975b6 100644
--- a/core/res/res/drawable/ic_qs_battery_saver.xml
+++ b/core/res/res/drawable/ic_qs_battery_saver.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (C) 2018 The Android Open Source Project
+ 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.
@@ -21,8 +21,10 @@
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
- android:pathData="M5,3
- l3.5,0 l0,-1.5 l7,0 l0,1.5 l3.5,0 l0,19.5 l-14,0z
- M10.5,8.5 l0,3 l-3,0 l0,3 l3,0 l0,3 l3,0 l0,-3 l3,0 l0,-3 l-3,0 l0,-3 z"
- android:fillColor="#FFFFFF"/>
+ android:fillColor="#FFF"
+ android:pathData="M16.67,4H14.5V2h-5v2H7.33C6.6,4 6,4.6 6,5.33V15v5.67C6,21.4 6.6,22 7.33,22h9.33C17.4,22 18,21.4 18,20.67V15V5.33C18,4.6 17.4,4 16.67,4zM16,15v5H8v-5V6h8V15z"/>
+ <path
+ android:fillColor="#FFF"
+ android:pathData="M15,12l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z"/>
+
</vector>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0041bfc..910af4c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2008,11 +2008,6 @@
a transaction, so it interacts poorly with SECURE_DELETE. -->
<string name="db_default_journal_mode" translatable="false">TRUNCATE</string>
- <!-- Enables compatibility WAL mode.
- In this mode, only database journal mode will be changed, connection pool
- size will still be limited to a single connection. -->
- <bool name="db_compatibility_wal_supported">true</bool>
-
<!-- Maximum size of the persistent journal file in bytes.
If the journal file grows to be larger than this amount then SQLite will
truncate it after committing the transaction. -->
@@ -3935,4 +3930,25 @@
The same restrictions apply to this array. -->
<array name="config_displayWhiteBalanceDisplayColorTemperatures">
</array>
+
+ <!-- All of the paths defined for the batterymeter are defined on a 12x20 canvas, and must
+ be parsable by android.utill.PathParser -->
+ <string name="config_batterymeterPerimeterPath" translatable="false">
+ M3.5,2 v0 H1.33 C0.6,2 0,2.6 0,3.33 V13v5.67 C0,19.4 0.6,20 1.33,20 h9.33 C11.4,20 12,19.4 12,18.67 V13V3.33 C12,2.6 11.4,2 10.67,2 H8.5 V0 H3.5 z M2,18v-7V4h8v9v5H2L2,18z
+ </string>
+
+ <string name="config_batterymeterFillMask" translatable="false">
+ M2,18 v-14 h8 v14 z
+ </string>
+ <string name="config_batterymeterBoltPath" translatable="false">
+ M5,17.5 V12 H3 L7,4.5 V10 h2 L5,17.5 z
+ </string>
+ <string name="config_batterymeterPowersavePath" translatable="false">
+ M9,10l-2,0l0,-2l-2,0l0,2l-2,0l0,2l2,0l0,2l2,0l0,-2l2,0z
+ </string>
+
+ <!-- A dual tone battery meter draws the perimeter path twice - once to define the shape
+ and a second time clipped to the fill level to indicate charge -->
+ <bool name="config_batterymeterDualTone">false</bool>
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 33ca311..426d813 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -752,7 +752,6 @@
<java-symbol type="string" name="date_time" />
<java-symbol type="string" name="date_time_set" />
<java-symbol type="string" name="date_time_done" />
- <java-symbol type="bool" name="db_compatibility_wal_supported" />
<java-symbol type="string" name="db_default_journal_mode" />
<java-symbol type="string" name="db_default_sync_mode" />
<java-symbol type="string" name="db_wal_sync_mode" />
@@ -3197,6 +3196,11 @@
<java-symbol type="raw" name="fallback_categories" />
<java-symbol type="string" name="config_icon_mask" />
+ <java-symbol type="string" name="config_batterymeterPerimeterPath" />
+ <java-symbol type="string" name="config_batterymeterFillMask" />
+ <java-symbol type="string" name="config_batterymeterBoltPath" />
+ <java-symbol type="string" name="config_batterymeterPowersavePath" />
+ <java-symbol type="bool" name="config_batterymeterDualTone" />
<!-- Accessibility Shortcut -->
<java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index 5731daa..4ae9494 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -99,7 +99,8 @@
@Test
public void testComputeForPassword_metrics() {
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A");
+ final PasswordMetrics metrics =
+ PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes());
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
@@ -112,32 +113,32 @@
@Test
public void testComputeForPassword_quality() {
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
- PasswordMetrics.computeForPassword("a1").quality);
+ PasswordMetrics.computeForPassword("a1".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
- PasswordMetrics.computeForPassword("a").quality);
+ PasswordMetrics.computeForPassword("a".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
- PasswordMetrics.computeForPassword("*~&%$").quality);
+ PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
- PasswordMetrics.computeForPassword("1").quality);
+ PasswordMetrics.computeForPassword("1".getBytes()).quality);
// contains a long sequence so isn't complex
assertEquals(PASSWORD_QUALITY_NUMERIC,
- PasswordMetrics.computeForPassword("1234").quality);
+ PasswordMetrics.computeForPassword("1234".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
- PasswordMetrics.computeForPassword("").quality);
+ PasswordMetrics.computeForPassword("".getBytes()).quality);
}
@Test
public void testMaxLengthSequence() {
- assertEquals(4, PasswordMetrics.maxLengthSequence("1234"));
- assertEquals(5, PasswordMetrics.maxLengthSequence("13579"));
- assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd"));
- assertEquals(3, PasswordMetrics.maxLengthSequence("aabc"));
- assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio"));
- assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC"));
+ assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes()));
+ assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes()));
+ assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes()));
+ assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes()));
+ assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes()));
+ assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes()));
// anything that repeats
- assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;"));
+ assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes()));
// ordered, but not composed of alphas or digits
- assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>"));
+ assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes()));
}
@Test
@@ -158,8 +159,8 @@
assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
new PasswordMetrics(PASSWORD_QUALITY_COMPLEX, 4));
- metrics0 = PasswordMetrics.computeForPassword("1234abcd,./");
- metrics1 = PasswordMetrics.computeForPassword("1234abcd,./");
+ metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
+ metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
assertEquals(metrics0, metrics1);
metrics1.letters++;
assertNotEquals(metrics0, metrics1);
@@ -197,7 +198,7 @@
@Test
public void testDetermineComplexity_none() {
assertEquals(PASSWORD_COMPLEXITY_NONE,
- PasswordMetrics.computeForPassword("").determineComplexity());
+ PasswordMetrics.computeForPassword("".getBytes()).determineComplexity());
}
@Test
@@ -209,61 +210,61 @@
@Test
public void testDetermineComplexity_lowNumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("1234").determineComplexity());
+ PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("124").determineComplexity());
+ PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!").determineComplexity());
+ PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPassword("a!1").determineComplexity());
+ PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("1238").determineComplexity());
+ PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!c").determineComplexity());
+ PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPassword("ab!1").determineComplexity());
+ PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("12389647!").determineComplexity());
+ PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("alphabetic!").determineComplexity());
+ PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPassword("alphanumeric123!").determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword(
+ "alphanumeric123!".getBytes()).determineComplexity());
}
@Test
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
index 5dbcb3c..82bd588 100644
--- a/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
+++ b/core/tests/coretests/src/android/database/sqlite/SQLiteCompatibilityWalFlagsTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.Context;
import android.database.DatabaseUtils;
@@ -54,44 +55,52 @@
@Test
public void testParseConfig() {
SQLiteCompatibilityWalFlags.init("");
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
-
SQLiteCompatibilityWalFlags.init(null);
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=false,wal_syncmode=OFF");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
- assertFalse(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals("OFF", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ // Ensure that legacy compatibility wal isn't turned on by the old flag.
+ SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=OFF");
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
+ try {
+ SQLiteCompatibilityWalFlags.getWALSyncMode();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+
SQLiteCompatibilityWalFlags.init("wal_syncmode=VALUE");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
- assertEquals(SQLiteGlobal.isCompatibilityWalSupported(),
- SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+ try {
+ SQLiteCompatibilityWalFlags.getWALSyncMode();
+ fail();
+ } catch (IllegalStateException expected) {
+ }
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true");
- assertTrue(SQLiteCompatibilityWalFlags.areFlagsSet());
+ SQLiteCompatibilityWalFlags.init("legacy_compatibility_wal_enabled=true");
+ assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
assertEquals(SQLiteGlobal.getWALSyncMode(),
SQLiteCompatibilityWalFlags.getWALSyncMode());
- assertTrue(SQLiteCompatibilityWalFlags.isCompatibilityWalSupported());
- assertEquals(-1, SQLiteCompatibilityWalFlags.getTruncateSize());
+
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=VALUE");
+ assertTrue(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
+ assertEquals("VALUE", SQLiteCompatibilityWalFlags.getWALSyncMode());
SQLiteCompatibilityWalFlags.init("truncate_size=1024");
assertEquals(1024, SQLiteCompatibilityWalFlags.getTruncateSize());
SQLiteCompatibilityWalFlags.reset();
SQLiteCompatibilityWalFlags.init("Invalid value");
- assertFalse(SQLiteCompatibilityWalFlags.areFlagsSet());
+ assertFalse(SQLiteCompatibilityWalFlags.isLegacyCompatibilityWalEnabled());
}
@Test
public void testApplyFlags() {
Context ctx = InstrumentationRegistry.getContext();
- SQLiteCompatibilityWalFlags.init("compatibility_wal_supported=true,wal_syncmode=NORMAL");
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=NORMAL");
mDatabase = SQLiteDatabase
.openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
@@ -100,5 +109,22 @@
assertEquals("Normal mode (1) is expected", "1", syncMode);
}
+ @Test
+ public void testApplyFlags_thenDisableWriteAheadLogging() {
+ Context ctx = InstrumentationRegistry.getContext();
+ SQLiteCompatibilityWalFlags.init(
+ "legacy_compatibility_wal_enabled=true,wal_syncmode=FULL");
+ mDatabase = SQLiteDatabase
+ .openOrCreateDatabase(ctx.getDatabasePath("SQLiteCompatibilityWalFlagsTest"), null);
+
+ mDatabase.disableWriteAheadLogging();
+ String journalMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA journal_mode", null);
+ assertEquals(SQLiteGlobal.getDefaultJournalMode(), journalMode.toUpperCase());
+ String syncMode = DatabaseUtils.stringForQuery(mDatabase, "PRAGMA synchronous", null);
+ // TODO: This is the old behaviour and seems incorrect. The specified wal_syncmode was only
+ // intended to be used if the database is in WAL mode, and we should revert to the global
+ // default sync mode if WAL is disabled.
+ assertEquals("Normal mode (2) is expected", "2", syncMode);
+ }
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 71ce02d..23ab05e 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -129,6 +129,29 @@
assertPosition(navParams.matrix, new Rect(400, 0, 500, 500), new Rect(460, 0, 560, 500));
}
+ @Test
+ public void testFinishing() {
+ when(mMockController.getState()).thenReturn(mInsetsState);
+ mController.finish(sideBars());
+ mController.applyChangeInsets(mInsetsState);
+ assertFalse(mInsetsState.getSource(TYPE_TOP_BAR).isVisible());
+ assertTrue(mInsetsState.getSource(TYPE_NAVIGATION_BAR).isVisible());
+ assertEquals(Insets.of(0, 0, 100, 0), mController.getCurrentInsets());
+ verify(mMockController).notifyFinished(eq(mController), eq(sideBars()));
+ }
+
+ @Test
+ public void testCancelled() {
+ mController.onCancelled();
+ try {
+ mController.changeInsets(Insets.NONE);
+ fail("Expected exception to be thrown");
+ } catch (IllegalStateException ignored) {
+ }
+ verify(mMockListener).onCancelled();
+ mController.finish(sideBars());
+ }
+
private void assertPosition(Matrix m, Rect original, Rect transformed) {
RectF rect = new RectF(original);
rect.offsetTo(0, 0);
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 731d564..d71bde83 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -20,6 +20,7 @@
import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
import static android.view.InsetsState.TYPE_TOP_BAR;
+import static android.view.WindowInsets.Type.topBar;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -48,6 +49,9 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.concurrent.CountDownLatch;
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
@@ -80,6 +84,8 @@
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
rect, rect, SOFT_INPUT_ADJUST_RESIZE);
+ mController.onFrameChanged(new Rect(0, 0, 100, 100));
+ mController.getState().setDisplayFrame(new Rect(0, 0, 100, 100));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -101,6 +107,19 @@
}
@Test
+ public void testControlsRevoked_duringAnim() {
+ InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
+
+ WindowInsetsAnimationControlListener mockListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(topBar(), mockListener);
+ verify(mockListener).onReady(any(), anyInt());
+ mController.onControlsChanged(new InsetsSourceControl[0]);
+ verify(mockListener).onCancelled();
+ }
+
+ @Test
public void testFrameDoesntMatchDisplay() {
mController.onFrameChanged(new Rect(0, 0, 100, 100));
mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
@@ -119,24 +138,21 @@
InsetsSourceControl ime = controls[2];
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // since there is no focused view, forcefully make IME visible.
+ mController.applyImeVisibility(true /* setVisible */);
mController.show(Type.all());
// quickly jump to final state by cancelling it.
mController.cancelExistingAnimation();
assertTrue(mController.getSourceConsumer(navBar.getType()).isVisible());
assertTrue(mController.getSourceConsumer(topBar.getType()).isVisible());
- // no focused view, no IME.
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+ assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+ mController.applyImeVisibility(false /* setVisible */);
mController.hide(Type.all());
mController.cancelExistingAnimation();
assertFalse(mController.getSourceConsumer(navBar.getType()).isVisible());
assertFalse(mController.getSourceConsumer(topBar.getType()).isVisible());
assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
-
- mController.show(Type.ime());
- mController.cancelExistingAnimation();
- // no focused view, no IME.
- assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
@@ -292,6 +308,35 @@
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
+ @Test
+ public void testAnimationEndState_controller() throws Exception {
+ InsetsSourceControl control = new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ WindowInsetsAnimationControlListener mockListener =
+ mock(WindowInsetsAnimationControlListener.class);
+ mController.controlWindowInsetsAnimation(topBar(), mockListener);
+
+ ArgumentCaptor<WindowInsetsAnimationController> controllerCaptor =
+ ArgumentCaptor.forClass(WindowInsetsAnimationController.class);
+ verify(mockListener).onReady(controllerCaptor.capture(), anyInt());
+ controllerCaptor.getValue().finish(0 /* shownTypes */);
+ });
+ waitUntilNextFrame();
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ assertFalse(mController.getSourceConsumer(TYPE_TOP_BAR).isVisible());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ private void waitUntilNextFrame() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(1);
+ Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
+ latch::countDown, null /* token */);
+ latch.await();
+ }
+
private InsetsSourceControl[] prepareControls() {
final InsetsSourceControl navBar = new InsetsSourceControl(TYPE_NAVIGATION_BAR, mLeash,
new Point());
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index aaf40b4..83c8b01 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -599,9 +599,6 @@
int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
@NonNull Paint paint) {
checkRange(verts.length, vertOffset, vertexCount);
- if (isHardwareAccelerated()) {
- return;
- }
if (texs != null) {
checkRange(texs.length, texOffset, vertexCount);
}
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
index 3b9a348..6606148 100644
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -135,6 +135,9 @@
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, ev.config.configId);
+ break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
break;
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index d2addba..5381c01 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -40,6 +40,8 @@
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
+ virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) = 0;
virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 733b866..abf0837 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -759,11 +759,11 @@
void PointerController::loadResourcesLocked() REQUIRES(mLock) {
mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId);
+ mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
+ mLocked.additionalMouseResources.clear();
+ mLocked.animationResources.clear();
if (mLocked.presentation == PRESENTATION_POINTER) {
- mLocked.additionalMouseResources.clear();
- mLocked.animationResources.clear();
- mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId);
mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
&mLocked.animationResources, mLocked.viewport.displayId);
}
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index dbb581f..d1b39b3 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -11,7 +11,7 @@
method public android.os.IBinder getBinder();
method public boolean isEnabled();
method @Deprecated protected void onDisable();
- method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
+ method @Deprecated protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method @Deprecated protected void onEnable();
method @Deprecated protected int onGetStatus(android.os.Bundle);
method @Deprecated protected long onGetStatusUpdateTime();
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 7cd7207..fa113a8 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -240,8 +240,10 @@
protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
/**
- * Dump debug information.
+ * @deprecated This callback will never be invoked on Android Q and above. This method may be
+ * removed in the future. Prefer to dump provider state via the containing service instead.
*/
+ @Deprecated
protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
/**
@@ -336,10 +338,5 @@
public void sendExtraCommand(String command, Bundle extras) {
onSendExtraCommand(command, extras);
}
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- onDump(fd, pw, args);
- }
}
}
diff --git a/media/apex/java/android/media/MediaConstants.java b/media/apex/java/android/media/MediaConstants.java
index 65b6f55..776c1ba 100644
--- a/media/apex/java/android/media/MediaConstants.java
+++ b/media/apex/java/android/media/MediaConstants.java
@@ -27,6 +27,7 @@
static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE";
+ static final String KEY_TOKEN_EXTRAS = "android.media.key.TOKEN_EXTRAS";
private MediaConstants() {
}
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
index 4ea384a..2709df0 100644
--- a/media/apex/java/android/media/MediaController2.java
+++ b/media/apex/java/android/media/MediaController2.java
@@ -21,6 +21,7 @@
import static android.media.MediaConstants.KEY_PID;
import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -264,6 +265,7 @@
Session2CommandGroup allowedCommands =
connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE);
+ Bundle tokenExtras = connectionResult.getBundle(KEY_TOKEN_EXTRAS);
if (DEBUG) {
Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder
+ ", allowedCommands=" + allowedCommands);
@@ -282,7 +284,7 @@
// so can be used without worrying about deadlock.
sessionBinder.linkToDeath(mDeathRecipient, 0);
mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION,
- mSessionToken.getPackageName(), sessionBinder);
+ mSessionToken.getPackageName(), sessionBinder, tokenExtras);
}
mCallbackExecutor.execute(() -> {
mCallback.onConnected(MediaController2.this, allowedCommands);
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index 4c6945a..148e16c 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -21,6 +21,7 @@
import static android.media.MediaConstants.KEY_PID;
import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE;
import static android.media.MediaConstants.KEY_SESSION2LINK;
+import static android.media.MediaConstants.KEY_TOKEN_EXTRAS;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -94,7 +95,8 @@
private ForegroundServiceEventCallback mForegroundServiceEventCallback;
MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
- @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) {
+ @NonNull Executor callbackExecutor, @NonNull SessionCallback callback,
+ Bundle tokenExtras) {
synchronized (MediaSession2.class) {
if (SESSION_ID_LIST.contains(id)) {
throw new IllegalStateException("Session ID must be unique. ID=" + id);
@@ -109,7 +111,7 @@
mCallback = callback;
mSessionStub = new Session2Link(this);
mSessionToken = new Session2Token(Process.myUid(), TYPE_SESSION, context.getPackageName(),
- mSessionStub);
+ mSessionStub, tokenExtras);
mSessionManager = (MediaSessionManager) mContext.getSystemService(
Context.MEDIA_SESSION_SERVICE);
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
@@ -339,6 +341,7 @@
connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
controllerInfo.mAllowedCommands);
connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive());
+ connectionResult.putBundle(KEY_TOKEN_EXTRAS, mSessionToken.getExtras());
// Double check if session is still there, because close() can be called in
// another thread.
@@ -444,6 +447,7 @@
private PendingIntent mSessionActivity;
private Executor mCallbackExecutor;
private SessionCallback mCallback;
+ private Bundle mExtras;
/**
* Creates a builder for {@link MediaSession2}.
@@ -507,6 +511,18 @@
}
/**
+ * Set extras for the session token.
+ *
+ * @return The Builder to allow chaining
+ * @see Session2Token#getExtras()
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /**
* Build {@link MediaSession2}.
*
* @return a new session
@@ -525,7 +541,7 @@
mId = "";
}
MediaSession2 session2 = new MediaSession2(mContext, mId, mSessionActivity,
- mCallbackExecutor, mCallback);
+ mCallbackExecutor, mCallback, mExtras);
// Notify framework about the newly create session after the constructor is finished.
// Otherwise, framework may access the session before the initialization is finished.
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
index 238cc2b..6680e40 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -88,6 +89,7 @@
private final String mServiceName;
private final Session2Link mSessionLink;
private final ComponentName mComponentName;
+ private final Bundle mExtras;
/**
* Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
@@ -116,15 +118,18 @@
mUid = uid;
mType = TYPE_SESSION_SERVICE;
mSessionLink = null;
+ mExtras = null;
}
- Session2Token(int uid, int type, String packageName, Session2Link sessionLink) {
+ Session2Token(int uid, int type, String packageName, Session2Link sessionLink,
+ Bundle tokenExtras) {
mUid = uid;
mType = type;
mPackageName = packageName;
mServiceName = null;
mComponentName = null;
mSessionLink = sessionLink;
+ mExtras = tokenExtras;
}
Session2Token(Parcel in) {
@@ -134,6 +139,7 @@
mServiceName = in.readString();
mSessionLink = in.readParcelable(null);
mComponentName = ComponentName.unflattenFromString(in.readString());
+ mExtras = in.readBundle();
}
@Override
@@ -144,6 +150,7 @@
dest.writeString(mServiceName);
dest.writeParcelable(mSessionLink, flags);
dest.writeString(mComponentName == null ? "" : mComponentName.flattenToString());
+ dest.writeBundle(mExtras);
}
@Override
@@ -207,6 +214,14 @@
return mType;
}
+ /**
+ * @return extras of the token
+ */
+ @Nullable
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
Session2Link getSessionLink() {
return mSessionLink;
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index bd828ee..3fb2365 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.projection.MediaProjection;
import android.media.session.MediaController;
import android.media.session.MediaSession;
@@ -5221,6 +5222,30 @@
return AudioSystem.isHapticPlaybackSupported();
}
+ /**
+ * @hide
+ * Introspection API to retrieve audio product strategies.
+ * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
+ * audio product strategies, which is indexed by a weakly typed index in order to be extended
+ * by OEM without any needs of AOSP patches.
+ * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
+ * strategy refered either by its index or human readable string. It will allow clients
+ * application to start streaming data using these {@link AudioAttributes} on the selected
+ * device by Audio Policy Engine.
+ * @return a (possibly zero-length) array of
+ * {@see android.media.audiopolicy.AudioProductStrategy} objects.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public @NonNull AudioProductStrategies getAudioProductStrategies() {
+ final IAudioService service = getService();
+ try {
+ return service.getAudioProductStrategies();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
//---------------------------------------------------------
// Inner classes
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 571e67e..abdc3c9 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -33,6 +33,7 @@
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
@@ -82,6 +83,8 @@
int getLastAudibleStreamVolume(int streamType);
+ AudioProductStrategies getAudioProductStrategies();
+
void setMicrophoneMute(boolean on, String callingPackage, int userId);
void setRingerModeExternal(int ringerMode, String caller);
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategies.java b/media/java/android/media/audiopolicy/AudioProductStrategies.java
index b836409..6a2375f 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategies.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategies.java
@@ -144,8 +144,10 @@
* @hide
* @param aa the {@link AudioAttributes} for which stream type is requested
* @return the legacy stream type relevant for the given {@link AudioAttributes}.
- * If the product strategy is not associated to any stream, it returns STREAM_MUSIC.
- * If no product strategy supports the stream type, it returns STREAM_MUSIC.
+ * If the product strategy is not associated to any stream, it returns
+ * {@link AudioSystem#STREAM_MUSIC}.
+ * If no product strategy supports the stream type, it returns
+ * {@link AudioSystem#STREAM_MUSIC}.
*/
@SystemApi
public int getLegacyStreamTypeForAudioAttributes(@NonNull AudioAttributes aa) {
@@ -165,6 +167,19 @@
return AudioSystem.STREAM_MUSIC;
}
+ /**
+ * @hide
+ * @param aa the {@link AudioAttributes} to be considered
+ * @return {@link AudioProductStrategy} supporting the given {@link AudioAttributes}.
+ * null is returned if no match with given attributes.
+ */
+ @SystemApi
+ @Nullable
+ public AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull AudioAttributes aa) {
+ Preconditions.checkNotNull(aa, "attributes must not be null");
+ return getById(native_get_product_strategies_from_audio_attributes(aa));
+ }
+
@Override
public int describeContents() {
return 0;
@@ -198,4 +213,7 @@
private static native int native_list_audio_product_strategies(
ArrayList<AudioProductStrategy> strategies);
+
+ private static native int native_get_product_strategies_from_audio_attributes(
+ AudioAttributes attributes);
}
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
index 2db575b..3fecd53 100644
--- a/native/android/choreographer.cpp
+++ b/native/android/choreographer.cpp
@@ -70,6 +70,8 @@
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
+ int32_t configId) override;
void scheduleCallbacks();
@@ -164,6 +166,13 @@
this, displayId, toString(connected));
}
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
+ int32_t configId) {
+ ALOGV("choreographer %p ~ received config changed event (displayId=%"
+ ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
+ this, displayId, toString(configId));
+}
+
void Choreographer::handleMessage(const Message& message) {
switch (message.what) {
case MSG_SCHEDULE_CALLBACKS:
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index caa928f..730e9e1 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -29,7 +29,7 @@
resource_dirs: ["res"],
- srcs: ["src/**/*.java"],
+ srcs: ["src/**/*.java", "src/**/*.kt"],
min_sdk_version: "21",
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
index b053317..4bc68b3 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
@@ -25,8 +25,7 @@
<View
android:id="@+id/bar_view"
android:layout_width="8dp"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorAccent"/>
+ android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/icon_view"
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 647d080..4876cb6 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -18,7 +18,7 @@
<resources>
<style name="BarViewStyle">
<item name="android:layout_width">0dp</item>
- <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_height">226dp</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_marginStart">8dp</item>
<item name="android:layout_marginEnd">8dp</item>
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index 3b87fca..1003c97 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -160,8 +160,11 @@
// If the state is loading, we just show a blank view.
if (mIsLoading) {
+ holder.itemView.setVisibility(View.INVISIBLE);
return;
}
+ holder.itemView.setVisibility(View.VISIBLE);
+
// We must show title of bar chart.
bindChartTitleView(holder);
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
index 6bf61ae..3ef0235 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -89,7 +89,7 @@
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.settings_bar_view, this);
setOrientation(LinearLayout.VERTICAL);
- setGravity(Gravity.CENTER);
+ setGravity(Gravity.CENTER | Gravity.BOTTOM);
mBarView = findViewById(R.id.bar_view);
mIcon = findViewById(R.id.icon_view);
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
new file mode 100644
index 0000000..337106b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
@@ -0,0 +1,404 @@
+/*
+ * 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.settingslib.graph
+
+import android.content.Context
+import android.graphics.BlendMode
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.util.PathParser
+import android.util.TypedValue
+
+import com.android.settingslib.R
+import com.android.settingslib.Utils
+
+/**
+ * A battery meter drawable that respects paths configured in
+ * frameworks/base/core/res/res/values/config.xml to allow for an easily overrideable battery icon
+ */
+open class ThemedBatteryDrawable(private val context: Context, frameColor: Int) : Drawable() {
+
+ // Need to load:
+ // 1. perimeter shape
+ // 2. fill mask (if smaller than perimeter, this would create a fill that
+ // doesn't touch the walls
+ private val perimeterPath = Path()
+ private val scaledPerimeter = Path()
+ // Fill will cover the whole bounding rect of the fillMask, and be masked by the path
+ private val fillMask = Path()
+ private val scaledFill = Path()
+ // Based off of the mask, the fill will interpolate across this space
+ private val fillRect = RectF()
+ // Top of this rect changes based on level, 100% == fillRect
+ private val levelRect = RectF()
+ private val levelPath = Path()
+ // Updates the transform of the paths when our bounds change
+ private val scaleMatrix = Matrix()
+ private val padding = Rect()
+ // The net result of fill + perimeter paths
+ private val unifiedPath = Path()
+
+ // Bolt path (used while charging)
+ private val boltPath = Path()
+ private val scaledBolt = Path()
+
+ // Plus sign (used for power save mode)
+ private val plusPath = Path()
+ private val scaledPlus = Path()
+
+ private var intrinsicHeight: Int
+ private var intrinsicWidth: Int
+
+ // To implement hysteresis, keep track of the need to invert the interior icon of the battery
+ private var invertFillIcon = false
+
+ // Colors can be configured based on battery level (see res/values/arrays.xml)
+ private var colorLevels: IntArray
+
+ private var fillColor: Int = Color.MAGENTA
+ private var backgroundColor: Int = Color.MAGENTA
+ // updated whenever level changes
+ private var levelColor: Int = Color.MAGENTA
+
+ // Dual tone implies that battery level is a clipped overlay over top of the whole shape
+ private var dualTone = false
+
+ private val invalidateRunnable: () -> Unit = {
+ invalidateSelf()
+ }
+
+ open var criticalLevel: Int = 0
+
+ var charging = false
+ set(value) {
+ field = value
+ postInvalidate()
+ }
+
+ var powerSaveEnabled = false
+ set(value) {
+ field = value
+ postInvalidate()
+ }
+
+ private val fillColorStrokePaint: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.isDither = true
+ p.strokeWidth = 5f
+ p.style = Paint.Style.STROKE
+ p.blendMode = BlendMode.SRC
+ p.strokeMiter = 5f
+ p
+ }
+
+ private val fillColorStrokeProtection: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.isDither = true
+ p.strokeWidth = 5f
+ p.style = Paint.Style.STROKE
+ p.blendMode = BlendMode.CLEAR
+ p.strokeMiter = 5f
+ p
+ }
+
+ private val fillPaint: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.alpha = 255
+ p.isDither = true
+ p.strokeWidth = 0f
+ p.style = Paint.Style.FILL_AND_STROKE
+ p
+ }
+
+ // Only used if dualTone is set to true
+ private val dualToneBackgroundFill: Paint by lazy {
+ val p = Paint(Paint.ANTI_ALIAS_FLAG)
+ p.color = frameColor
+ p.alpha = 255
+ p.isDither = true
+ p.strokeWidth = 0f
+ p.style = Paint.Style.FILL_AND_STROKE
+ p
+ }
+
+ init {
+ val density = context.resources.displayMetrics.density
+ intrinsicHeight = (Companion.HEIGHT * density).toInt()
+ intrinsicWidth = (Companion.WIDTH * density).toInt()
+
+ val res = context.resources
+ val levels = res.obtainTypedArray(R.array.batterymeter_color_levels)
+ val colors = res.obtainTypedArray(R.array.batterymeter_color_values)
+ val N = levels.length()
+ colorLevels = IntArray(2 * N)
+ for (i in 0 until N) {
+ colorLevels[2 * i] = levels.getInt(i, 0)
+ if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
+ colorLevels[2 * i + 1] = Utils.getColorAttrDefaultColor(context,
+ colors.getThemeAttributeId(i, 0))
+ } else {
+ colorLevels[2 * i + 1] = colors.getColor(i, 0)
+ }
+ }
+ levels.recycle()
+ colors.recycle()
+
+ criticalLevel = context.resources.getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel)
+
+ loadPaths()
+ }
+
+ override fun draw(c: Canvas) {
+ unifiedPath.reset()
+ levelPath.reset()
+ levelRect.set(fillRect)
+ val fillFraction = level / 100f
+ val fillTop =
+ if (level >= 95)
+ fillRect.top
+ else
+ fillRect.top + (fillRect.height() * (1 - fillFraction))
+
+ levelRect.top = Math.floor(fillTop.toDouble()).toFloat()
+ levelPath.addRect(levelRect, Path.Direction.CCW)
+
+ // The perimeter should never change
+ unifiedPath.addPath(scaledPerimeter)
+ // IF drawing dual tone, the level is used only to clip the whole drawable path
+ if (!dualTone) {
+ unifiedPath.op(levelPath, Path.Op.UNION)
+ }
+
+ fillPaint.color = levelColor
+
+ // Deal with unifiedPath clipping before it draws
+ if (charging) {
+ // Clip out the bolt shape
+ unifiedPath.op(scaledBolt, Path.Op.DIFFERENCE)
+ if (!invertFillIcon) {
+ c.drawPath(scaledBolt, fillPaint)
+ }
+ } else if (powerSaveEnabled) {
+ // Clip out the plus shape
+ unifiedPath.op(scaledPlus, Path.Op.DIFFERENCE)
+ if (!invertFillIcon) {
+ c.drawPath(scaledPlus, fillPaint)
+ }
+ }
+
+ if (dualTone) {
+ // Dual tone means we draw the shape again, clipped to the charge level
+ c.drawPath(unifiedPath, dualToneBackgroundFill)
+ c.save()
+ c.clipRect(0f,
+ bounds.bottom - bounds.height() * fillFraction,
+ bounds.right.toFloat(),
+ bounds.bottom.toFloat())
+ c.drawPath(unifiedPath, fillPaint)
+ c.restore()
+ } else {
+ // Non dual-tone means we draw the perimeter (with the level fill), and potentially
+ // draw the fill again with a critical color
+ fillPaint.color = fillColor
+ c.drawPath(unifiedPath, fillPaint)
+ fillPaint.color = levelColor
+
+ // Show colorError below this level
+ if (level <= Companion.CRITICAL_LEVEL && !charging) {
+ c.save()
+ c.clipPath(scaledFill)
+ c.drawPath(levelPath, fillPaint)
+ c.restore()
+ }
+ }
+
+ if (charging) {
+ c.clipOutPath(scaledBolt)
+ if (invertFillIcon) {
+ c.drawPath(scaledBolt, fillColorStrokePaint)
+ } else {
+ c.drawPath(scaledBolt, fillColorStrokeProtection)
+ }
+ } else if (powerSaveEnabled) {
+ c.clipOutPath(scaledPlus)
+ if (invertFillIcon) {
+ c.drawPath(scaledPlus, fillColorStrokePaint)
+ } else {
+ c.drawPath(scaledPlus, fillColorStrokeProtection)
+ }
+ }
+ }
+
+ private fun batteryColorForLevel(level: Int): Int {
+ return when {
+ charging || powerSaveEnabled -> fillPaint.color
+ else -> getColorForLevel(level)
+ }
+ }
+
+ private fun getColorForLevel(level: Int): Int {
+ var thresh: Int
+ var color = 0
+ var i = 0
+ while (i < colorLevels.size) {
+ thresh = colorLevels[i]
+ color = colorLevels[i + 1]
+ if (level <= thresh) {
+
+ // Respect tinting for "normal" level
+ return if (i == colorLevels.size - 2) {
+ fillColor
+ } else {
+ color
+ }
+ }
+ i += 2
+ }
+ return color
+ }
+
+ /**
+ * Alpha is unused internally, and should be defined in the colors passed to {@link setColors}.
+ * Further, setting an alpha for a dual tone battery meter doesn't make sense without bounds
+ * defining the minimum background fill alpha. This is because fill + background must be equal
+ * to the net alpha passed in here.
+ */
+ override fun setAlpha(alpha: Int) {
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ fillPaint.colorFilter = colorFilter
+ fillColorStrokePaint.colorFilter = colorFilter
+ dualToneBackgroundFill.colorFilter = colorFilter
+ }
+
+ /**
+ * Deprecated, but required by Drawable
+ */
+ override fun getOpacity(): Int {
+ return PixelFormat.OPAQUE
+ }
+
+ override fun getIntrinsicHeight(): Int {
+ return intrinsicHeight
+ }
+
+ override fun getIntrinsicWidth(): Int {
+ return intrinsicWidth
+ }
+
+ /**
+ * Set the fill level
+ */
+ public open fun setBatteryLevel(l: Int) {
+ invertFillIcon = if (l >= 67) true else if (l <= 33) false else invertFillIcon
+ level = l
+ levelColor = batteryColorForLevel(level)
+ invalidateSelf()
+ }
+
+ public fun getBatteryLevel(): Int {
+ return level
+ }
+
+ override fun onBoundsChange(bounds: Rect?) {
+ super.onBoundsChange(bounds)
+ updateSize()
+ }
+
+ fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
+ padding.left = left
+ padding.top = top
+ padding.right = right
+ padding.bottom = bottom
+
+ updateSize()
+ }
+
+ fun setColors(fgColor: Int, bgColor: Int, singleToneColor: Int) {
+ fillColor = if (dualTone) fgColor else singleToneColor
+
+ fillPaint.color = fillColor
+ fillColorStrokePaint.color = fillColor
+
+ backgroundColor = bgColor
+ dualToneBackgroundFill.color = bgColor
+
+ invalidateSelf()
+ }
+
+ private fun postInvalidate() {
+ unscheduleSelf(invalidateRunnable)
+ scheduleSelf(invalidateRunnable, 0)
+ }
+
+ private fun updateSize() {
+ val b = bounds
+ if (b.isEmpty) {
+ scaleMatrix.setScale(1f, 1f)
+ } else {
+ scaleMatrix.setScale((b.right / Companion.WIDTH), (b.bottom / Companion.HEIGHT))
+ }
+
+ perimeterPath.transform(scaleMatrix, scaledPerimeter)
+ fillMask.transform(scaleMatrix, scaledFill)
+ scaledFill.computeBounds(fillRect, true)
+ boltPath.transform(scaleMatrix, scaledBolt)
+ plusPath.transform(scaleMatrix, scaledPlus)
+ }
+
+ private fun loadPaths() {
+ val pathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterPerimeterPath)
+ perimeterPath.set(PathParser.createPathFromPathData(pathString))
+ val b = RectF()
+ perimeterPath.computeBounds(b, true)
+
+ val fillMaskString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterFillMask)
+ fillMask.set(PathParser.createPathFromPathData(fillMaskString))
+ // Set the fill rect so we can calculate the fill properly
+ fillMask.computeBounds(fillRect, true)
+
+ val boltPathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterBoltPath)
+ boltPath.set(PathParser.createPathFromPathData(boltPathString))
+
+ val plusPathString = context.resources.getString(
+ com.android.internal.R.string.config_batterymeterPowersavePath)
+ plusPath.set(PathParser.createPathFromPathData(plusPathString))
+
+ dualTone = context.resources.getBoolean(
+ com.android.internal.R.bool.config_batterymeterDualTone)
+ }
+
+ companion object {
+ private const val TAG = "ThemedBatteryDrawable"
+ private const val WIDTH = 12f
+ private const val HEIGHT = 20f
+ private const val CRITICAL_LEVEL = 15
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index 2a12810..a31b71e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -59,6 +59,5 @@
setIcon(R.drawable.ic_info_outline_24);
setKey(KEY_FOOTER);
setOrder(ORDER_FOOTER);
- setSelectable(false);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 1080cf4..3acca2a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -305,7 +305,7 @@
}
@Test
- public void onBindViewHolder_loadingStateIsTrue_shouldNotInitAnyView() {
+ public void onBindViewHolder_loadingStateIsTrue_shouldHideAllViews() {
final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app);
viewInfo.setClickListener(v -> {
});
@@ -317,8 +317,7 @@
mPreference.onBindViewHolder(mHolder);
- assertThat(TextUtils.isEmpty(mTitleView.getText())).isTrue();
- assertThat(TextUtils.isEmpty(mDetailsView.getText())).isTrue();
+ assertThat(mHolder.itemView.getVisibility()).isEqualTo(View.INVISIBLE);
}
@Test
@@ -334,6 +333,7 @@
mPreference.onBindViewHolder(mHolder);
+ assertThat(mHolder.itemView.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(TextUtils.isEmpty(mTitleView.getText())).isFalse();
assertThat(TextUtils.isEmpty(mDetailsView.getText())).isFalse();
}
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
index bc15f2c4..665fc3f 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_content.xml
@@ -54,9 +54,6 @@
android:orientation="vertical"
android:gravity="start"
/>
-
- <include android:id="@+id/overflow" layout="@layout/ongoing_privacy_dialog_item"
- android:visibility="gone" />
</LinearLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 536bc4e..50cf37b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -44,8 +44,9 @@
<!-- Height of the battery icon in the status bar. -->
<dimen name="status_bar_battery_icon_height">13.0dp</dimen>
- <!-- Width of the battery icon in the status bar. -->
- <dimen name="status_bar_battery_icon_width">8.5dp</dimen>
+ <!-- Width of the battery icon in the status bar. The battery drawable assumes a 12x20 canvas,
+ so the width of the icon should be 13.0dp * (12.0 / 20.0) -->
+ <dimen name="status_bar_battery_icon_width">7.8dp</dimen>
<!-- The font size for the clock in the status bar. -->
<dimen name="status_bar_clock_size">14sp</dimen>
@@ -1049,4 +1050,7 @@
<dimen name="bubble_pointer_margin">8dp</dimen>
<!-- Height of the permission prompt shown with bubbles -->
<dimen name="bubble_permission_height">120dp</dimen>
+
+ <!-- Size of the RAT type for CellularTile -->
+ <dimen name="celltile_rat_type_size">10sp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1e411cf..30dbc8b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -216,6 +216,12 @@
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
+ <!-- This is hard coded to be sans-serif-condensed to match the icons -->
+ <style name="TextAppearance.RATBadge" parent="@style/TextAppearance.QS.TileLabel.Secondary">
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:textSize">@dimen/celltile_rat_type_size</item>
+ </style>
+
<style name="TextAppearance.QS.CarrierInfo">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
<item name="android:textSize">@dimen/qs_carrier_info_text_size</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a055950..4cb8d90 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -34,6 +34,8 @@
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
+import java.util.Arrays;
+
/**
* Base class for PIN and password unlock screens.
*/
@@ -124,18 +126,19 @@
protected void verifyPasswordAndUnlock() {
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
- final String entry = getPasswordText();
+ final byte[] entry = getPasswordText();
setPasswordEntryInputEnabled(false);
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
}
final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
// to avoid accidental lockout, only count attempts that are long enough to be a
// real password. This may require some tweaking.
setPasswordEntryInputEnabled(true);
onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
+ Arrays.fill(entry, (byte) 0);
return;
}
@@ -157,6 +160,7 @@
}
onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
true /* isValidPassword */);
+ Arrays.fill(entry, (byte) 0);
}
@Override
@@ -171,6 +175,7 @@
onPasswordChecked(userId, false /* matched */, timeoutMs,
true /* isValidPassword */);
}
+ Arrays.fill(entry, (byte) 0);
}
@Override
@@ -181,6 +186,7 @@
LatencyTracker.getInstance(mContext).onActionEnd(
ACTION_CHECK_CREDENTIAL_UNLOCKED);
}
+ Arrays.fill(entry, (byte) 0);
}
});
}
@@ -211,7 +217,7 @@
}
protected abstract void resetPasswordText(boolean animate, boolean announce);
- protected abstract String getPasswordText();
+ protected abstract byte[] getPasswordText();
protected abstract void setPasswordEntryEnabled(boolean enabled);
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 261f391..185edbf 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -241,8 +241,8 @@
}
@Override
- protected String getPasswordText() {
- return mPasswordEntry.getText().toString();
+ protected byte[] getPasswordText() {
+ return charSequenceToByteArray(mPasswordEntry.getText());
}
@Override
@@ -377,4 +377,18 @@
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock);
}
+
+ /*
+ * This method avoids creating a new string when getting a byte array from EditView#getText().
+ */
+ private static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 3cc18dd..ecafc34 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -165,8 +165,8 @@
}
@Override
- protected String getPasswordText() {
- return mPasswordEntry.getText();
+ protected byte[] getPasswordText() {
+ return charSequenceToByteArray(mPasswordEntry.getText());
}
@Override
@@ -264,4 +264,18 @@
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
}
+
+ /*
+ * This method avoids creating a new string when getting a byte array from EditView#getText().
+ */
+ private static byte[] charSequenceToByteArray(CharSequence chars) {
+ if (chars == null) {
+ return null;
+ }
+ byte[] bytes = new byte[chars.length()];
+ for (int i = 0; i < chars.length(); i++) {
+ bytes[i] = (byte) chars.charAt(i);
+ }
+ return bytes;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2006794..592b603 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -46,7 +46,7 @@
import android.widget.TextView;
import com.android.settingslib.Utils;
-import com.android.settingslib.graph.BatteryMeterDrawableBase;
+import com.android.settingslib.graph.ThemedBatteryDrawable;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
@@ -76,7 +76,7 @@
public static final int MODE_OFF = 2;
public static final int MODE_ESTIMATE = 3;
- private final BatteryMeterDrawableBase mDrawable;
+ private final ThemedBatteryDrawable mDrawable;
private final String mSlotBattery;
private final ImageView mBatteryIconView;
private final CurrentUserTracker mUserTracker;
@@ -94,9 +94,11 @@
private boolean mIsSubscribedForTunerUpdates;
private boolean mCharging;
+ private int mDarkModeSingleToneColor;
private int mDarkModeBackgroundColor;
private int mDarkModeFillColor;
+ private int mLightModeSingleToneColor;
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
private int mUser;
@@ -106,6 +108,7 @@
*/
private boolean mUseWallpaperTextColors;
+ private int mNonAdaptedSingleToneColor;
private int mNonAdaptedForegroundColor;
private int mNonAdaptedBackgroundColor;
@@ -127,7 +130,7 @@
defStyle, 0);
final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
context.getColor(R.color.meter_background_color));
- mDrawable = new BatteryMeterDrawableBase(context, frameColor);
+ mDrawable = new ThemedBatteryDrawable(context, frameColor);
atts.recycle();
mSettingObserver = new SettingObserver(new Handler(context.getMainLooper()));
@@ -169,6 +172,10 @@
setClipChildren(false);
setClipToPadding(false);
Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this);
+
+ // Needed for PorderDuff.Mode.CLEAR operations to work properly, but redraws don't happen
+ // enough to justify a hardware layer.
+ setLayerType(LAYER_TYPE_SOFTWARE, null);
}
public void setForceShowPercent(boolean show) {
@@ -243,9 +250,11 @@
if (mUseWallpaperTextColors) {
updateColors(
Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor),
- Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary));
+ Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColorSecondary),
+ Utils.getColorAttrDefaultColor(mContext, R.attr.wallpaperTextColor));
} else {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
+ mNonAdaptedSingleToneColor);
}
}
@@ -258,10 +267,14 @@
Utils.getThemeAttr(context, R.attr.darkIconTheme));
Context dualToneLightTheme = new ContextThemeWrapper(context,
Utils.getThemeAttr(context, R.attr.lightIconTheme));
+ mDarkModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
+ R.attr.singleToneColor);
mDarkModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.backgroundColor);
mDarkModeFillColor = Utils.getColorAttrDefaultColor(dualToneDarkTheme,
R.attr.fillColor);
+ mLightModeSingleToneColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
+ R.attr.singleToneColor);
mLightModeBackgroundColor = Utils.getColorAttrDefaultColor(dualToneLightTheme,
R.attr.backgroundColor);
mLightModeFillColor = Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor);
@@ -303,8 +316,8 @@
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- mDrawable.setBatteryLevel(level);
mDrawable.setCharging(pluggedIn);
+ mDrawable.setBatteryLevel(level);
mCharging = pluggedIn;
mLevel = level;
updatePercentText();
@@ -315,7 +328,7 @@
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
- mDrawable.setPowerSave(isPowerSave);
+ mDrawable.setPowerSaveEnabled(isPowerSave);
}
private TextView loadPercentView() {
@@ -406,21 +419,24 @@
@Override
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+ mNonAdaptedSingleToneColor = getColorForDarkIntensity(
+ intensity, mLightModeSingleToneColor, mDarkModeSingleToneColor);
mNonAdaptedForegroundColor = getColorForDarkIntensity(
intensity, mLightModeFillColor, mDarkModeFillColor);
mNonAdaptedBackgroundColor = getColorForDarkIntensity(
intensity, mLightModeBackgroundColor,mDarkModeBackgroundColor);
if (!mUseWallpaperTextColors) {
- updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor);
+ updateColors(mNonAdaptedForegroundColor, mNonAdaptedBackgroundColor,
+ mNonAdaptedSingleToneColor);
}
}
- private void updateColors(int foregroundColor, int backgroundColor) {
- mDrawable.setColors(foregroundColor, backgroundColor);
- mTextColor = foregroundColor;
+ private void updateColors(int foregroundColor, int backgroundColor, int singleToneColor) {
+ mDrawable.setColors(foregroundColor, backgroundColor, singleToneColor);
+ mTextColor = singleToneColor;
if (mBatteryPercentView != null) {
- mBatteryPercentView.setTextColor(foregroundColor);
+ mBatteryPercentView.setTextColor(singleToneColor);
}
}
@@ -429,7 +445,7 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- String powerSave = mDrawable == null ? null : mDrawable.getPowerSave() + "";
+ String powerSave = mDrawable == null ? null : mDrawable.getPowerSaveEnabled() + "";
CharSequence percent = mBatteryPercentView == null ? null : mBatteryPercentView.getText();
pw.println(" BatteryMeterView:");
pw.println(" mDrawable.getPowerSave: " + powerSave);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 5353ee6..06dbdbf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -17,11 +17,11 @@
package com.android.systemui.doze;
import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 3250182..36e28dc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -21,9 +21,9 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 4d89a39..6c4be06 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -17,12 +17,12 @@
package com.android.systemui.doze;
import android.annotation.MainThread;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
import android.view.Display;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.Preconditions;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index d1e127d..c5799cc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -30,6 +30,7 @@
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemClock;
@@ -40,7 +41,6 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.plugins.SensorManagerPlugin;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b6e830c..3654aac 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -27,6 +27,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -34,7 +35,6 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.Preconditions;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 75b8a05..84a3446 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -42,14 +42,10 @@
private val iconSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_size)
- private val plusSize = context.resources.getDimensionPixelSize(
- R.dimen.ongoing_appops_dialog_app_plus_size)
private val iconColor = context.resources.getColor(
com.android.internal.R.color.text_color_primary, context.theme)
- private val plusColor: Int
private val iconMargin = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_margin)
- private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
private val iconFactory = IconDrawableFactory.newInstance(context, true)
private var dismissDialog: (() -> Unit)? = null
private val appsAndTypes = dialogBuilder.appsAndTypes
@@ -57,13 +53,6 @@
{ it.second.min() },
{ it.first }))
- init {
- val a = context.theme.obtainStyledAttributes(
- intArrayOf(com.android.internal.R.attr.colorAccent))
- plusColor = a.getColor(0, 0)
- a.recycle()
- }
-
fun createDialog(): Dialog {
val builder = AlertDialog.Builder(context).apply {
setPositiveButton(R.string.ongoing_privacy_dialog_ok, null)
@@ -96,33 +85,9 @@
val numItems = appsAndTypes.size
for (i in 0..(numItems - 1)) {
- if (i >= MAX_ITEMS) break
val item = appsAndTypes[i]
addAppItem(appsList, item.first, item.second, dialogBuilder.types.size > 1)
}
-
- if (numItems > MAX_ITEMS) {
- val overflow = contentView.findViewById(R.id.overflow) as LinearLayout
- overflow.visibility = View.VISIBLE
- val overflowText = overflow.findViewById(R.id.app_name) as TextView
- overflowText.text = context.resources.getQuantityString(
- R.plurals.ongoing_privacy_dialog_overflow_text,
- numItems - MAX_ITEMS,
- numItems - MAX_ITEMS
- )
- val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
- val lp = overflowPlus.layoutParams.apply {
- height = plusSize
- width = plusSize
- }
- overflowPlus.layoutParams = lp
- overflowPlus.apply {
- val plus = context.getDrawable(R.drawable.plus)
- imageTintList = ColorStateList.valueOf(plusColor)
- setImageDrawable(plus)
- }
- }
-
return contentView
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index a6e48f8..3f581c4d 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -18,6 +18,8 @@
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import android.util.IconDrawableFactory
import com.android.systemui.R
typealias Privacy = PrivacyType
@@ -46,14 +48,21 @@
private val applicationInfo: ApplicationInfo? by lazy {
try {
- context.packageManager.getApplicationInfo(packageName, 0)
+ val userHandle = UserHandle.getUserHandleForUid(uid)
+ context.createPackageContextAsUser(packageName, 0, userHandle).getPackageManager()
+ .getApplicationInfo(packageName, 0)
} catch (_: PackageManager.NameNotFoundException) {
null
}
}
val icon: Drawable by lazy {
applicationInfo?.let {
- context.packageManager.getApplicationIcon(it)
+ try {
+ val iconFactory = IconDrawableFactory.newInstance(context, true)
+ iconFactory.getBadgedIcon(it, UserHandle.getUserId(uid))
+ } catch (_: Exception) {
+ null
+ }
} ?: context.getDrawable(android.R.drawable.sym_def_app_icon)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 7f76900..c664a20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -15,14 +15,11 @@
*/
package com.android.systemui.qs.tiles;
-import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Drawable;
import android.service.quicksettings.Tile;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.graph.BatteryMeterDrawableBase;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.qs.QSHost;
@@ -41,6 +38,8 @@
private boolean mCharging;
private boolean mPluggedIn;
+ private Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_battery_saver);
+
@Inject
public BatterySaverTile(QSHost host, BatteryController batteryController) {
super(host);
@@ -84,9 +83,7 @@
protected void handleUpdateState(BooleanState state, Object arg) {
state.state = mPluggedIn ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- BatterySaverIcon bsi = new BatterySaverIcon();
- bsi.mState = state.state;
- state.icon = bsi;
+ state.icon = mIcon;
state.label = mContext.getString(R.string.battery_detail_switch_title);
state.contentDescription = state.label;
state.value = mPowerSave;
@@ -106,48 +103,4 @@
mPowerSave = isPowerSave;
refreshState(null);
}
-
- public static class BatterySaverIcon extends Icon {
- private int mState;
-
- @Override
- public Drawable getDrawable(Context context) {
- BatterySaverDrawable b =
- new BatterySaverDrawable(context, QSTileImpl.getColorForState(context, mState));
- b.mState = mState;
- final int pad = context.getResources()
- .getDimensionPixelSize(R.dimen.qs_tile_divider_height);
- b.setPadding(pad, pad, pad, pad);
- return b;
- }
- }
-
- private static class BatterySaverDrawable extends BatteryMeterDrawableBase {
- private int mState;
- private static final int MAX_BATTERY = 100;
-
- BatterySaverDrawable(Context context, int frameColor) {
- super(context, frameColor);
- // Show as full so it's always uniform color
- super.setBatteryLevel(MAX_BATTERY);
- setPowerSave(true);
- setCharging(false);
- setPowerSaveAsColorError(false);
- mPowerSaveAsColorError = true;
- mFramePaint.setColor(0);
- mPowersavePaint.setColor(frameColor);
- mFramePaint.setStrokeWidth(mPowersavePaint.getStrokeWidth());
- mPlusPaint.setColor(frameColor);
- }
-
- @Override
- protected int batteryColorForLevel(int level) {
- return 0;
- }
-
- @Override
- public void setBatteryLevel(int val) {
- // Don't change the actual level, otherwise this won't draw correctly
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index e1becdb..c587a39 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -25,7 +25,11 @@
import android.content.res.Resources;
import android.provider.Settings;
import android.service.quicksettings.Tile;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -188,7 +192,8 @@
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
} else if (mobileDataEnabled) {
state.state = Tile.STATE_ACTIVE;
- state.secondaryLabel = getMobileDataSubscriptionName(cb);
+ state.secondaryLabel = appendMobileDataType(getMobileDataSubscriptionName(cb),
+ cb.dataContentDescription);
} else {
state.state = Tile.STATE_INACTIVE;
state.secondaryLabel = r.getString(R.string.cell_data_off);
@@ -207,6 +212,18 @@
state.contentDescription = state.label + ", " + contentDescriptionSuffix;
}
+ private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) {
+ if (TextUtils.isEmpty(dataType)) {
+ return current;
+ }
+ SpannableString type = new SpannableString(dataType);
+ SpannableStringBuilder builder = new SpannableStringBuilder(current);
+ builder.append(" ");
+ builder.append(type, new TextAppearanceSpan(mContext, R.style.TextAppearance_RATBadge),
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return builder;
+ }
+
private CharSequence getMobileDataSubscriptionName(CallbackInfo cb) {
if (cb.roaming && !TextUtils.isEmpty(cb.dataSubscriptionName)) {
String roaming = mContext.getString(R.string.data_connection_roaming);
@@ -232,6 +249,7 @@
private static final class CallbackInfo {
boolean airplaneModeEnabled;
CharSequence dataSubscriptionName;
+ CharSequence dataContentDescription;
boolean activityIn;
boolean activityOut;
boolean noSim;
@@ -250,6 +268,7 @@
return;
}
mInfo.dataSubscriptionName = mController.getMobileDataNetworkName();
+ mInfo.dataContentDescription = (description != null) ? typeContentDescription : null;
mInfo.activityIn = activityIn;
mInfo.activityOut = activityOut;
mInfo.roaming = roaming;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index c9be2c8..007c50c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -25,6 +25,8 @@
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.SecureSetting;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DataSaverController.Listener;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -42,6 +44,7 @@
public static final String INVERSION = "inversion";
public static final String WORK = "work";
public static final String NIGHT = "night";
+ public static final String CAST = "cast";
private final Context mContext;
private final QSTileHost mHost;
@@ -51,6 +54,7 @@
private final DataSaverController mDataSaverController;
private final ManagedProfileController mManagedProfileController;
private final NightDisplayListener mNightDisplayListener;
+ private final CastController mCastController;
@Inject
public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
@@ -58,7 +62,8 @@
HotspotController hotspotController,
DataSaverController dataSaverController,
ManagedProfileController managedProfileController,
- NightDisplayListener nightDisplayListener) {
+ NightDisplayListener nightDisplayListener,
+ CastController castController) {
mAutoTracker = autoAddTracker;
mContext = context;
mHost = host;
@@ -67,6 +72,7 @@
mDataSaverController = dataSaverController;
mManagedProfileController = managedProfileController;
mNightDisplayListener = nightDisplayListener;
+ mCastController = castController;
if (!mAutoTracker.isAdded(HOTSPOT)) {
hotspotController.addCallback(mHotspotCallback);
}
@@ -95,6 +101,9 @@
&& ColorDisplayManager.isNightDisplayAvailable(mContext)) {
nightDisplayListener.setCallback(mNightDisplayCallback);
}
+ if (!mAutoTracker.isAdded(CAST)) {
+ castController.addCallback(mCastCallback);
+ }
}
public void destroy() {
@@ -108,6 +117,7 @@
if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
mNightDisplayListener.setCallback(null);
}
+ mCastController.removeCallback(mCastCallback);
}
public void unmarkTileAsAutoAdded(String tabSpec) {
@@ -181,4 +191,27 @@
mHandler.post(() -> mNightDisplayListener.setCallback(null));
}
};
+
+ @VisibleForTesting
+ final CastController.Callback mCastCallback = new CastController.Callback() {
+ @Override
+ public void onCastDevicesChanged() {
+ if (mAutoTracker.isAdded(CAST)) return;
+
+ boolean isCasting = false;
+ for (CastDevice device : mCastController.getCastDevices()) {
+ if (device.state == CastDevice.STATE_CONNECTED
+ || device.state == CastDevice.STATE_CONNECTING) {
+ isCasting = true;
+ break;
+ }
+ }
+
+ if (isCasting) {
+ mHost.addTile(CAST);
+ mAutoTracker.setTileAdded(CAST);
+ mHandler.post(() -> mCastController.removeCallback(mCastCallback));
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 1049773..a17e042 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -26,7 +27,6 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index d3ff63a..50c4fac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -29,6 +29,7 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.media.AudioManager;
import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
@@ -56,7 +57,6 @@
import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.view.FloatingActionMode;
import com.android.internal.widget.FloatingToolbar;
import com.android.systemui.Dependency;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
index b22150b..8b81585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -57,13 +57,17 @@
private final int mDefaultMinNumSystemGeneratedReplies;
private final int mDefaultMaxNumActions;
- private boolean mEnabled;
- private boolean mRequiresTargetingP;
- private int mMaxSqueezeRemeasureAttempts;
- private boolean mEditChoicesBeforeSending;
- private boolean mShowInHeadsUp;
- private int mMinNumSystemGeneratedReplies;
- private int mMaxNumActions;
+ // These fields are updated on the UI thread but can be accessed on both the UI thread and
+ // background threads. We use the volatile keyword here instead of synchronization blocks since
+ // we only care about variable updates here being visible to other threads (and not for example
+ // whether the variables we are reading were updated in the same go).
+ private volatile boolean mEnabled;
+ private volatile boolean mRequiresTargetingP;
+ private volatile int mMaxSqueezeRemeasureAttempts;
+ private volatile boolean mEditChoicesBeforeSending;
+ private volatile boolean mShowInHeadsUp;
+ private volatile int mMinNumSystemGeneratedReplies;
+ private volatile int mMaxNumActions;
private final Context mContext;
private final KeyValueListParser mParser = new KeyValueListParser(',');
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index ecf1784..0070dcf 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -19,6 +19,7 @@
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
@@ -29,7 +30,6 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceFragment;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.R;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
index 45342d4..6807c22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationTest.java
@@ -18,12 +18,12 @@
import static junit.framework.TestCase.assertEquals;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index e4558df..9438cbb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -16,12 +16,13 @@
package com.android.systemui.doze;
+import android.hardware.display.AmbientDisplayConfiguration;
+
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.statusbar.phone.DozeParameters;
import org.mockito.Answers;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 0fc0953..23ff3d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -35,7 +36,6 @@
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 5a6200f..f972508 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -38,11 +38,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.UiThreadTest;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.wakelock.WakeLockFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 066dff2..463a6e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -31,12 +31,12 @@
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.SensorManagerPlugin;
import com.android.systemui.statusbar.phone.DozeParameters;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index cdac7c97..ca37347 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -27,6 +27,7 @@
import android.app.AlarmManager;
import android.app.Instrumentation;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Handler;
import android.os.Looper;
import android.support.test.InstrumentationRegistry;
@@ -34,7 +35,6 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerFake;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index f3740c4..87699b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -31,6 +32,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.qs.AutoAddTracker;
import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.HotspotController;
@@ -40,6 +43,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Collections;
+import java.util.Set;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -47,6 +53,7 @@
@Mock private QSTileHost mQsTileHost;
@Mock private AutoAddTracker mAutoAddTracker;
+ @Mock private CastController mCastController;
private AutoTileManager mAutoTileManager;
@@ -58,7 +65,8 @@
mock(HotspotController.class),
mock(DataSaverController.class),
mock(ManagedProfileController.class),
- mock(NightDisplayListener.class));
+ mock(NightDisplayListener.class),
+ mCastController);
}
@Test
@@ -108,4 +116,24 @@
ColorDisplayManager.AUTO_MODE_DISABLED);
verify(mQsTileHost, never()).addTile("night");
}
+
+ private static Set<CastDevice> buildFakeCastDevice(boolean isCasting) {
+ CastDevice cd = new CastDevice();
+ cd.state = isCasting ? CastDevice.STATE_CONNECTED : CastDevice.STATE_DISCONNECTED;
+ return Collections.singleton(cd);
+ }
+
+ @Test
+ public void castTileAdded_whenDeviceIsCasting() {
+ doReturn(buildFakeCastDevice(true)).when(mCastController).getCastDevices();
+ mAutoTileManager.mCastCallback.onCastDevicesChanged();
+ verify(mQsTileHost).addTile("cast");
+ }
+
+ @Test
+ public void castTileNotAdded_whenDeviceIsNotCasting() {
+ doReturn(buildFakeCastDevice(false)).when(mCastController).getCastDevices();
+ mAutoTileManager.mCastCallback.onCastDevicesChanged();
+ verify(mQsTileHost, never()).addTile("cast");
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index d025d73..de41152 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -402,7 +402,7 @@
private void updateActivityStartsLoggingEnabled() {
mFlagActivityStartsLoggingEnabled = Settings.Global.getInt(mResolver,
- Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 0) == 1;
+ Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED, 1) == 1;
}
private void updateBackgroundActivityStartsEnabled() {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ac20f6c..1e406c0 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2214,7 +2214,11 @@
void startUserWidgets(int userId) {
AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class);
if (awm != null) {
- awm.unlockUser(userId);
+ // Out of band, because this is called during a sequence with
+ // sensitive cross-service lock management
+ FgThread.getHandler().post(() -> {
+ awm.unlockUser(userId);
+ });
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9e92745..5d802a7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -88,6 +88,7 @@
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicyConfig;
+import android.media.audiopolicy.AudioProductStrategies;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
@@ -274,6 +275,9 @@
private SettingsObserver mSettingsObserver;
+ /** @see AudioProductStrategies */
+ private static AudioProductStrategies sAudioProductStrategies;
+
private int mMode = AudioSystem.MODE_NORMAL;
// protects mRingerMode
private final Object mSettingsLock = new Object();
@@ -624,6 +628,8 @@
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
+ sAudioProductStrategies = new AudioProductStrategies();
+
// Initialize volume
int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
if (maxCallVolume != -1) {
@@ -988,6 +994,14 @@
}
}
+ /**
+ * @return the {@link android.media.audiopolicy.AudioProductStrategies} discovered from the
+ * platform configuration file.
+ */
+ public @NonNull AudioProductStrategies getAudioProductStrategies() {
+ return sAudioProductStrategies;
+ }
+
private void checkAllAliasStreamVolumes() {
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4891947..77df10b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -65,7 +65,8 @@
new LongSparseArray<LocalDisplayDevice>();
@SuppressWarnings("unused") // Becomes active at instantiation time.
- private HotplugDisplayEventReceiver mHotplugReceiver;
+ private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver;
+
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
@@ -77,7 +78,7 @@
public void registerLocked() {
super.registerLocked();
- mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
+ mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper());
for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
tryConnectDisplayLocked(physicalDisplayId);
@@ -727,8 +728,8 @@
}
}
- private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
- public HotplugDisplayEventReceiver(Looper looper) {
+ private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver {
+ PhysicalDisplayEventReceiver(Looper looper) {
super(looper, VSYNC_SOURCE_APP);
}
@@ -742,5 +743,15 @@
}
}
}
+
+ @Override
+ public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) {
+ if (DEBUG) {
+ Slog.d(TAG, "onConfigChanged("
+ + "timestampNanos=" + timestampNanos
+ + ", builtInDisplayId=" + physicalDisplayId
+ + ", configId=" + configId + ")");
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index bffa8f4..3052e3c 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.input.InputManagerInternal;
import android.os.Binder;
import android.os.Build;
@@ -46,7 +47,6 @@
import android.util.Slog;
import android.view.Display;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index afe3473..00e1ffa 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -34,13 +34,11 @@
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-import com.android.internal.os.TransferPipe;
import com.android.server.FgThread;
import com.android.server.LocationManagerService;
import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -189,14 +187,6 @@
pw.println(" additional packages=" + mProviderPackages);
}
}
- mServiceWatcher.runOnBinderBlocking(binder -> {
- try {
- TransferPipe.dumpAsync(binder, fd, args);
- } catch (IOException | RemoteException e) {
- pw.println(" <failed to dump location provider: " + e + ">");
- }
- return null;
- }, null);
}
@Override
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d83eb08..ee968c8 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -123,7 +123,6 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
@@ -277,7 +276,7 @@
* @param managedUserPassword Managed profile original password (when it has separated lock).
* NULL when it does not have a separated lock before.
*/
- public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
+ public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
// Only for managed profile
if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
@@ -312,7 +311,12 @@
byte[] randomLockSeed = new byte[] {};
try {
randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
- String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
+ char[] newPasswordChars = HexEncoding.encode(randomLockSeed);
+ byte[] newPassword = new byte[newPasswordChars.length];
+ for (int i = 0; i < newPasswordChars.length; i++) {
+ newPassword[i] = (byte) newPasswordChars[i];
+ }
+ Arrays.fill(newPasswordChars, '\u0000');
final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
managedUserPassword, quality, managedUserId);
@@ -321,6 +325,7 @@
// password directly, so we always store a password.
setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId);
tieProfileLockToParent(managedUserId, newPassword);
+ Arrays.fill(newPassword, (byte) 0);
} catch (NoSuchAlgorithmException | RemoteException e) {
Slog.e(TAG, "Fail to tie managed profile", e);
// Nothing client can do to fix this issue, so we do not throw exception out
@@ -618,7 +623,7 @@
try {
final long handle = getSyntheticPasswordHandleLocked(userId);
- final String noCredential = null;
+ final byte[] noCredential = null;
AuthenticationResult result =
mSpManager.unwrapPasswordBasedSyntheticPassword(
getGateKeeperService(), handle, noCredential, userId, null);
@@ -956,7 +961,7 @@
@Override
public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
- String managedUserPassword) {
+ byte[] managedUserPassword) {
checkWritePermission(userId);
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
@@ -969,8 +974,8 @@
}
@GuardedBy("mSeparateChallengeLock")
- private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled,
- String managedUserPassword) {
+ private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId,
+ boolean enabled, byte[] managedUserPassword) {
final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
try {
@@ -1113,24 +1118,28 @@
return mStorage.hasCredential(userId);
}
- private void setKeystorePassword(String password, int userHandle) {
+ private void setKeystorePassword(byte[] password, int userHandle) {
final KeyStore ks = KeyStore.getInstance();
- ks.onUserPasswordChanged(userHandle, password);
+ // TODO(b/120484642): Update keystore to accept byte[] passwords
+ String passwordString = password == null ? null : new String(password);
+ ks.onUserPasswordChanged(userHandle, passwordString);
}
- private void unlockKeystore(String password, int userHandle) {
+ private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
+ // TODO(b/120484642): Update keystore to accept byte[] passwords
+ String passwordString = password == null ? null : new String(password);
final KeyStore ks = KeyStore.getInstance();
- ks.unlock(userHandle, password);
+ ks.unlock(userHandle, passwordString);
}
@VisibleForTesting
- protected String getDecryptedPasswordForTiedProfile(int userId)
+ protected byte[] getDecryptedPasswordForTiedProfile(int userId)
throws KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
CertificateException, IOException {
- if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
+ if (DEBUG) Slog.v(TAG, "Get child profile decrypted key");
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
throw new FileNotFoundException("Child profile lock file not found");
@@ -1149,7 +1158,7 @@
cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
decryptionResult = cipher.doFinal(encryptedPassword);
- return new String(decryptionResult, StandardCharsets.UTF_8);
+ return decryptionResult;
}
private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
@@ -1226,11 +1235,11 @@
&& mUserManager.isUserRunning(userInfo.id);
}
- private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
+ private Map<Integer, byte[]> getDecryptedPasswordsForAllTiedProfiles(int userId) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return null;
}
- Map<Integer, String> result = new ArrayMap<Integer, String>();
+ Map<Integer, byte[]> result = new ArrayMap<Integer, byte[]>();
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
final int size = profiles.size();
for (int i = 0; i < size; i++) {
@@ -1268,7 +1277,7 @@
* terminates when the user is a managed profile.
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
- Map<Integer, String> profilePasswordMap) throws RemoteException {
+ Map<Integer, byte[]> profilePasswordMap) throws RemoteException {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return;
}
@@ -1317,9 +1326,10 @@
// This method should be called by LockPatternUtil only, all internal methods in this class
// should call setLockCredentialInternal.
@Override
- public void setLockCredential(String credential, int type, String savedCredential,
- int requestedQuality, int userId)
+ public void setLockCredential(byte[] credential, int type,
+ byte[] savedCredential, int requestedQuality, int userId)
throws RemoteException {
+
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature");
@@ -1333,14 +1343,14 @@
notifySeparateProfileChallengeChanged(userId);
}
- private void setLockCredentialInternal(String credential, int credentialType,
- String savedCredential, int requestedQuality, int userId) throws RemoteException {
+ private void setLockCredentialInternal(byte[] credential, int credentialType,
+ byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
// Normalize savedCredential and credential such that empty string is always represented
// as null.
- if (TextUtils.isEmpty(savedCredential)) {
+ if (savedCredential == null || savedCredential.length == 0) {
savedCredential = null;
}
- if (TextUtils.isEmpty(credential)) {
+ if (credential == null || credential.length == 0) {
credential = null;
}
synchronized (mSpManager) {
@@ -1409,7 +1419,7 @@
mStorage.writeCredentialHash(willStore, userId);
// push new secret and auth token to vold
GateKeeperResponse gkResponse = getGateKeeperService()
- .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
+ .verifyChallenge(userId, 0, willStore.hash, credential);
setUserKeyProtection(userId, credential, convertResponse(gkResponse));
fixateNewestUserKeyAuth(userId);
// Refresh the auth token
@@ -1429,9 +1439,8 @@
}
@VisibleForTesting
- protected void tieProfileLockToParent(int userId, String password) {
+ protected void tieProfileLockToParent(int userId, byte[] password) {
if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
- byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
byte[] encryptionResult;
byte[] iv;
try {
@@ -1465,7 +1474,7 @@
KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
+ KeyProperties.ENCRYPTION_PADDING_NONE);
cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
- encryptionResult = cipher.doFinal(randomLockSeed);
+ encryptionResult = cipher.doFinal(password);
iv = cipher.getIV();
} finally {
// The original key can now be discarded.
@@ -1490,17 +1499,11 @@
}
private byte[] enrollCredential(byte[] enrolledHandle,
- String enrolledCredential, String toEnroll, int userId)
+ byte[] enrolledCredential, byte[] toEnroll, int userId)
throws RemoteException {
checkWritePermission(userId);
- byte[] enrolledCredentialBytes = enrolledCredential == null
- ? null
- : enrolledCredential.getBytes();
- byte[] toEnrollBytes = toEnroll == null
- ? null
- : toEnroll.getBytes();
GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
- enrolledCredentialBytes, toEnrollBytes);
+ enrolledCredential, toEnroll);
if (response == null) {
return null;
@@ -1521,7 +1524,7 @@
addUserKeyAuth(userId, null, key);
}
- private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
+ private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr)
throws RemoteException {
if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
if (vcr == null) {
@@ -1543,16 +1546,15 @@
addUserKeyAuth(userId, null, null);
}
- private static byte[] secretFromCredential(String credential) throws RemoteException {
+ private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-512");
// Personalize the hash
- byte[] personalization = "Android FBE credential hash"
- .getBytes(StandardCharsets.UTF_8);
+ byte[] personalization = "Android FBE credential hash".getBytes();
// Pad it to the block size of the hash function
personalization = Arrays.copyOf(personalization, 128);
digest.update(personalization);
- digest.update(credential.getBytes(StandardCharsets.UTF_8));
+ digest.update(credential);
return digest.digest();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
@@ -1588,7 +1590,7 @@
checkWritePermission(userId);
if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
int managedUserId = -1;
- String managedUserDecryptedPassword = null;
+ byte[] managedUserDecryptedPassword = null;
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock managed profile with unified lock
@@ -1625,17 +1627,20 @@
tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
}
}
+ if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) {
+ Arrays.fill(managedUserDecryptedPassword, (byte) 0);
+ }
}
@Override
- public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
+ public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
}
@Override
- public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
+ public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge,
int userId) throws RemoteException {
checkPasswordReadPermission(userId);
return doVerifyCredential(credential, type, true, challenge, userId,
@@ -1646,10 +1651,10 @@
* Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
* format.
*/
- private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
+ private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType,
boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
- if (TextUtils.isEmpty(credential)) {
+ if (credential == null || credential.length == 0) {
throw new IllegalArgumentException("Credential can't be null or empty");
}
if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
@@ -1684,9 +1689,9 @@
boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
&& storedHash.isBaseZeroPattern;
- String credentialToVerify;
+ byte[] credentialToVerify;
if (shouldReEnrollBaseZero) {
- credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
+ credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential);
} else {
credentialToVerify = credential;
}
@@ -1706,7 +1711,7 @@
}
@Override
- public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
+ public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type,
long challenge, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
if (!isManagedProfileWithUnifiedLock(userId)) {
@@ -1748,14 +1753,15 @@
* hash to GK.
*/
private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
- String credential, boolean hasChallenge, long challenge,
+ byte[] credential, boolean hasChallenge, long challenge,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
- if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
+ if ((storedHash == null || storedHash.hash.length == 0)
+ && (credential == null || credential.length == 0)) {
// don't need to pass empty credentials to GateKeeper
return VerifyCredentialResponse.OK;
}
- if (storedHash == null || TextUtils.isEmpty(credential)) {
+ if (storedHash == null || credential == null || credential.length == 0) {
return VerifyCredentialResponse.ERROR;
}
@@ -1766,14 +1772,14 @@
if (storedHash.version == CredentialHash.VERSION_LEGACY) {
final byte[] hash;
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
- hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
+ hash = LockPatternUtils.patternToHash(
+ LockPatternUtils.byteArrayToPattern(credential));
} else {
- hash = mLockPatternUtils.legacyPasswordToHash(credential, userId)
- .getBytes(StandardCharsets.UTF_8);
+ hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes();
}
if (Arrays.equals(hash, storedHash.hash)) {
if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
- unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
+ unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId);
} else {
unlockKeystore(credential, userId);
}
@@ -1804,7 +1810,7 @@
}
}
GateKeeperResponse gateKeeperResponse = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
+ .verifyChallenge(userId, challenge, storedHash.hash, credential);
VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
@@ -1863,7 +1869,7 @@
* Call this method to notify DPMS regarding the latest password metric. This should be called
* when the user is authenticating or when a new password is being set.
*/
- private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
+ private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) {
final PasswordMetrics metrics;
if (password == null) {
metrics = new PasswordMetrics();
@@ -1912,6 +1918,7 @@
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
final IStorageManager service = mInjector.getStorageManager();
+ // TODO(b/120484642): Update vold to return a password as a byte array
String password;
long identity = Binder.clearCallingIdentity();
try {
@@ -1926,8 +1933,8 @@
try {
if (mLockPatternUtils.isLockPatternEnabled(userId)) {
- if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
- null /* progressCallback */)
+ if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ userId, null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
return true;
}
@@ -1937,8 +1944,8 @@
try {
if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
- if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
- null /* progressCallback */)
+ if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ userId, null /* progressCallback */)
.getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
return true;
}
@@ -2323,7 +2330,7 @@
@GuardedBy("mSpManager")
@VisibleForTesting
protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
- String credential, int credentialType, int requestedQuality,
+ byte[] credential, int credentialType, int requestedQuality,
int userId) throws RemoteException {
Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
@@ -2384,7 +2391,7 @@
setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
}
- private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int
+ private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int
credentialType, boolean hasChallenge, long challenge, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId);
@@ -2483,12 +2490,12 @@
* added back when new password is set in future.
*/
@GuardedBy("mSpManager")
- private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
+ private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType,
AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
credential, credentialType, auth, requestedQuality, userId);
- final Map<Integer, String> profilePasswords;
+ final Map<Integer, byte[]> profilePasswords;
if (credential != null) {
// // not needed by synchronizeUnifiedWorkChallengeForProfiles()
profilePasswords = null;
@@ -2527,12 +2534,19 @@
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
notifyActivePasswordMetricsAvailable(credential, userId);
+
+ if (profilePasswords != null) {
+ for (Map.Entry<Integer, byte[]> entry : profilePasswords.entrySet()) {
+ Arrays.fill(entry.getValue(), (byte) 0);
+ }
+ }
+
return newHandle;
}
@GuardedBy("mSpManager")
- private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
- String savedCredential, int requestedQuality, int userId) throws RemoteException {
+ private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
+ byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
if (isManagedProfileWithUnifiedLock(userId)) {
// get credential from keystore when managed profile has unified lock
@@ -2605,9 +2619,9 @@
* If user is a managed profile with unified challenge, currentCredential is ignored.
*/
@Override
- public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
+ public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
- if (TextUtils.isEmpty(currentCredential)) {
+ if (currentCredential == null || currentCredential.length == 0) {
currentCredential = null;
}
if (isManagedProfileWithUnifiedLock(userId)) {
@@ -2701,7 +2715,7 @@
}
}
- private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
+ private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle,
byte[] token, int requestedQuality, int userId) throws RemoteException {
boolean result;
synchronized (mSpManager) {
@@ -2721,7 +2735,7 @@
return result;
}
- private boolean setLockCredentialWithTokenInternal(String credential, int type,
+ private boolean setLockCredentialWithTokenInternal(byte[] credential, int type,
long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException {
final AuthenticationResult result;
synchronized (mSpManager) {
@@ -2948,8 +2962,8 @@
}
@Override
- public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
- byte[] token, int requestedQuality, int userId) {
+ public boolean setLockCredentialWithToken(byte[] credential, int type,
+ long tokenHandle, byte[] token, int requestedQuality, int userId) {
if (!mLockPatternUtils.hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires secure lock screen feature.");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 6163077..ee22264 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -190,22 +190,30 @@
}
private void runSetPattern() {
- mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId);
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId);
getOutPrintWriter().println("Pattern set to '" + mNew + "'");
}
private void runSetPassword() {
- mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId);
+ byte[] newBytes = mNew != null ? mNew.getBytes() : null;
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC,
+ mCurrentUserId);
getOutPrintWriter().println("Password set to '" + mNew + "'");
}
private void runSetPin() {
- mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId);
+ byte[] newBytes = mNew != null ? mNew.getBytes() : null;
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC,
+ mCurrentUserId);
getOutPrintWriter().println("Pin set to '" + mNew + "'");
}
private void runClear() {
- mLockPatternUtils.clearLock(mOld, mCurrentUserId);
+ byte[] oldBytes = mOld != null ? mOld.getBytes() : null;
+ mLockPatternUtils.clearLock(oldBytes, mCurrentUserId);
getOutPrintWriter().println("Lock credential cleared");
}
@@ -232,7 +240,8 @@
try {
final boolean result;
if (havePassword) {
- result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId);
+ byte[] passwordBytes = mOld != null ? mOld.getBytes() : null;
+ result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId);
} else {
result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId);
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 0e195bc..ea39dff 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -97,7 +97,7 @@
private static final String WEAVER_SLOT_NAME = "weaver";
public static final long DEFAULT_HANDLE = 0L;
- private static final String DEFAULT_PASSWORD = "default-password";
+ private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes();
private static final byte WEAVER_VERSION = 1;
private static final int INVALID_WEAVER_SLOT = -1;
@@ -165,7 +165,7 @@
}
}
- public String deriveKeyStorePassword() {
+ public byte[] deriveKeyStorePassword() {
return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD));
}
@@ -454,11 +454,11 @@
*
*/
public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper,
- byte[] hash, String credential, int userId) throws RemoteException {
+ byte[] hash, byte[] credential, int userId) throws RemoteException {
AuthenticationToken result = AuthenticationToken.create();
GateKeeperResponse response;
if (hash != null) {
- response = gatekeeper.enroll(userId, hash, credential.getBytes(),
+ response = gatekeeper.enroll(userId, hash, credential,
result.deriveGkPassword());
if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId);
@@ -616,7 +616,7 @@
* @see #clearSidForUser
*/
public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- String credential, int credentialType, AuthenticationToken authToken,
+ byte[] credential, int credentialType, AuthenticationToken authToken,
int requestedQuality, int userId)
throws RemoteException {
if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
@@ -670,7 +670,7 @@
}
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
- String userCredential, int credentialType,
+ byte[] userCredential, int credentialType,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
PersistentData persistentData = mStorage.readPersistentDataBlock();
if (persistentData.type == PersistentData.TYPE_SP) {
@@ -839,7 +839,7 @@
* unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType
*/
public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper,
- long handle, String credential, int userId,
+ long handle, byte[] credential, int userId,
ICheckCredentialProgressCallback progressCallback) throws RemoteException {
if (credential == null) {
credential = DEFAULT_PASSWORD;
@@ -1152,7 +1152,7 @@
return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle);
}
- private byte[] computePasswordToken(String password, PasswordData data) {
+ private byte[] computePasswordToken(byte[] password, PasswordData data) {
return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP,
PASSWORD_TOKEN_LENGTH);
}
@@ -1173,8 +1173,8 @@
return nativeSidFromPasswordHandle(handle);
}
- protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
- return new Scrypt().scrypt(password.getBytes(), salt, N, r, p, outLen);
+ protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
+ return new Scrypt().scrypt(password, salt, n, r, p, outLen);
}
native long nativeSidFromPasswordHandle(byte[] handle);
@@ -1195,17 +1195,17 @@
return result;
}
- final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
- public static String bytesToHex(byte[] bytes) {
+ protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes();
+ private static byte[] bytesToHex(byte[] bytes) {
if (bytes == null) {
- return "null";
+ return "null".getBytes();
}
- char[] hexChars = new char[bytes.length * 2];
+ byte[] hexBytes = new byte[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
- hexChars[j * 2] = hexArray[v >>> 4];
- hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ hexBytes[j * 2] = HEX_ARRAY[v >>> 4];
+ hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
- return new String(hexChars);
+ return hexBytes;
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index e7a71b9..5676da2 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -38,7 +38,6 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -51,6 +50,7 @@
import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -85,7 +85,7 @@
private final RecoverableKeyStoreDb mRecoverableKeyStoreDb;
private final int mUserId;
private final int mCredentialType;
- private final String mCredential;
+ private final byte[] mCredential;
private final boolean mCredentialUpdated;
private final PlatformKeyManager mPlatformKeyManager;
private final RecoverySnapshotStorage mRecoverySnapshotStorage;
@@ -100,7 +100,7 @@
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
int userId,
int credentialType,
- String credential,
+ byte[] credential,
boolean credentialUpdated
) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException {
return new KeySyncTask(
@@ -134,7 +134,7 @@
RecoverySnapshotListenersStorage recoverySnapshotListenersStorage,
int userId,
int credentialType,
- String credential,
+ byte[] credential,
boolean credentialUpdated,
PlatformKeyManager platformKeyManager,
TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
@@ -450,7 +450,7 @@
*/
@VisibleForTesting
@KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat(
- int credentialType, String credential) {
+ int credentialType, byte[] credential) {
if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
return KeyChainProtectionParams.UI_FORMAT_PATTERN;
} else if (isPin(credential)) {
@@ -475,13 +475,13 @@
* Returns {@code true} if {@code credential} looks like a pin.
*/
@VisibleForTesting
- static boolean isPin(@Nullable String credential) {
+ static boolean isPin(@Nullable byte[] credential) {
if (credential == null) {
return false;
}
- int length = credential.length();
+ int length = credential.length;
for (int i = 0; i < length; i++) {
- if (!Character.isDigit(credential.charAt(i))) {
+ if (!Character.isDigit((char) credential[i])) {
return false;
}
}
@@ -494,8 +494,7 @@
* @return The SHA-256 hash.
*/
@VisibleForTesting
- static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) {
- byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8);
+ static byte[] hashCredentialsBySaltedSha256(byte[] salt, byte[] credentialsBytes) {
ByteBuffer byteBuffer = ByteBuffer.allocate(
salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -506,17 +505,19 @@
byte[] bytes = byteBuffer.array();
try {
- return MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
+ byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes);
+ Arrays.fill(bytes, (byte) 0);
+ return hash;
} catch (NoSuchAlgorithmException e) {
// Impossible, SHA-256 must be supported on Android.
throw new RuntimeException(e);
}
}
- private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) {
+ private byte[] hashCredentialsByScrypt(byte[] salt, byte[] credentials) {
return mScrypt.scrypt(
- credentials.getBytes(StandardCharsets.UTF_8), salt,
- SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES);
+ credentials, salt, SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P,
+ SCRYPT_PARAM_OUTLEN_BYTES);
}
private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index ed864c0..47b9c27 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -892,13 +892,13 @@
* This function can only be used inside LockSettingsService.
*
* @param storedHashType from {@code CredentialHash}
- * @param credential - unencrypted String. Password length should be at most 16 symbols {@code
- * mPasswordMaxLength}
+ * @param credential - unencrypted byte array. Password length should be at most 16 symbols
+ * {@code mPasswordMaxLength}
* @param userId for user who just unlocked the device.
* @hide
*/
public void lockScreenSecretAvailable(
- int storedHashType, @NonNull String credential, int userId) {
+ int storedHashType, @NonNull byte[] credential, int userId) {
// So as not to block the critical path unlocking the phone, defer to another thread.
try {
mExecutorService.execute(KeySyncTask.newInstance(
@@ -923,13 +923,13 @@
* This function can only be used inside LockSettingsService.
*
* @param storedHashType from {@code CredentialHash}
- * @param credential - unencrypted String
+ * @param credential - unencrypted byte array
* @param userId for the user whose lock screen credentials were changed.
* @hide
*/
public void lockScreenSecretChanged(
int storedHashType,
- @Nullable String credential,
+ @Nullable byte[] credential,
int userId) {
// So as not to block the critical path unlocking the phone, defer to another thread.
try {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
index 057429c..90a36723 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java
@@ -87,10 +87,30 @@
|| isTestOnlyCertificateAlias(rootCertificateAlias);
}
- public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) {
- return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD)
- && (credential != null)
- && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX);
+ /**
+ * Checks whether a password is in "Insecure mode"
+ * @param credentialType the type of credential, e.g. pattern and password
+ * @param credential the pattern or password
+ * @return true, if the credential is in "Insecure mode"
+ */
+ public boolean doesCredentialSupportInsecureMode(int credentialType, byte[] credential) {
+ if (credential == null) {
+ return false;
+ }
+ if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) {
+ return false;
+ }
+ byte[] insecurePasswordPrefixBytes =
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes();
+ if (credential.length < insecurePasswordPrefixBytes.length) {
+ return false;
+ }
+ for (int i = 0; i < insecurePasswordPrefixBytes.length; i++) {
+ if (credential[i] != insecurePasswordPrefixBytes[i]) {
+ return false;
+ }
+ }
+ return true;
}
public Map<String, Pair<SecretKey, byte[]>> keepOnlyWhitelistedInsecureKeys(
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index b52c021..1c9028d 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -333,7 +333,7 @@
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
- optimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
+ optimizer.performDexOpt(pkg,
null /* ISAs */,
null /* CompilerStats.PackageStats */,
mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5b38208..580137d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -125,7 +125,7 @@
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
* synchronized on {@link #mInstallLock}.
*/
- int performDexOpt(PackageParser.Package pkg, List<SharedLibraryInfo> sharedLibraries,
+ int performDexOpt(PackageParser.Package pkg,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
if (pkg.applicationInfo.uid == -1) {
@@ -138,7 +138,7 @@
synchronized (mInstallLock) {
final long acquireTime = acquireWakeLockLI(pkg.applicationInfo.uid);
try {
- return performDexOptLI(pkg, sharedLibraries, instructionSets,
+ return performDexOptLI(pkg, instructionSets,
packageStats, packageUseInfo, options);
} finally {
releaseWakeLockLI(acquireTime);
@@ -152,9 +152,9 @@
*/
@GuardedBy("mInstallLock")
private int performDexOptLI(PackageParser.Package pkg,
- List<SharedLibraryInfo> sharedLibraries,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
+ final List<SharedLibraryInfo> sharedLibraries = pkg.usesLibraryInfos;
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index eeb4812..b72e836 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -204,7 +204,8 @@
mSessionsDir.mkdirs();
mApexManager = am;
- mStagingManager = new StagingManager(pm, this, am);
+
+ mStagingManager = new StagingManager(pm, this, am, context);
}
boolean okToSendBroadcasts() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 20829b5..80e794f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9413,12 +9413,12 @@
options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
for (PackageParser.Package depPackage : deps) {
// TODO: Analyze and investigate if we (should) profile libraries.
- pdo.performDexOpt(depPackage, null /* sharedLibraries */, instructionSets,
+ pdo.performDexOpt(depPackage, instructionSets,
getOrCreateCompilerPackageStats(depPackage),
mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
}
}
- return pdo.performDexOpt(p, p.usesLibraryInfos, instructionSets,
+ return pdo.performDexOpt(p, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
}
@@ -16324,7 +16324,7 @@
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
+ mPackageDexOptimizer.performDexOpt(pkg,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index cbf5e9e..fac3839 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -39,6 +39,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
@@ -68,15 +69,18 @@
private final PackageInstallerService mPi;
private final PackageManagerService mPm;
private final ApexManager mApexManager;
+ private final PowerManager mPowerManager;
private final Handler mBgHandler;
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
- StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am) {
+ StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am,
+ Context context) {
mPm = pm;
mPi = pi;
mApexManager = am;
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mBgHandler = BackgroundThread.getHandler();
}
@@ -286,6 +290,20 @@
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Staged installation of APKs failed. Check logcat messages for"
+ "more information.");
+
+ if (!hasApex) {
+ return;
+ }
+
+ if (!mApexManager.abortActiveSession()) {
+ Slog.e(TAG, "Failed to abort APEXd session");
+ } else {
+ Slog.e(TAG,
+ "Successfully aborted apexd session. Rebooting device in order to revert "
+ + "to the previous state of APEXd.");
+ mPowerManager.reboot(null);
+ }
+
return;
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 176dbbf..89d24b1 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -36,6 +36,7 @@
import android.database.ContentObserver;
import android.hardware.SensorManager;
import android.hardware.SystemSensorManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.hardware.power.V1_0.PowerHint;
@@ -81,7 +82,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.hardware.AmbientDisplayConfiguration;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.EventLogTags;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ab1b6ae..706901b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4373,7 +4373,11 @@
Slog.d(TAG, "relayoutVisibleWindow: " + this + " mAnimatingExit=true, mRemoveOnExit="
+ mRemoveOnExit + ", mDestroying=" + mDestroying);
- mWinAnimator.cancelExitAnimationForNextAnimationLocked();
+ // Cancel the existing exit animation for the next enter animation.
+ if (isSelfAnimating()) {
+ cancelAnimation();
+ destroySurfaceUnchecked();
+ }
mAnimatingExit = false;
}
if (mDestroying) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2e2da6d..969ced4 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -248,14 +248,6 @@
mWallpaperControllerLocked = win.getDisplayContent().mWallpaperController;
}
- void cancelExitAnimationForNextAnimationLocked() {
- if (DEBUG_ANIM) Slog.d(TAG,
- "cancelExitAnimationForNextAnimationLocked: " + mWin);
-
- mWin.cancelAnimation();
- mWin.destroySurfaceUnchecked();
- }
-
void onAnimationFinished() {
// Done animating, clean up.
if (DEBUG_ANIM) Slog.v(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3070488..f496e81 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5046,7 +5046,8 @@
if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
quality = PASSWORD_QUALITY_UNSPECIFIED;
}
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
+ // TODO(b/120484642): remove getBytes() below
+ final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes());
final int realQuality = metrics.quality;
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
@@ -5133,16 +5134,22 @@
try {
if (token == null) {
if (!TextUtils.isEmpty(password)) {
- mLockPatternUtils.saveLockPassword(password, null, quality, userHandle);
+ mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
+ userHandle);
} else {
mLockPatternUtils.clearLock(null, userHandle);
}
result = true;
} else {
- result = mLockPatternUtils.setLockCredentialWithToken(password,
- TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
- : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- quality, tokenHandle, token, userHandle);
+ if (!TextUtils.isEmpty(password)) {
+ result = mLockPatternUtils.setLockCredentialWithToken(password.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ quality, tokenHandle, token, userHandle);
+ } else {
+ result = mLockPatternUtils.setLockCredentialWithToken(null,
+ LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ quality, tokenHandle, token, userHandle);
+ }
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
diff --git a/services/tests/rescueparty/how_to_run.txt b/services/tests/rescueparty/how_to_run.txt
index 9528d39..a3a26d6 100644
--- a/services/tests/rescueparty/how_to_run.txt
+++ b/services/tests/rescueparty/how_to_run.txt
@@ -1,4 +1,3 @@
-# Per http://go/westworld-local-development#step3-test-atom-and-metric-locally-on-device ,
# In one terminal:
make statsd_testdrive
./out/host/linux-x86/bin/statsd_testdrive 122
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index de782a5..4293247 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4167,7 +4167,7 @@
assertTrue(dpm.isResetPasswordTokenActive(admin1));
// test reset password with token
- when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
+ when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password.getBytes()),
eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token),
eq(UserHandle.USER_SYSTEM)))
@@ -5214,7 +5214,7 @@
.thenReturn(DpmMockContext.CALLER_USER_HANDLE);
dpms.mUserPasswordMetrics.put(
DpmMockContext.CALLER_USER_HANDLE,
- PasswordMetrics.computeForPassword("asdf"));
+ PasswordMetrics.computeForPassword("asdf".getBytes()));
assertEquals(PASSWORD_COMPLEXITY_MEDIUM, dpm.getPasswordComplexity());
}
@@ -5231,10 +5231,10 @@
dpms.mUserPasswordMetrics.put(
DpmMockContext.CALLER_USER_HANDLE,
- PasswordMetrics.computeForPassword("asdf"));
+ PasswordMetrics.computeForPassword("asdf".getBytes()));
dpms.mUserPasswordMetrics.put(
parentUser.id,
- PasswordMetrics.computeForPassword("parentUser"));
+ PasswordMetrics.computeForPassword("parentUser".getBytes()));
assertEquals(PASSWORD_COMPLEXITY_HIGH, dpm.getPasswordComplexity());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
index d2caa0a..94d21dd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
@@ -18,24 +18,22 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.os.RemoteException;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
-import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
-
-import java.util.ArrayList;
import org.mockito.ArgumentCaptor;
+import java.util.ArrayList;
+
/**
* Run the synthetic password tests with caching enabled.
*
@@ -56,10 +54,10 @@
}
public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
@@ -67,45 +65,46 @@
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// Verify the password
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode());
}
public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException {
- final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password";
- final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword";
+ final byte[] password =
+ "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes();
+ final byte[] newPassword =
+ "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
// Untrusted change password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
// Verify the password
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
// Ensure the same secret was passed each time
ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class);
@@ -114,27 +113,29 @@
}
public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException {
- final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password";
- final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword";
+ final byte[] password =
+ "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes();
+ final byte[] newPassword =
+ "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes();
// Disable caching for this test
enableSpCaching(false);
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// Untrusted change password
assertExpectException(IllegalStateException.class, /* messageRegex= */ null,
- () -> mService.setLockCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
+ () -> mService.setLockCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// Verify the new password doesn't work but the old one still does
- assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index bf71318..f4632db 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -133,12 +133,12 @@
}
@Override
- protected void tieProfileLockToParent(int userId, String password) {
- mStorage.writeChildProfileLock(userId, password.getBytes());
+ protected void tieProfileLockToParent(int userId, byte[] password) {
+ mStorage.writeChildProfileLock(userId, password);
}
@Override
- protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
+ protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException,
KeyPermanentlyInvalidatedException {
byte[] storedData = mStorage.readChildProfileLock(userId);
if (storedData == null) {
@@ -151,7 +151,7 @@
} catch (RemoteException e) {
// shouldn't happen.
}
- return new String(storedData);
+ return storedData;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 5124803..6e0ba3c 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -84,8 +84,8 @@
initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
try {
- mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd",
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
+ "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("Did not fail when enrolling using incorrect credential");
} catch (RemoteException expected) {
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
@@ -96,7 +96,7 @@
public void testClearPasswordPrimaryUser() throws RemoteException {
final String PASSWORD = "password";
initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
- mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD,
+ mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertFalse(mService.havePassword(PRIMARY_USER_ID));
assertFalse(mService.havePattern(PRIMARY_USER_ID));
@@ -106,7 +106,8 @@
public void testManagedProfileUnifiedChallenge() throws RemoteException {
final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1";
final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
- mService.setLockCredential(firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.setLockCredential(firstUnifiedPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
@@ -125,8 +126,8 @@
mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID);
// verify credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ PRIMARY_USER_ID).getResponseCode());
// Verify that we have a new auth token for the profile
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
@@ -141,15 +142,16 @@
*/
mStorageManager.setIgnoreBadUnlock(true);
// Change primary password and verify that profile SID remains
- mService.setLockCredential(secondUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- firstUnifiedPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential(secondUnifiedPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
// Clear unified challenge
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- secondUnifiedPassword, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
@@ -158,14 +160,16 @@
public void testManagedProfileSeparateChallenge() throws RemoteException {
final String primaryPassword = "testManagedProfileSeparateChallenge-primary";
final String profilePassword = "testManagedProfileSeparateChallenge-profile";
- mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(primaryPassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
* credential as part of verifyCredential() before the new credential is committed in
* StorageManager. So we relax the check in our mock StorageManager to allow that.
*/
mStorageManager.setIgnoreBadUnlock(true);
- mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(profilePassword.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
@@ -179,31 +183,32 @@
mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID);
// verify primary credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ PRIMARY_USER_ID).getResponseCode());
assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
// verify profile credential
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
MANAGED_PROFILE_USER_ID).getResponseCode());
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
// Change primary credential and make sure we don't affect profile
mStorageManager.setIgnoreBadUnlock(true);
- mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- primaryPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+ mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mStorageManager.setIgnoreBadUnlock(false);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
MANAGED_PROFILE_USER_ID).getResponseCode());
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
}
private void testCreateCredential(int userId, String credential, int type, int quality)
throws RemoteException {
- mService.setLockCredential(credential, type, null, quality, userId);
+ mService.setLockCredential(credential.getBytes(), type, null, quality,
+ userId);
assertVerifyCredentials(userId, credential, type, -1);
}
@@ -212,7 +217,8 @@
mHasSecureLockScreen = false;
try {
- mService.setLockCredential(credential, type, null, quality, userId);
+ mService.setLockCredential(credential.getBytes(), type, null, quality,
+ userId);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
// Success - the exception was expected.
@@ -226,15 +232,16 @@
String oldCredential, int oldType, int quality) throws RemoteException {
final long sid = 1234;
initializeStorageWithCredential(userId, oldCredential, oldType, sid);
- mService.setLockCredential(newCredential, newType, oldCredential, quality, userId);
+ mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
+ quality, userId);
assertVerifyCredentials(userId, newCredential, newType, sid);
}
private void assertVerifyCredentials(int userId, String credential, int type, long sid)
throws RemoteException{
final long challenge = 54321;
- VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge,
- userId);
+ VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(),
+ type, challenge, userId);
assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode());
if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId));
@@ -253,18 +260,19 @@
incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
// check for bad type
- assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential,
- incorrectType, challenge, userId).getResponseCode());
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
+ credential.getBytes(), incorrectType, challenge, userId).getResponseCode());
// check for bad credential
- assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential,
- type, challenge, userId).getResponseCode());
+ assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(
+ ("0" + credential).getBytes(), type, challenge, userId).getResponseCode());
}
private void initializeStorageWithCredential(int userId, String credential, int type, long sid)
throws RemoteException {
+ byte[] credentialBytes = credential == null ? null : credential.getBytes();
byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes();
if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) {
- mService.initializeSyntheticPasswordLocked(oldHash, credential, type,
+ mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type,
type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC
: PASSWORD_QUALITY_SOMETHING, userId);
} else {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index 929c3b5..fcfc6d2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -85,23 +85,24 @@
public void testWrongPassword() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(false);
assertEquals(-1, mCommand.exec(mBinder, in, out, err,
new String[] { "set-pin", "--old", "1234" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt());
+ verify(mLockPatternUtils, never()).saveLockPassword(any(byte[].class), any(byte[].class),
+ anyInt(), anyInt());
}
@Test
public void testChangePin() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-pin", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC,
- mUserId);
+ verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
+ PASSWORD_QUALITY_NUMERIC, mUserId);
}
@Test
@@ -118,12 +119,12 @@
public void testChangePassword() throws Exception {
when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
- when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true);
+ when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true);
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-password", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC,
- mUserId);
+ verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(),
+ PASSWORD_QUALITY_ALPHABETIC, mUserId);
}
@Test
@@ -144,7 +145,8 @@
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "set-pattern", "--old", "1234", "4321" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId);
+ verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234".getBytes(),
+ mUserId);
}
@Test
@@ -165,6 +167,6 @@
assertEquals(0, mCommand.exec(new Binder(), in, out, err,
new String[] { "clear", "--old", "1234" },
mShellCallback, mResultReceiver));
- verify(mLockPatternUtils).clearLock("1234", mUserId);
+ verify(mLockPatternUtils).clearLock("1234".getBytes(), mUserId);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
index 6f68179..b9cb730 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java
@@ -93,9 +93,13 @@
}
@Override
- protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) {
+ protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
try {
- PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8);
+ char[] passwordChars = new char[password.length];
+ for (int i = 0; i < password.length; i++) {
+ passwordChars[i] = (char) password[i];
+ }
+ PBEKeySpec spec = new PBEKeySpec(passwordChars, salt, 10, outLen * 8);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return f.generateSecret(spec).getEncoded();
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 89e155e..e6e020d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -65,22 +65,23 @@
public void testPasswordBasedSyntheticPassword() throws RemoteException {
final int USER_ID = 10;
- final String PASSWORD = "user-password";
- final String BADPASSWORD = "bad-password";
+ final byte[] password = "user-password".getBytes();
+ final byte[] badPassword = "bad-password".getBytes();
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
mGateKeeperService, mUserManager);
AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null,
null, USER_ID);
- long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, PASSWORD,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC,
- USER_ID);
+ long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService,
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken,
+ PASSWORD_QUALITY_ALPHABETIC, USER_ID);
AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword(
- mGateKeeperService, handle, PASSWORD, USER_ID, null);
- assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword());
+ mGateKeeperService, handle, password, USER_ID, null);
+ assertArrayEquals(result.authToken.deriveKeyStorePassword(),
+ authToken.deriveKeyStorePassword());
result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle,
- BADPASSWORD, USER_ID, null);
+ badPassword, USER_ID, null);
assertNull(result.authToken);
}
@@ -97,30 +98,30 @@
}
public void testPasswordMigration() throws RemoteException {
- final String PASSWORD = "testPasswordMigration-password";
+ final byte[] password = "testPasswordMigration-password".getBytes();
disableSyntheticPassword();
- mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
enableSyntheticPassword();
// Performs migration
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
// SP-based verification
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayNotEquals(primaryStorageKey,
mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
- protected void initializeCredentialUnderSP(String password, int userId) throws RemoteException {
+ protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
enableSyntheticPassword();
int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
: PASSWORD_QUALITY_UNSPECIFIED;
@@ -130,62 +131,64 @@
}
public void testSyntheticPasswordChangeCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordChangeCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes();
+ final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
+ mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordVerifyCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordVerifyCredential-password";
- final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword";
+ final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes();
+ final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(
- BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
}
public void testSyntheticPasswordClearCredential() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordClearCredential-password";
- final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword";
+ final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes();
+ final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
// clear password
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
// set a new password
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ .getResponseCode());
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
}
public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password";
- final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new";
+ final byte[] password =
+ "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes();
+ final byte[] badPassword =
+ "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
- mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD,
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+ mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Check the same secret was passed each time
@@ -195,24 +198,25 @@
}
public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException {
- final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password";
- final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new";
+ final byte[] password =
+ "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes();
+ final byte[] newPassword =
+ "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes();
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
reset(mAuthSecretService);
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
}
public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException {
- final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password";
- final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new";
+ final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes();
- initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID);
+ initializeCredentialUnderSP(password, SECONDARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID)
.getResponseCode());
verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
}
@@ -228,8 +232,8 @@
}
public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
- final String PASSWORD = "passwordForASyntheticPassword";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "passwordForASyntheticPassword".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
reset(mAuthSecretService);
mService.onUnlockUser(PRIMARY_USER_ID);
@@ -238,9 +242,9 @@
}
public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
- final String PASSWORD = "getASyntheticPassword";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
+ final byte[] password = "getASyntheticPassword".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
reset(mAuthSecretService);
@@ -250,7 +254,7 @@
}
public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
- final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
+ final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
disableSyntheticPassword();
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
@@ -284,8 +288,10 @@
}
public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
- final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary";
- final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile";
+ final byte[] primaryPassword =
+ "testManagedProfileSeparateChallengeMigration-primary".getBytes();
+ final byte[] profilePassword =
+ "testManagedProfileSeparateChallengeMigration-profile".getBytes();
disableSyntheticPassword();
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
@@ -326,92 +332,92 @@
}
public void testTokenBasedResetPassword() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
// Verify DPM gets notified about new device lock
mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
- PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN);
+ PasswordMetrics metric = PasswordMetrics.computeForPassword(pattern);
metric.quality = PASSWORD_QUALITY_SOMETHING;
verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedClearPassword() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
- mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
+ pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException {
- final String PASSWORD = "password";
- final String PATTERN = "123654";
- final String NEWPASSWORD = "password";
- final String TOKEN = "some-high-entropy-secure-token";
- initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] newPassword = "password".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
0, PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
- mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD,
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
- mLocalService.setLockCredentialWithToken(NEWPASSWORD,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(),
+ mLocalService.setLockCredentialWithToken(newPassword,
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
}
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration()
throws RemoteException {
- final String TOKEN = "some-high-entropy-secure-token";
+ final String token = "some-high-entropy-secure-token";
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -419,9 +425,9 @@
public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration()
throws RemoteException {
- final String TOKEN = "some-high-entropy-secure-token";
+ final String token = "some-high-entropy-secure-token";
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -429,38 +435,38 @@
public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration()
throws RemoteException {
- final String TOKEN = "some-high-entropy-secure-token";
- final String PASSWORD = "password";
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
+ final byte[] password = "password".getBytes();
// Set up pre-SP user password
disableSyntheticPassword();
- mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+ mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
// Token not activated immediately since user password exists
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
// Activate token (password gets migrated to SP at the same time)
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+ password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
.getResponseCode());
// Verify token is activated
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
}
public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
- final String password = "password";
- final String pattern = "123654";
- final String token = "some-high-entropy-secure-token";
+ final byte[] password = "password".getBytes();
+ final byte[] pattern = "123654".getBytes();
+ final byte[] token = "some-high-entropy-secure-token".getBytes();
mHasSecureLockScreen = false;
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
try {
mLocalService.setLockCredentialWithToken(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
@@ -470,7 +476,7 @@
try {
mLocalService.setLockCredentialWithToken(pattern,
- LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token.getBytes(),
+ LockPatternUtils.CREDENTIAL_TYPE_PATTERN, handle, token,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
fail("An exception should have been thrown.");
} catch (UnsupportedOperationException e) {
@@ -480,14 +486,14 @@
}
public void testgetHashFactorPrimaryUser() throws RemoteException {
- final String password = "password";
+ final byte[] password = "password".getBytes();
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
assertNotNull(hashFactor);
- mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
- PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+ mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
+ password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
assertNotNull(newHashFactor);
// Hash factor should never change after password change/removal
@@ -495,16 +501,16 @@
}
public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
- final String pattern = "1236";
- mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
- PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+ final byte[] pattern = "1236".getBytes();
+ mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
}
public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
- final String primaryPassword = "primary";
- final String profilePassword = "profile";
+ final byte[] primaryPassword = "primary".getBytes();
+ final byte[] profilePassword = "profile".getBytes();
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
@@ -557,7 +563,7 @@
public void testGsiDisablesAuthSecret() throws RemoteException {
mGsiService.setIsGsiRunning(true);
- final String password = "testGsiDisablesAuthSecret-password";
+ final byte[] password = "testGsiDisablesAuthSecret-password".getBytes();
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index c2d4846..a992dd1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -139,7 +139,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
TEST_CREDENTIAL_TYPE,
- TEST_CREDENTIAL,
+ TEST_CREDENTIAL.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -163,17 +163,17 @@
@Test
public void isPin_isTrueForNumericString() {
- assertTrue(KeySyncTask.isPin("3298432574398654376547"));
+ assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes()));
}
@Test
public void isPin_isFalseForStringContainingLetters() {
- assertFalse(KeySyncTask.isPin("398i54369548654"));
+ assertFalse(KeySyncTask.isPin("398i54369548654".getBytes()));
}
@Test
public void isPin_isFalseForStringContainingSymbols() {
- assertFalse(KeySyncTask.isPin("-3987543643"));
+ assertFalse(KeySyncTask.isPin("-3987543643".getBytes()));
}
@Test
@@ -182,8 +182,8 @@
byte[] salt = randomBytes(16);
assertArrayEquals(
- KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials),
- KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials));
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()));
}
@Test
@@ -192,8 +192,8 @@
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"),
- KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345")));
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234".getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345".getBytes())));
}
@Test
@@ -202,34 +202,38 @@
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials),
- KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials)));
+ KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
+ credentials.getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64),
+ credentials.getBytes())));
}
@Test
public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() {
assertFalse(
Arrays.equals(
- KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"),
- KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567")));
+ KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"),
+ "4567".getBytes()),
+ KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"),
+ "567".getBytes())));
}
@Test
public void getUiFormat_returnsPinIfPin() {
assertEquals(UI_FORMAT_PIN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes()));
}
@Test
public void getUiFormat_returnsPasswordIfPassword() {
assertEquals(UI_FORMAT_PASSWORD,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes()));
}
@Test
public void getUiFormat_returnsPatternIfPattern() {
assertEquals(UI_FORMAT_PATTERN,
- KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234"));
+ KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes()));
}
@@ -291,7 +295,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ password,
+ /*credential=*/ password.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -332,7 +336,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PATTERN,
- /*credential=*/ pattern,
+ /*credential=*/ pattern.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -366,7 +370,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ shortPassword,
+ /*credential=*/ shortPassword.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -526,7 +530,7 @@
verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID);
byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256(
keyDerivationParams.getSalt(),
- TEST_CREDENTIAL);
+ TEST_CREDENTIAL.getBytes());
Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID);
assertThat(counterId).isNotNull();
byte[] recoveryKey = decryptThmEncryptedKey(
@@ -649,7 +653,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- password,
+ password.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -680,7 +684,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PASSWORD,
- /*credential=*/ pin,
+ /*credential=*/ pin.getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -712,7 +716,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
CREDENTIAL_TYPE_PATTERN,
- "12345",
+ "12345".getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
@@ -796,7 +800,7 @@
mSnapshotListenersStorage,
TEST_USER_ID,
/*credentialType=*/ 3,
- "12345",
+ "12345".getBytes(),
/*credentialUpdated=*/ false,
mPlatformKeyManager,
mTestOnlyInsecureCertificateHelper,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
index 9b4c3be..6921bb2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java
@@ -27,30 +27,30 @@
@Test
public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse();
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345".getBytes())).isFalse();
assertThat(mHelper.doesCredentialSupportInsecureMode(
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse();
+ LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())).isFalse();
}
@Test
public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isTrue();
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue();
+ (TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12").getBytes())).isTrue();
}
@Test
public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception {
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
assertThat(mHelper.doesCredentialSupportInsecureMode(
LockPatternUtils.CREDENTIAL_TYPE_NONE,
- TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse();
+ TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse();
}
@Test
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 3881e9e..4d6ff48 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
@@ -41,6 +42,8 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashMap;
@@ -339,6 +342,90 @@
public static final String[] strings = { "current", "disabled", "enabled" };
}
+ /**
+ * Security types we support.
+ */
+ /** @hide */
+ public static final int SECURITY_TYPE_OPEN = 0;
+ /** @hide */
+ public static final int SECURITY_TYPE_WEP = 1;
+ /** @hide */
+ public static final int SECURITY_TYPE_PSK = 2;
+ /** @hide */
+ public static final int SECURITY_TYPE_EAP = 3;
+ /** @hide */
+ public static final int SECURITY_TYPE_SAE = 4;
+ /** @hide */
+ public static final int SECURITY_TYPE_EAP_SUITE_B = 5;
+ /** @hide */
+ public static final int SECURITY_TYPE_OWE = 6;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
+ SECURITY_TYPE_OPEN,
+ SECURITY_TYPE_WEP,
+ SECURITY_TYPE_PSK,
+ SECURITY_TYPE_EAP,
+ SECURITY_TYPE_SAE,
+ SECURITY_TYPE_EAP_SUITE_B,
+ SECURITY_TYPE_OWE
+ })
+ public @interface SecurityType {}
+
+ /**
+ * @hide
+ * Set security params (sets the various bitsets exposed in WifiConfiguration).
+ *
+ * @param securityType One of the security types from {@link SecurityType}.
+ */
+ public void setSecurityParams(@SecurityType int securityType) {
+ // Clear all the bitsets.
+ allowedKeyManagement.clear();
+ allowedProtocols.clear();
+ allowedAuthAlgorithms.clear();
+ allowedPairwiseCiphers.clear();
+ allowedGroupCiphers.clear();
+ allowedGroupManagementCiphers.clear();
+ allowedSuiteBCiphers.clear();
+
+ switch (securityType) {
+ case SECURITY_TYPE_OPEN:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ break;
+ case SECURITY_TYPE_WEP:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
+ break;
+ case SECURITY_TYPE_PSK:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ break;
+ case SECURITY_TYPE_EAP:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ break;
+ case SECURITY_TYPE_SAE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ requirePMF = true;
+ break;
+ case SECURITY_TYPE_EAP_SUITE_B:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
+ allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
+ allowedSuiteBCiphers.set(WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ requirePMF = true;
+ break;
+ case SECURITY_TYPE_OWE:
+ allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ requirePMF = true;
+ break;
+ default:
+ throw new IllegalArgumentException("unknown security type " + securityType);
+ }
+ }
+
/** @hide */
public static final int UNKNOWN_UID = -1;
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 333b82c..c99bd2e 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -269,58 +269,26 @@
}
- /**
- * Set defaults for the various low level credential type fields in the newly created
- * WifiConfiguration object.
- *
- * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
- * WifiConfiguration)}.
- *
- * @param configuration provided WifiConfiguration object.
- */
- private static void setDefaultsInWifiConfiguration(
- @NonNull WifiConfiguration configuration) {
- configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
- }
-
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
} else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
- // PMF mandatory for SAE.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
} else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
configuration.enterpriseConfig = mWpa2EnterpriseConfig;
} else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
- configuration.allowedGroupManagementCiphers.set(
- WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_RSA);
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
- // PMF mandatory.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
} else { // Open network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
}
@@ -330,7 +298,6 @@
*/
private WifiConfiguration buildWifiConfiguration() {
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
- setDefaultsInWifiConfiguration(wifiConfiguration);
// WifiConfiguration.SSID needs quotes around unicode SSID.
if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 233fa2c..f02404f 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -303,58 +303,26 @@
return this;
}
- /**
- * Set defaults for the various low level credential type fields in the newly created
- * WifiConfiguration object.
- *
- * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
- * WifiConfiguration)}.
- *
- * @param configuration provided WifiConfiguration object.
- */
- private static void setDefaultsInWifiConfiguration(
- @NonNull WifiConfiguration configuration) {
- configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
- configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
- }
-
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
} else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
- // PMF mandatory for SAE.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
// WifiConfiguration.preSharedKey needs quotes around ASCII password.
configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
} else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP);
configuration.enterpriseConfig = mWpa2EnterpriseConfig;
} else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
- configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
- // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
- configuration.allowedGroupManagementCiphers.set(
- WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
- configuration.allowedSuiteBCiphers.set(
- WifiConfiguration.SuiteBCipher.ECDHE_RSA);
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B);
configuration.enterpriseConfig = mWpa3EnterpriseConfig;
} else if (mIsEnhancedOpen) { // OWE network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
- // PMF mandatory.
- configuration.requirePMF = true;
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE);
} else { // Open network
- configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ configuration.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN);
}
}
@@ -364,7 +332,6 @@
*/
private WifiConfiguration buildWifiConfiguration() {
final WifiConfiguration wifiConfiguration = new WifiConfiguration();
- setDefaultsInWifiConfiguration(wifiConfiguration);
// WifiConfiguration.SSID needs quotes around unicode SSID.
wifiConfiguration.SSID = "\"" + mSsid + "\"";
if (mBssid != null) {
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index acc0518..b73551f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -259,8 +259,17 @@
* {@hide}
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean ignoreLocationSettings;
+ /**
+ * This scan request will be hidden from app-ops noting for location information. This
+ * should only be used by FLP/NLP module on the device which is using the scan results to
+ * compute results for behalf on their clients. FLP/NLP module using this flag should ensure
+ * that they note in app-ops the eventual delivery of location information computed using
+ * these results to their client .
+ * {@hide}
+ */
+ @SystemApi
+ public boolean hideFromAppOps;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -279,6 +288,7 @@
dest.writeInt(isPnoScan ? 1 : 0);
dest.writeInt(type);
dest.writeInt(ignoreLocationSettings ? 1 : 0);
+ dest.writeInt(hideFromAppOps ? 1 : 0);
if (channels != null) {
dest.writeInt(channels.length);
for (int i = 0; i < channels.length; i++) {
@@ -314,6 +324,7 @@
settings.isPnoScan = in.readInt() == 1;
settings.type = in.readInt();
settings.ignoreLocationSettings = in.readInt() == 1;
+ settings.hideFromAppOps = in.readInt() == 1;
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index f931ad2..479adbc 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -26,6 +26,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.regex.PatternSyntaxException;
/**
* A class representing a Wi-Fi P2p configuration for setting up a connection
@@ -252,7 +253,12 @@
* Specify the network name, a.k.a. group name,
* for creating or joining a group.
* <p>
- * Must be called - an empty network name is not valid.
+ * A network name shall begin with "DIRECT-xy". x and y are selected
+ * from the following character set: upper case letters, lower case
+ * letters and numbers.
+ * <p>
+ * Must be called - an empty network name or an network name
+ * not conforming to the P2P Group ID naming rule is not valid.
*
* @param networkName network name of a group.
* @return The builder to facilitate chaining
@@ -263,6 +269,14 @@
throw new IllegalArgumentException(
"network name must be non-empty.");
}
+ try {
+ if (!networkName.matches("^DIRECT-[a-zA-Z0-9]{2}.*")) {
+ throw new IllegalArgumentException(
+ "network name must starts with the prefix DIRECT-xy.");
+ }
+ } catch (PatternSyntaxException e) {
+ // can never happen (fixed pattern)
+ }
mNetworkName = networkName;
return this;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index bef33b7..feac0e5 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -69,16 +69,6 @@
assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.NONE));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
}
/**
@@ -105,16 +95,6 @@
wifiNetworkSpecifier.bssidPatternMatcher.second);
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.WPA_PSK));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
}
@@ -150,16 +130,6 @@
.get(WifiConfiguration.KeyMgmt.WPA_EAP));
assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
.get(WifiConfiguration.KeyMgmt.IEEE8021X));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
- .get(WifiConfiguration.Protocol.RSN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
- .get(WifiConfiguration.AuthAlgorithm.OPEN));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
- .get(WifiConfiguration.PairwiseCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.CCMP));
- assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
- .get(WifiConfiguration.GroupCipher.TKIP));
assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
assertEquals(enterpriseConfig.getEapMethod(),
wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java
new file mode 100644
index 0000000..560c88e
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pConfigTest.java
@@ -0,0 +1,76 @@
+/*
+ * 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.net.wifi.p2p;
+
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit test harness for {@link android.net.wifi.p2p.WifiP2pConfig}
+ */
+@SmallTest
+public class WifiP2pConfigTest {
+ /**
+ * Check network name setter
+ */
+ @Test
+ public void testBuilderInvalidNetworkName() throws Exception {
+ WifiP2pConfig.Builder b = new WifiP2pConfig.Builder();
+
+ // sunny case
+ try {
+ b.setNetworkName("DIRECT-ab-Hello");
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException");
+ }
+
+ // sunny case, no trailing string
+ try {
+ b.setNetworkName("DIRECT-WR");
+ } catch (IllegalArgumentException e) {
+ fail("Unexpected IllegalArgumentException");
+ }
+
+ // less than 9 characters.
+ try {
+ b.setNetworkName("DIRECT-z");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // not starts with DIRECT-xy.
+ try {
+ b.setNetworkName("ABCDEFGHIJK");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // not starts with uppercase DIRECT-xy
+ try {
+ b.setNetworkName("direct-ab");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+
+ // x and y are not selected from upper case letters, lower case letters or
+ // numbers.
+ try {
+ b.setNetworkName("direct-a?");
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) { }
+ }
+}