Merge "Start Screenrecord from Record Issue QS Tile." into main
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index 6d1e6d0..4352c8a 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -24,10 +24,11 @@
import android.content.res.TypedArray
import android.perftests.utils.BenchmarkState
import android.perftests.utils.PerfStatusReporter
+import android.util.ArraySet
import androidx.test.filters.LargeTest
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.internal.util.ConcurrentUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.ArrayBlockingQueue
@@ -214,7 +215,10 @@
path,
manifestArray,
isCoreApp,
+ this,
)
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
override fun parseImpl(file: File) =
diff --git a/core/api/current.txt b/core/api/current.txt
index 7f261d4..1b5c953 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12606,6 +12606,7 @@
method public boolean isStagedSessionApplied();
method public boolean isStagedSessionFailed();
method public boolean isStagedSessionReady();
+ method @FlaggedApi("android.content.pm.archiving") public boolean isUnarchival();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
field public static final int INVALID_ID = -1; // 0xffffffff
@@ -13296,6 +13297,7 @@
method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
method @IntRange(from=0xffffffff) public long getLongVersion();
method public String getName();
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.VersionedPackage> getOptionalDependentPackages();
method public int getType();
method @Deprecated @IntRange(from=0xffffffff) public int getVersion();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index e7803fb..d395b8c 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -136,6 +136,7 @@
package android.content.pm {
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method @FlaggedApi("android.content.pm.sdk_lib_independence") @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getOptionalSharedLibraryInfos();
method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraryInfos();
field public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1; // 0xffffffff
field public static final int HIDDEN_API_ENFORCEMENT_DISABLED = 0; // 0x0
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 7237af3..e92564b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12930,6 +12930,7 @@
field public static final int CONFIDENCE_LEVEL_LOW = 1; // 0x1
field public static final int CONFIDENCE_LEVEL_MEDIUM = 2; // 0x2
field public static final int CONFIDENCE_LEVEL_NONE = 0; // 0x0
+ field @FlaggedApi("android.service.voice.flags.allow_hotword_bump_egress") public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordRejectedResult> CREATOR;
}
@@ -13051,7 +13052,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.VisualQueryDetector createVisualQueryDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VisualQueryDetector.Callback);
- method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setIsReceiveSandboxedTrainingDataAllowed(boolean);
+ method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setShouldReceiveSandboxedTrainingData(boolean);
}
}
@@ -13701,6 +13702,7 @@
method @NonNull public java.util.List<java.lang.Boolean> areCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public int describeContents();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers();
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_restriction_status") public int getCarrierRestrictionStatus();
method public int getDefaultCarrierRestriction();
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
method public int getMultiSimPolicy();
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index dec1ee5..cef11bb 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1909,6 +1909,8 @@
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addAccessibilityStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.view.accessibility.AccessibilityManager#addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.view.accessibility.AccessibilityManager.addTouchExplorationStateChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.view.inputmethod.InputMethodInfo#dump(android.util.Printer, String):
+ SAM-compatible parameters (such as parameter 1, "pw", in android.view.inputmethod.InputMethodInfo.dump) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.webkit.WebChromeClient#onShowFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams):
SAM-compatible parameters (such as parameter 2, "filePathCallback", in android.webkit.WebChromeClient.onShowFileChooser) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 87c86df..287d2bd 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2909,7 +2909,7 @@
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
- getUserId());
+ UserHandle.myUserId() /* suspendingUserId */, getUserId() /* targetUserId */);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index d935449..53a21cd 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -16,6 +16,8 @@
package android.app;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.DrawableRes;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
@@ -390,7 +392,7 @@
*/
@FlaggedApi(Flags.FLAG_MODES_API)
public void setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
}
/**
@@ -451,6 +453,24 @@
mAllowManualInvocation = allowManualInvocation;
}
+ /** @hide */
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidType(mType);
+ }
+ }
+
+ @FlaggedApi(Flags.FLAG_MODES_API)
+ @Type
+ private static int checkValidType(@Type int type) {
+ checkArgument(type >= TYPE_UNKNOWN && type <= TYPE_MANAGED,
+ "Rule type must be one of TYPE_UNKNOWN, TYPE_OTHER, TYPE_SCHEDULE_TIME, "
+ + "TYPE_SCHEDULE_CALENDAR, TYPE_BEDTIME, TYPE_DRIVING, TYPE_IMMERSIVE, "
+ + "TYPE_THEATER, or TYPE_MANAGED");
+ return type;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -703,10 +723,10 @@
}
/**
- * Sets the type of the rule
+ * Sets the type of the rule.
*/
public @NonNull Builder setType(@Type int type) {
- mType = type;
+ mType = checkValidType(type);
return this;
}
@@ -714,7 +734,7 @@
* Sets a user visible description of when this rule will be active
* (see {@link Condition#STATE_TRUE}).
*
- * A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
+ * <p>A description should be a (localized) string like "Mon-Fri, 9pm-7am" or
* "When connected to [Car Name]".
*/
public @NonNull Builder setTriggerDescription(@Nullable String description) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 16a80e9..3713380 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,6 +19,7 @@
import static android.os.Build.VERSION_CODES.DONUT;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1065,11 +1066,25 @@
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
* the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* {@hide}
*/
+ @Nullable
public List<SharedLibraryInfo> sharedLibraryInfos;
/**
+ * List of all shared libraries this application is optionally linked against.
+ * This field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
+ * the structure.
+ *
+ * @hide
+ */
+ @Nullable
+ public List<SharedLibraryInfo> optionalSharedLibraryInfos;
+
+ /**
* Full path to the default directory assigned to the package for its
* persistent data.
*/
@@ -1937,6 +1952,7 @@
seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
sharedLibraryInfos = orig.sharedLibraryInfos;
+ optionalSharedLibraryInfos = orig.optionalSharedLibraryInfos;
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -2029,6 +2045,7 @@
dest.writeString8(seInfoUser);
dest.writeString8Array(sharedLibraryFiles);
dest.writeTypedList(sharedLibraryInfos);
+ dest.writeTypedList(optionalSharedLibraryInfos);
dest.writeString8(dataDir);
dest.writeString8(deviceProtectedDataDir);
dest.writeString8(credentialProtectedDataDir);
@@ -2129,6 +2146,7 @@
seInfoUser = source.readString8();
sharedLibraryFiles = source.createString8Array();
sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
+ optionalSharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
dataDir = source.readString8();
deviceProtectedDataDir = source.readString8();
credentialProtectedDataDir = source.readString8();
@@ -2760,6 +2778,8 @@
* list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
*
+ * NOTE: the list also contains the result of {@link #getOptionalSharedLibraryInfos}.
+ *
* @hide
*/
@NonNull
@@ -2772,6 +2792,23 @@
}
/**
+ * List of all shared libraries this application is optionally linked against. This
+ * list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public List<SharedLibraryInfo> getOptionalSharedLibraryInfos() {
+ if (optionalSharedLibraryInfos == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return optionalSharedLibraryInfos;
+ }
+
+ /**
* Gets the trusted host certificate digests of apps that are allowed to embed activities of
* this application. The digests are computed using the SHA-256 digest algorithm.
* @see android.R.attr#knownActivityEmbeddingCerts
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 6f7299a..a97de63 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -65,6 +65,8 @@
in UserHandle user);
LauncherUserInfo getLauncherUserInfo(in UserHandle user);
List<String> getPreInstalledSystemPackages(in UserHandle user);
+ IntentSender getAppMarketActivityIntent(String callingPackage, String packageName,
+ in UserHandle user);
void showAppDetailsAsUser(in IApplicationThread caller, String callingPackage,
String callingFeatureId, in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 98623de..6dc8d47 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -300,7 +300,8 @@
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
- in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);
+ in SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId);
String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index ccc8f09..1d2b1af 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -799,6 +799,55 @@
}
}
+
+ /**
+ * Returns an intent sender which can be used to start the App Market activity (Installer
+ * Activity).
+ * This method is primarily used to get an intent sender which starts App Market activity for
+ * another profile, if the caller is not otherwise allowed to start activity in that profile.
+ *
+ * <p>When packageName is set, intent sender to start the App Market Activity which installed
+ * the package in calling user will be returned, but for the profile passed.
+ *
+ * <p>When packageName is not set, intent sender to launch the default App Market Activity for
+ * the profile will be returned. In case there are multiple App Market Activities available for
+ * the profile, IntentPicker will be started, allowing user to choose the preferred activity.
+ *
+ * <p>The method will fall back to the behaviour of not having the packageName set, in case:
+ * <ul>
+ * <li>No activity for the packageName is found in calling user-space.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present.</li>
+ * <li>The App Market Activity which installed the package in calling user-space is not
+ * present in the profile passed.</li>
+ * </ul>
+ * </p>
+ *
+ *
+ *
+ * @param packageName the package for which intent sender to launch App Market Activity is
+ * required.
+ * @param user the profile for which intent sender to launch App Market Activity is required.
+ * @return {@link IntentSender} object which launches the App Market Activity, null in case
+ * there is no such activity.
+ * @hide
+ */
+ @Nullable
+ @FlaggedApi(Flags.FLAG_ALLOW_PRIVATE_PROFILE)
+ public IntentSender getAppMarketActivityIntent(@Nullable String packageName,
+ @NonNull UserHandle user) {
+ if (DEBUG) {
+ Log.i(TAG, "getAppMarketActivityIntent for package: " + packageName
+ + " user: " + user);
+ }
+ try {
+ return mService.getAppMarketActivityIntent(mContext.getPackageName(),
+ packageName, user);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
/**
* Returns the list of the system packages that are installed at user creation.
*
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index e395127..0e131b4 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -4381,6 +4381,17 @@
return pendingUserActionReason;
}
+ /**
+ * Returns true if the session is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ */
+ @FlaggedApi(Flags.FLAG_ARCHIVING)
+ public boolean isUnarchival() {
+ return (installFlags & PackageManager.INSTALL_UNARCHIVE) != 0;
+ }
+
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a5d16f2..a8638708 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1517,6 +1517,7 @@
INSTALL_REQUEST_UPDATE_OWNERSHIP,
INSTALL_IGNORE_DEXOPT_PROFILE,
INSTALL_UNARCHIVE_DRAFT,
+ INSTALL_UNARCHIVE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -1764,13 +1765,22 @@
* If set, then the session is a draft session created for an upcoming unarchival by its
* installer.
*
- * @see PackageInstaller#requestUnarchive(String)
+ * @see PackageInstaller#requestUnarchive
*
* @hide
*/
public static final int INSTALL_UNARCHIVE_DRAFT = 1 << 29;
/**
+ * If set, then the {@link PackageInstaller.Session} is an unarchival.
+ *
+ * @see PackageInstaller#requestUnarchive
+ *
+ * @hide
+ */
+ public static final int INSTALL_UNARCHIVE = 1 << 30;
+
+ /**
* Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
* a development-only feature and should not be used on end user devices.
*
@@ -9990,6 +10000,9 @@
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
* {@link android.Manifest.permission#SUSPEND_APPS}.
*
+ * <p>
+ * <strong>Note:</strong>This API doesn't support cross user suspension and should only be used
+ * for testing.
* @param suspendedPackage The package that has been suspended.
* @return Name of the package that suspended the given package. Returns {@code null} if the
* given package is not currently suspended and the platform package name - i.e.
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 25ba725..5acebf5 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -23,6 +24,7 @@
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Pair;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -99,20 +101,22 @@
private final boolean mIsNative;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
+
+ private final List<VersionedPackage> mOptionalDependentPackages;
private List<SharedLibraryInfo> mDependencies;
/**
* Creates a new instance.
*
- * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
- * this shared library. Null for builtin library.
- * @param name The lib name.
- * @param version The lib version if not builtin.
- * @param type The lib type.
- * @param declaringPackage The package that declares the library.
+ * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of
+ * jars of
+ * this shared library. Null for builtin library.
+ * @param name The lib name.
+ * @param version The lib version if not builtin.
+ * @param type The lib type.
+ * @param declaringPackage The package that declares the library.
* @param dependentPackages The packages that depend on the library.
- * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
- *
+ * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
* @hide
*/
public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
@@ -129,6 +133,58 @@
mDependentPackages = dependentPackages;
mDependencies = dependencies;
mIsNative = isNative;
+ mOptionalDependentPackages = null;
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
+ * this shared library. Null for builtin library.
+ * @param name The lib name.
+ * @param version The lib version if not builtin.
+ * @param type The lib type.
+ * @param declaringPackage The package that declares the library.
+ * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
+ * @param allDependentPackages All packages that depend on the library (including the optional
+ * sdk libraries).
+ *
+ * @hide
+ */
+ public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+ String name, long version, int type,
+ VersionedPackage declaringPackage,
+ List<SharedLibraryInfo> dependencies, boolean isNative,
+ Pair<List<VersionedPackage>, List<Boolean>> allDependentPackages) {
+ mPath = path;
+ mPackageName = packageName;
+ mCodePaths = codePaths;
+ mName = name;
+ mVersion = version;
+ mType = type;
+ mDeclaringPackage = declaringPackage;
+ mDependencies = dependencies;
+ mIsNative = isNative;
+
+ var allDependents = allDependentPackages.first;
+ var usesLibOptional = allDependentPackages.second;
+ mDependentPackages = allDependents;
+ List<VersionedPackage> optionalDependents = null;
+ if (mType == SharedLibraryInfo.TYPE_SDK_PACKAGE
+ && Flags.sdkLibIndependence() && allDependents != null
+ && usesLibOptional != null
+ && allDependents.size() == usesLibOptional.size()) {
+ for (int k = 0; k < allDependents.size(); k++) {
+ VersionedPackage versionedPackage = allDependents.get(k);
+ if (usesLibOptional.get(k)) {
+ if (optionalDependents == null) {
+ optionalDependents = new ArrayList<>();
+ }
+ optionalDependents.add(versionedPackage);
+ }
+ }
+ }
+ mOptionalDependentPackages = optionalDependents;
}
private SharedLibraryInfo(Parcel parcel) {
@@ -148,6 +204,8 @@
parcel.readArrayList(null, android.content.pm.VersionedPackage.class);
mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
mIsNative = parcel.readBoolean();
+ mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
+ VersionedPackage.class.getClassLoader(), VersionedPackage.class);
}
/**
@@ -324,6 +382,8 @@
/**
* Gets the packages that depend on the library.
*
+ * NOTE: the list also contains the result of {@link #getOptionalDependentPackages}.
+ *
* @return The dependent packages.
*/
public @NonNull List<VersionedPackage> getDependentPackages() {
@@ -333,6 +393,19 @@
return mDependentPackages;
}
+ /**
+ * Gets the packages that optionally depend on the library.
+ *
+ * @return The dependent packages.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
+ public @NonNull List<VersionedPackage> getOptionalDependentPackages() {
+ if (mOptionalDependentPackages == null) {
+ return Collections.emptyList();
+ }
+ return mOptionalDependentPackages;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -362,6 +435,7 @@
parcel.writeList(mDependentPackages);
parcel.writeTypedList(mDependencies);
parcel.writeBoolean(mIsNative);
+ parcel.writeParcelableList(mOptionalDependentPackages, flags);
}
private static String typeToString(int type) {
diff --git a/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
new file mode 100644
index 0000000..73ac333
--- /dev/null
+++ b/core/java/android/hardware/biometrics/AuthenticationStateListener.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.biometrics;
+
+/**
+ * Low-level callback interface between <Biometric>Manager and <Auth>Service. Allows core system
+ * services (e.g. SystemUI) to register a listener for updates about the current state of biometric
+ * authentication.
+ * @hide
+ */
+oneway interface AuthenticationStateListener {
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ void onAuthenticationStarted(int requestReason);
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ void onAuthenticationStopped();
+}
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index f82f79e..d7d1d1a 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -552,6 +552,44 @@
}
/**
+ * Registers listener for changes to biometric authentication state.
+ * Only sends callbacks for events that occur after the callback has been registered.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.registerAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "registerAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+ /**
+ * Unregisters listener for changes to biometric authentication state.
+ * @param listener Listener for changes to biometric authentication state
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener) {
+ if (mService != null) {
+ try {
+ mService.unregisterAuthenticationStateListener(listener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "unregisterAuthenticationStateListener(): Service not connected");
+ }
+ }
+
+
+ /**
* Requests all {@link Authenticators.Types#BIOMETRIC_STRONG} sensors to have their
* authenticatorId invalidated for the specified user. This happens when enrollments have been
* added on devices with multiple biometric sensors.
diff --git a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
similarity index 69%
rename from core/java/android/hardware/biometrics/BiometricOverlayConstants.java
rename to core/java/android/hardware/biometrics/BiometricRequestConstants.java
index 065ae64a..b036f30 100644
--- a/core/java/android/hardware/biometrics/BiometricOverlayConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricRequestConstants.java
@@ -22,24 +22,27 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Common constants for biometric overlays.
+ * Common constants for biometric requests.
* @hide
*/
-public interface BiometricOverlayConstants {
+public class BiometricRequestConstants {
+
+ private BiometricRequestConstants() {}
+
/** Unknown usage. */
- int REASON_UNKNOWN = 0;
+ public static final int REASON_UNKNOWN = 0;
/** User is about to enroll. */
- int REASON_ENROLL_FIND_SENSOR = 1;
+ public static final int REASON_ENROLL_FIND_SENSOR = 1;
/** User is enrolling. */
- int REASON_ENROLL_ENROLLING = 2;
+ public static final int REASON_ENROLL_ENROLLING = 2;
/** Usage from BiometricPrompt. */
- int REASON_AUTH_BP = 3;
- /** Usage from Keyguard. */
- int REASON_AUTH_KEYGUARD = 4;
+ public static final int REASON_AUTH_BP = 3;
+ /** Usage from Device Entry. */
+ public static final int REASON_AUTH_KEYGUARD = 4;
/** Non-specific usage (from FingerprintManager). */
- int REASON_AUTH_OTHER = 5;
+ public static final int REASON_AUTH_OTHER = 5;
/** Usage from Settings. */
- int REASON_AUTH_SETTINGS = 6;
+ public static final int REASON_AUTH_SETTINGS = 6;
@IntDef({REASON_UNKNOWN,
REASON_ENROLL_FIND_SENSOR,
@@ -49,5 +52,5 @@
REASON_AUTH_OTHER,
REASON_AUTH_SETTINGS})
@Retention(RetentionPolicy.SOURCE)
- @interface ShowReason {}
+ public @interface RequestReason {}
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 5bdbe2b5..8514f98 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -16,6 +16,7 @@
package android.hardware.biometrics;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.biometrics.IBiometricServiceReceiver;
import android.hardware.biometrics.IInvalidationCallback;
@@ -66,6 +67,12 @@
// Register callback for when keyguard biometric eligibility changes.
void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
+ // Register listener for changes to authentication state.
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregister listener for changes to authentication state.
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Requests all BIOMETRIC_STRONG sensors to have their authenticatorId invalidated for the
// specified user. This happens when enrollments have been added on devices with multiple
// biometric sensors.
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 93fbe8a..7cf10d8 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -1216,7 +1216,7 @@
* <ul>
* <li>Profile {@link android.hardware.camera2.params.DynamicRangeProfiles#HLG10 }</li>
* <li>All mandatory stream combinations for this specific capability as per
- * <a href="CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#10-bit-output-additional-guaranteed-configurations">documentation</a></li>
* <li>In case the device is not able to capture some combination of supported
* standard 8-bit and/or 10-bit dynamic range profiles within the same capture request,
* then those constraints must be listed in
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 06397c9..ded96a2 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1484,7 +1484,7 @@
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2161,7 +2161,7 @@
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ab4406c3..1d26d69 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -899,7 +899,7 @@
* <p>To start a CaptureSession with a target FPS range different from the
* capture request template's default value, the application
* is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the target fps range before creating the capture session. The aeTargetFpsRange is
* typically a session parameter. Specifying it at session creation time helps avoid
* session reconfiguration delays in cases like 60fps or high speed recording.</p>
@@ -2382,7 +2382,7 @@
* OFF if the recording output is not stabilized, or if there are no output
* Surface types that can be stabilized.</p>
* <p>The application is strongly recommended to call
- * {@link SessionConfiguration#setSessionParameters }
+ * {@link android.hardware.camera2.params.SessionConfiguration#setSessionParameters }
* with the desired video stabilization mode before creating the capture session.
* Video stabilization mode is a session parameter on many devices. Specifying
* it at session creation time helps avoid reconfiguration delay caused by difference
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 935157a..fe7de83 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -983,6 +983,7 @@
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* @hide
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 0100660..f594c00 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -15,6 +15,7 @@
*/
package android.hardware.fingerprint;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.IBiometricStateListener;
@@ -203,6 +204,14 @@
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setSidefpsController(in ISidefpsController controller);
+ // Registers AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void registerAuthenticationStateListener(AuthenticationStateListener listener);
+
+ // Unregisters AuthenticationStateListener.
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void unregisterAuthenticationStateListener(AuthenticationStateListener listener);
+
// Registers BiometricStateListener.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void registerBiometricStateListener(IBiometricStateListener listener);
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 531626b1..6e771f8 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
package android.service.notification;
+import static com.android.internal.util.Preconditions.checkArgument;
+
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -117,7 +119,7 @@
/** The source of, or reason for, the state change represented by this Condition. **/
@FlaggedApi(Flags.FLAG_MODES_API)
- public final @Source int source;
+ public final @Source int source; // default = SOURCE_UNKNOWN
/**
* The maximum string length for any string contained in this condition.
@@ -179,7 +181,7 @@
this.line2 = getTrimmedString(line2);
this.icon = icon;
this.state = state;
- this.source = source;
+ this.source = checkValidSource(source);
this.flags = flags;
}
@@ -197,10 +199,26 @@
source.readInt());
}
+ /** @hide */
+ public void validate() {
+ if (Flags.modesApi()) {
+ checkValidSource(source);
+ }
+ }
+
private static boolean isValidState(int state) {
return state >= STATE_FALSE && state <= STATE_ERROR;
}
+ private static int checkValidSource(@Source int source) {
+ if (Flags.modesApi()) {
+ checkArgument(source >= SOURCE_UNKNOWN && source <= SOURCE_CONTEXT,
+ "Condition source must be one of SOURCE_UNKNOWN, SOURCE_USER_ACTION, "
+ + "SOURCE_SCHEDULE, or SOURCE_CONTEXT");
+ }
+ return source;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(id, 0);
diff --git a/core/java/android/service/voice/HotwordRejectedResult.java b/core/java/android/service/voice/HotwordRejectedResult.java
index 26c1ca4..eb1ac67 100644
--- a/core/java/android/service/voice/HotwordRejectedResult.java
+++ b/core/java/android/service/voice/HotwordRejectedResult.java
@@ -16,9 +16,11 @@
package android.service.voice;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.SystemApi;
import android.os.Parcelable;
+import android.service.voice.flags.Flags;
import com.android.internal.util.DataClass;
@@ -53,12 +55,17 @@
/** High confidence in hotword detector result. */
public static final int CONFIDENCE_LEVEL_HIGH = 3;
+ /** Very high confidence in hotword detector result. **/
+ @FlaggedApi(Flags.FLAG_ALLOW_HOTWORD_BUMP_EGRESS)
+ public static final int CONFIDENCE_LEVEL_VERY_HIGH = 4;
+
/** @hide */
@IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
@Retention(RetentionPolicy.SOURCE)
@interface HotwordConfidenceLevelValue {
@@ -91,9 +98,10 @@
CONFIDENCE_LEVEL_NONE,
CONFIDENCE_LEVEL_LOW,
CONFIDENCE_LEVEL_MEDIUM,
- CONFIDENCE_LEVEL_HIGH
+ CONFIDENCE_LEVEL_HIGH,
+ CONFIDENCE_LEVEL_VERY_HIGH
})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
public @interface ConfidenceLevel {}
@@ -109,6 +117,8 @@
return "CONFIDENCE_LEVEL_MEDIUM";
case CONFIDENCE_LEVEL_HIGH:
return "CONFIDENCE_LEVEL_HIGH";
+ case CONFIDENCE_LEVEL_VERY_HIGH:
+ return "CONFIDENCE_LEVEL_VERY_HIGH";
default: return Integer.toHexString(value);
}
}
@@ -259,10 +269,10 @@
}
@DataClass.Generated(
- time = 1621961370106L,
+ time = 1701990933632L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordRejectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final @android.annotation.FlaggedApi int CONFIDENCE_LEVEL_VERY_HIGH\nprivate final @android.service.voice.HotwordRejectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate static int defaultConfidenceLevel()\nclass HotwordRejectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index fba0923..75ab48a 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -1042,13 +1042,13 @@
@SystemApi
@FlaggedApi(Flags.FLAG_ALLOW_TRAINING_DATA_EGRESS_FROM_HDS)
@RequiresPermission(Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- Log.i(TAG, "setIsReceiveSandboxedTrainingDataAllowed to " + allowed);
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ Log.i(TAG, "setShouldReceiveSandboxedTrainingData to " + allowed);
if (mSystemService == null) {
throw new IllegalStateException("Not available until onReady() is called");
}
try {
- mSystemService.setIsReceiveSandboxedTrainingDataAllowed(allowed);
+ mSystemService.setShouldReceiveSandboxedTrainingData(allowed);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index c414ef8..b596666 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -6,3 +6,10 @@
description: "This flag allows the hotword detection service to egress training data to the default assistant."
bug: "296074924"
}
+
+flag {
+ name: "allow_hotword_bump_egress"
+ namespace: "machine_learning"
+ description: "This flag allows hotword detection service to egress reason code for hotword bump."
+ bug: "290951024"
+}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index dbacca5..9bf43a3 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -162,6 +162,8 @@
* @param flags See {@code View#startDragAndDrop}
* @param surface Surface containing drag shadow image
* @param touchSource See {@code InputDevice#getSource()}
+ * @param touchDeviceId device ID of last touch event
+ * @param pointerId pointer ID of last touch event
* @param touchX X coordinate of last touch point
* @param touchY Y coordinate of last touch point
* @param thumbCenterX X coordinate for the position within the shadow image that should be
@@ -171,9 +173,9 @@
* @param data Data transferred by drag and drop
* @return Token of drag operation which will be passed to cancelDragAndDrop.
*/
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
IBinder performDrag(IWindow window, int flags, in SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, in ClipData data);
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, in ClipData data);
/**
* Drops the content of the current drag operation for accessibility
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 75f8eba..bb5ee03 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -28340,6 +28340,8 @@
IBinder token = mAttachInfo.mSession.performDrag(
mAttachInfo.mWindow, flags, null,
mAttachInfo.mViewRootImpl.getLastTouchSource(),
+ mAttachInfo.mViewRootImpl.getLastTouchDeviceId(),
+ mAttachInfo.mViewRootImpl.getLastTouchPointerId(),
0f, 0f, 0f, 0f, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token);
@@ -28414,7 +28416,8 @@
}
token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl,
- root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y,
+ root.getLastTouchSource(), root.getLastTouchDeviceId(),
+ root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y,
shadowTouchPoint.x, shadowTouchPoint.y, data);
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "performDrag returned " + token);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8339d33..e83488e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -813,6 +813,8 @@
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
int mLastTouchSource;
+ int mLastTouchDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
+ int mLastTouchPointerId;
/** Tracks last {@link MotionEvent#getToolType(int)} with {@link MotionEvent#ACTION_UP}. **/
private int mLastClickToolType;
@@ -7163,6 +7165,8 @@
mLastTouchPoint.x = event.getRawX();
mLastTouchPoint.y = event.getRawY();
mLastTouchSource = event.getSource();
+ mLastTouchDeviceId = event.getDeviceId();
+ mLastTouchPointerId = event.getPointerId(0);
// Register last ACTION_UP. This will be propagated to IME.
if (event.getActionMasked() == MotionEvent.ACTION_UP) {
@@ -8574,6 +8578,14 @@
return mLastTouchSource;
}
+ public int getLastTouchDeviceId() {
+ return mLastTouchDeviceId;
+ }
+
+ public int getLastTouchPointerId() {
+ return mLastTouchPointerId;
+ }
+
/**
* Used by InputMethodManager.
* @hide
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c7e1807..e3d9c60 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -592,6 +592,13 @@
int TRANSIT_FLAG_KEYGUARD_UNOCCLUDING = (1 << 13); // 0x2000
/**
+ * Transition flag: Indicates that there is a physical display switch
+ * TODO(b/316112906) remove after defer_display_updates flag roll out
+ * @hide
+ */
+ int TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH = (1 << 14); // 0x4000
+
+ /**
* @hide
*/
@IntDef(flag = true, prefix = { "TRANSIT_FLAG_" }, value = {
@@ -608,7 +615,8 @@
TRANSIT_FLAG_INVISIBLE,
TRANSIT_FLAG_KEYGUARD_APPEARING,
TRANSIT_FLAG_KEYGUARD_OCCLUDING,
- TRANSIT_FLAG_KEYGUARD_UNOCCLUDING
+ TRANSIT_FLAG_KEYGUARD_UNOCCLUDING,
+ TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH,
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionFlags {}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 393d256..d6ac562 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -489,8 +489,9 @@
@Override
public android.os.IBinder performDrag(android.view.IWindow window, int flags,
- android.view.SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, android.content.ClipData data) {
+ android.view.SurfaceControl surface, int touchSource, int touchDeviceId,
+ int touchPointerId, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ android.content.ClipData data) {
return null;
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 82ee8fc..e92c6a6 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -397,5 +397,5 @@
* sandboxed detection (from trusted process).
*/
@EnforcePermission("MANAGE_HOTWORD_DETECTION")
- void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed);
+ void setShouldReceiveSandboxedTrainingData(boolean allowed);
}
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index efc1455..f1aa330 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -39,6 +39,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -308,7 +309,8 @@
try {
final String[] errored = ipm.setPackagesSuspendedAsUser(
new String[]{mSuspendedPackage}, false, null, null, null, 0,
- mSuspendingPackage, mUserId);
+ mSuspendingPackage, mUserId /* suspendingUserId */,
+ mUserId /* targetUserId */);
if (ArrayUtils.contains(errored, mSuspendedPackage)) {
Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage);
break;
@@ -350,17 +352,18 @@
}
public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
+ UserPackage suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
IntentSender onUnsuspend, int userId) {
- return new Intent()
+ Intent intent = new Intent()
.setClassName("android", SuspendedAppActivity.class.getName())
.putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
.putExtra(EXTRA_DIALOG_INFO, dialogInfo)
- .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
+ .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage.packageName)
.putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend)
.putExtra(EXTRA_ACTIVITY_OPTIONS, options)
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ return intent;
}
}
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index f460233..96740c5 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -109,6 +109,7 @@
* eg: Exit the app using back gesture.
*/
public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK = 78;
+ // 79 is reserved.
public static final int CUJ_IME_INSETS_SHOW_ANIMATION = 80;
public static final int CUJ_IME_INSETS_HIDE_ANIMATION = 81;
@@ -119,10 +120,11 @@
public static final int CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY = 84;
public static final int CUJ_PREDICTIVE_BACK_CROSS_TASK = 85;
public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
+ public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
@VisibleForTesting
- static final int LAST_CUJ = CUJ_PREDICTIVE_BACK_HOME;
+ static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_OPEN;
/** @hide */
@IntDef({
@@ -204,6 +206,7 @@
CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY,
CUJ_PREDICTIVE_BACK_CROSS_TASK,
CUJ_PREDICTIVE_BACK_HOME,
+ CUJ_LAUNCHER_SEARCH_QSB_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -295,6 +298,8 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_ACTIVITY;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_CROSS_TASK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_CROSS_TASK;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] =
+ FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
}
private Cuj() {
@@ -467,6 +472,8 @@
return "PREDICTIVE_BACK_CROSS_TASK";
case CUJ_PREDICTIVE_BACK_HOME:
return "PREDICTIVE_BACK_HOME";
+ case CUJ_LAUNCHER_SEARCH_QSB_OPEN:
+ return "LAUNCHER_SEARCH_QSB_OPEN";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/net/TEST_MAPPING b/core/java/com/android/internal/net/TEST_MAPPING
index 971ad36..f935946c 100644
--- a/core/java/com/android/internal/net/TEST_MAPPING
+++ b/core/java/com/android/internal/net/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksNetTests",
"options": [
diff --git a/core/java/com/android/internal/pm/parsing/AppInfoUtils.java b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
new file mode 100644
index 0000000..38a2fe2
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/AppInfoUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 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.internal.pm.parsing;
+
+import android.annotation.CheckResult;
+import android.content.pm.ApplicationInfo;
+
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.AndroidPackage;
+
+public class AppInfoUtils {
+
+ /**
+ * @see ApplicationInfo#flags
+ */
+ public static int appInfoFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isExternalStorage(), ApplicationInfo.FLAG_EXTERNAL_STORAGE)
+ | flag(pkg.isHardwareAccelerated(), ApplicationInfo.FLAG_HARDWARE_ACCELERATED)
+ | flag(pkg.isBackupAllowed(), ApplicationInfo.FLAG_ALLOW_BACKUP)
+ | flag(pkg.isKillAfterRestoreAllowed(), ApplicationInfo.FLAG_KILL_AFTER_RESTORE)
+ | flag(pkg.isRestoreAnyVersion(), ApplicationInfo.FLAG_RESTORE_ANY_VERSION)
+ | flag(pkg.isFullBackupOnly(), ApplicationInfo.FLAG_FULL_BACKUP_ONLY)
+ | flag(pkg.isPersistent(), ApplicationInfo.FLAG_PERSISTENT)
+ | flag(pkg.isDebuggable(), ApplicationInfo.FLAG_DEBUGGABLE)
+ | flag(pkg.isVmSafeMode(), ApplicationInfo.FLAG_VM_SAFE_MODE)
+ | flag(pkg.isDeclaredHavingCode(), ApplicationInfo.FLAG_HAS_CODE)
+ | flag(pkg.isTaskReparentingAllowed(), ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
+ | flag(pkg.isClearUserDataAllowed(), ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA)
+ | flag(pkg.isLargeHeap(), ApplicationInfo.FLAG_LARGE_HEAP)
+ | flag(pkg.isCleartextTrafficAllowed(), ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC)
+ | flag(pkg.isRtlSupported(), ApplicationInfo.FLAG_SUPPORTS_RTL)
+ | flag(pkg.isTestOnly(), ApplicationInfo.FLAG_TEST_ONLY)
+ | flag(pkg.isMultiArch(), ApplicationInfo.FLAG_MULTIARCH)
+ | flag(pkg.isExtractNativeLibrariesRequested(), ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS)
+ | flag(pkg.isGame(), ApplicationInfo.FLAG_IS_GAME)
+ | flag(pkg.isSmallScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS)
+ | flag(pkg.isNormalScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS)
+ | flag(pkg.isLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS)
+ | flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
+ | flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
+ | flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ /** @see ApplicationInfo#privateFlags */
+ public static int appInfoPrivateFlags(AndroidPackage pkg) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isStaticSharedLibrary(), ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY)
+ | flag(pkg.isResourceOverlay(), ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY)
+ | flag(pkg.isIsolatedSplitLoading(), ApplicationInfo.PRIVATE_FLAG_ISOLATED_SPLIT_LOADING)
+ | flag(pkg.isHasDomainUrls(), ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS)
+ | flag(pkg.isProfileableByShell(), ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL)
+ | flag(pkg.isBackupInForeground(), ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND)
+ | flag(pkg.isUseEmbeddedDex(), ApplicationInfo.PRIVATE_FLAG_USE_EMBEDDED_DEX)
+ | flag(pkg.isDefaultToDeviceProtectedStorage(), ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE)
+ | flag(pkg.isDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE)
+ | flag(pkg.isPartiallyDirectBootAware(), ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE)
+ | flag(pkg.isClearUserDataOnFailedRestoreAllowed(), ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE)
+ | flag(pkg.isAllowAudioPlaybackCapture(), ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE)
+ | flag(pkg.isRequestLegacyExternalStorage(), ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE)
+ | flag(pkg.isNonSdkApiRequested(), ApplicationInfo.PRIVATE_FLAG_USES_NON_SDK_API)
+ | flag(pkg.isUserDataFragile(), ApplicationInfo.PRIVATE_FLAG_HAS_FRAGILE_USER_DATA)
+ | flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
+ | flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
+ | flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
+
+ Boolean resizeableActivity = pkg.getResizeableActivity();
+ if (resizeableActivity != null) {
+ if (resizeableActivity) {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
+ } else {
+ pkgWithoutStateFlags |= ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
+ }
+ }
+
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+
+ /** @see ApplicationInfo#privateFlagsExt */
+ public static int appInfoPrivateFlagsExt(AndroidPackage pkg,
+ boolean isAllowlistedForHiddenApis) {
+ // @formatter:off
+ int pkgWithoutStateFlags = flag(pkg.isProfileable(), ApplicationInfo.PRIVATE_FLAG_EXT_PROFILEABLE)
+ | flag(pkg.hasRequestForegroundServiceExemption(), ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
+ | flag(pkg.isAttributionsUserVisible(), ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+ | flag(pkg.isOnBackInvokedCallbackEnabled(), ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)
+ | flag(isAllowlistedForHiddenApis, ApplicationInfo.PRIVATE_FLAG_EXT_ALLOWLISTED_FOR_HIDDEN_APIS);
+ return pkgWithoutStateFlags;
+ // @formatter:on
+ }
+
+ @CheckResult
+ private static int flag(boolean hasFlag, int flag) {
+ return hasFlag ? flag : 0;
+ }
+}
diff --git a/core/java/com/android/internal/pm/parsing/PackageParserException.java b/core/java/com/android/internal/pm/parsing/PackageParserException.java
new file mode 100644
index 0000000..4250bbd
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/PackageParserException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.internal.pm.parsing;
+
+public class PackageParserException extends Exception {
+ public final int error;
+
+ public PackageParserException(int error, String detailMessage) {
+ super(detailMessage);
+ this.error = error;
+ }
+
+ public PackageParserException(int error, String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ this.error = error;
+ }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
new file mode 100644
index 0000000..e65f1c9
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/pkg/AndroidPackageLegacyUtils.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2023 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.internal.pm.parsing.pkg;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+
+import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.server.pm.pkg.AndroidPackage;
+
+/** @hide */
+public class AndroidPackageLegacyUtils {
+
+ private AndroidPackageLegacyUtils() {
+ }
+
+ /**
+ * Returns the primary ABI as parsed from the package. Used only during parsing and derivation.
+ * Otherwise prefer {@link PackageState#getPrimaryCpuAbi()}.
+ */
+ public static String getRawPrimaryCpuAbi(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getPrimaryCpuAbi();
+ }
+
+ /**
+ * Returns the secondary ABI as parsed from the package. Used only during parsing and
+ * derivation. Otherwise prefer {@link PackageState#getSecondaryCpuAbi()}.
+ */
+ public static String getRawSecondaryCpuAbi(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi();
+ }
+
+ @Deprecated
+ @NonNull
+ public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
+ }
+
+ /**
+ * Replacement of unnecessary legacy getRealPackage. Only returns a value if the package was
+ * actually renamed.
+ */
+ @Nullable
+ public static String getRealPackageOrNull(@NonNull AndroidPackage pkg, boolean isSystem) {
+ if (pkg.getOriginalPackages().isEmpty() || !isSystem) {
+ return null;
+ }
+
+ return pkg.getManifestPackageName();
+ }
+
+ public static void fillVersionCodes(@NonNull AndroidPackage pkg, @NonNull PackageInfo info) {
+ info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
+ info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystem}
+ */
+ @Deprecated
+ public static boolean isSystem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isSystemExt}
+ */
+ @Deprecated
+ public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isSystemExt();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isPrivileged}
+ */
+ @Deprecated
+ public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isPrivileged();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOem}
+ */
+ @Deprecated
+ public static boolean isOem(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOem();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isVendor}
+ */
+ @Deprecated
+ public static boolean isVendor(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isVendor();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isProduct}
+ */
+ @Deprecated
+ public static boolean isProduct(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isProduct();
+ }
+
+ /**
+ * @deprecated Use {@link PackageState#isOdm}
+ */
+ @Deprecated
+ public static boolean isOdm(@NonNull AndroidPackage pkg) {
+ return ((AndroidPackageHidden) pkg).isOdm();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
similarity index 98%
rename from services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
rename to core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index da58d47..f7e1f72 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.parsing.pkg;
+package com.android.internal.pm.parsing.pkg;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
@@ -50,47 +50,44 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
-import com.android.internal.pm.parsing.pkg.AndroidPackageInternal;
-import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.parsing.AppInfoUtils;
import com.android.internal.pm.pkg.AndroidPackageSplitImpl;
+import com.android.internal.pm.pkg.SEInfoUtil;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageSplit;
-import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl;
-import com.android.server.pm.pkg.component.ParsedAttributionImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import libcore.util.EmptyArray;
@@ -422,8 +419,10 @@
@NonNull
public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
- @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
+ @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
+ return new PackageImpl(
+ packageName, baseCodePath, codePath, manifestArray, isCoreApp, callback);
}
/**
@@ -453,7 +452,7 @@
@NonNull
@VisibleForTesting
public static ParsingPackage forTesting(String packageName, String baseCodePath) {
- return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
+ return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false, null);
}
@NonNull
@@ -2694,12 +2693,16 @@
private String mBaseAppDataCredentialProtectedDirForSystemUser;
private String mBaseAppDataDeviceProtectedDirForSystemUser;
+ ParsingPackageUtils.Callback mCallback;
+
@VisibleForTesting
public PackageImpl(@NonNull String packageName, @NonNull String baseApkPath,
- @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp) {
+ @NonNull String path, @Nullable TypedArray manifestArray, boolean isCoreApp,
+ @Nullable ParsingPackageUtils.Callback callback) {
this.packageName = TextUtils.safeIntern(packageName);
this.mBaseApkPath = baseApkPath;
this.mPath = path;
+ this.mCallback = callback;
if (manifestArray != null) {
versionCode = manifestArray.getInteger(R.styleable.AndroidManifest_versionCode, 0);
@@ -2750,9 +2753,11 @@
}
private void assignDerivedFields2() {
- mBaseAppInfoFlags = PackageInfoUtils.appInfoFlags(this, null);
- mBaseAppInfoPrivateFlags = PackageInfoUtils.appInfoPrivateFlags(this, null);
- mBaseAppInfoPrivateFlagsExt = PackageInfoUtils.appInfoPrivateFlagsExt(this, null);
+ mBaseAppInfoFlags = AppInfoUtils.appInfoFlags(this);
+ mBaseAppInfoPrivateFlags = AppInfoUtils.appInfoPrivateFlags(this);
+ mBaseAppInfoPrivateFlagsExt = AppInfoUtils.appInfoPrivateFlagsExt(this,
+ mCallback == null ? false :
+ mCallback.getHiddenApiWhitelistedApps().contains(this.packageName));
String baseAppDataDir = Environment.getDataDirectoryPath(getVolumeUuid()) + File.separator;
String systemUserSuffix = File.separator + UserHandle.USER_SYSTEM + File.separator;
mBaseAppDataCredentialProtectedDirForSystemUser = TextUtils.safeIntern(
@@ -3087,7 +3092,7 @@
appInfo.primaryCpuAbi = primaryCpuAbi;
appInfo.secondaryCpuAbi = secondaryCpuAbi;
appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
- appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR;
+ appInfo.seInfoUser = SEInfoUtil.COMPLETE_STR;
appInfo.uid = uid;
return appInfo;
}
diff --git a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
similarity index 85%
rename from services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
rename to core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
index d962505..a670c6d 100644
--- a/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
+++ b/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.permission;
+package com.android.internal.pm.permission;
import android.Manifest;
import android.annotation.NonNull;
@@ -67,7 +67,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -97,10 +97,10 @@
}
@DataClass.Generated(
- time = 1627674427184L,
+ time = 1701338392152L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final android.content.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/permission/CompatibilityPermissionInfo.java",
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mName\nprivate final int mSdkVersion\npublic static final com.android.internal.pm.permission.CompatibilityPermissionInfo[] COMPAT_PERMS\nclass CompatibilityPermissionInfo extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genGetters=true, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/com/android/internal/pm/pkg/SEInfoUtil.java b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
new file mode 100644
index 0000000..a698882
--- /dev/null
+++ b/core/java/com/android/internal/pm/pkg/SEInfoUtil.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.internal.pm.pkg;
+
+/**
+ * Utility methods that need to be used in application space.
+ * @hide
+ */
+public final class SEInfoUtil {
+
+ /** Append to existing seinfo label for instant apps @hide */
+ public static final String INSTANT_APP_STR = ":ephemeralapp";
+
+ /** Append to existing seinfo when modifications are complete @hide */
+ public static final String COMPLETE_STR = ":complete";
+}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
similarity index 88%
rename from services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
index 1964df0..fd5f0f0 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentMutateUtils.java
@@ -14,19 +14,11 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.pm.pkg.component.ParsedActivity;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
-import com.android.internal.pm.pkg.component.ParsedProcess;
-import com.android.internal.pm.pkg.component.ParsedProvider;
-
/**
* Contains mutation methods so that code doesn't have to cast to the Impl. Meant to eventually
* be removed once all post-parsing mutation is moved to parsing.
diff --git a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
similarity index 85%
rename from services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
index 019ca13..db08005 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ComponentParseUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.AttrRes;
import android.annotation.NonNull;
@@ -29,14 +29,9 @@
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.PackageUserState;
-import com.android.server.pm.pkg.PackageUserStateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -173,16 +168,4 @@
public static int getIcon(ParsedComponent component) {
return component.getIcon();
}
-
- public static boolean isMatch(PackageUserState state, boolean isSystem,
- boolean isPackageEnabled, ParsedMainComponent component, long flags) {
- return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
- component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
- }
-
- public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
- ParsedMainComponent parsedComponent, long flags) {
- return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
- parsedComponent.getName(), flags);
- }
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
similarity index 94%
rename from services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
rename to core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
index dd54cfc..0b04591 100644
--- a/services/core/java/com/android/server/pm/pkg/component/InstallConstraintsTagParser.java
+++ b/core/java/com/android/internal/pm/pkg/component/InstallConstraintsTagParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.content.pm.parsing.result.ParseInput;
@@ -27,7 +27,6 @@
import com.android.internal.R;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.SystemConfig;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -48,9 +47,8 @@
* @hide
*/
public static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- Set<String> allowlist = SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser,
+ Set<String> allowlist) throws XmlPullParserException, IOException {
if (!allowlist.contains(pkg.getPackageName())) {
return input.skip("install-constraints cannot be used by this package");
}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
similarity index 92%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
index f027901..2f977ee 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
@@ -22,8 +22,8 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForStringSet;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForStringSet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,10 +36,9 @@
import android.text.TextUtils;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import java.util.Collections;
import java.util.Locale;
@@ -380,7 +379,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -696,10 +695,10 @@
}
@DataClass.Generated(
- time = 1669437519576L,
+ time = 1701338377709L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
- inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedActivityImpl.java",
+ inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedActivityImpl> CREATOR\npublic static @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.internal.pm.pkg.component.ParsedActivity)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
similarity index 98%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
index 64985bd..c3f7dab 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedActivityUtils.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -48,11 +48,10 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
similarity index 95%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
index cfed19a..27f7eee 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
@@ -22,7 +22,6 @@
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -60,7 +59,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -248,9 +247,9 @@
};
@DataClass.Generated(
- time = 1643723578605L,
+ time = 1701710844088L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java",
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceImpl.java",
inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedApexSystemService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
similarity index 95%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
index d3fb29b..c69213f 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedApexSystemServiceUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.R;
import android.annotation.NonNull;
@@ -25,8 +25,6 @@
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
-import com.android.internal.pm.pkg.component.ParsedApexSystemService;
-
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
similarity index 91%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
index 62b9947..e3bfb38 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.StringRes;
@@ -22,7 +22,6 @@
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.util.DataClass;
import java.util.ArrayList;
@@ -60,7 +59,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -207,10 +206,10 @@
};
@DataClass.Generated(
- time = 1641431950829L,
+ time = 1701338881658L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java",
- inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedAttributionImpl.java",
+ inputSignatures = "static final int MAX_NUM_ATTRIBUTIONS\nprivate @android.annotation.NonNull java.lang.String tag\nprivate @android.annotation.StringRes int label\nprivate @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\nclass ParsedAttributionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedAttribution, android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false, genSetters=true, genBuilder=false, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
similarity index 97%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
index 411220a..ee5c320 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedAttributionUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedAttribution;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
similarity index 82%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
index 512e5c7..7ee22f3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import static java.util.Collections.emptyMap;
@@ -32,12 +32,10 @@
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedComponent;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.util.ArrayList;
import java.util.Collections;
@@ -200,7 +198,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -306,10 +304,10 @@
}
@DataClass.Generated(
- time = 1641414207885L,
+ time = 1701445673589L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java",
- inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<android.content.pm.parsing.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\n void addIntent(android.content.pm.parsing.component.ParsedIntentInfoImpl)\n void addProperty(android.content.pm.PackageManager.Property)\npublic android.content.pm.parsing.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<android.content.pm.parsing.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedComponentImpl.java",
+ inputSignatures = "private @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String name\nprivate int icon\nprivate int labelRes\nprivate @android.annotation.Nullable java.lang.CharSequence nonLocalizedLabel\nprivate int logo\nprivate int banner\nprivate int descriptionRes\nprivate int flags\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String packageName\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"intent\") java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfoImpl> intents\nprivate @android.annotation.Nullable android.content.ComponentName componentName\nprivate @android.annotation.Nullable android.os.Bundle metaData\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.PackageManager.Property> mProperties\npublic void addIntent(com.android.internal.pm.pkg.component.ParsedIntentInfoImpl)\npublic void addProperty(android.content.pm.PackageManager.Property)\npublic com.android.internal.pm.pkg.component.ParsedComponentImpl setName(java.lang.String)\npublic @android.annotation.CallSuper void setPackageName(java.lang.String)\npublic @java.lang.Override @android.annotation.NonNull android.content.ComponentName getComponentName()\npublic @android.annotation.NonNull @java.lang.Override android.os.Bundle getMetaData()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.internal.pm.pkg.component.ParsedIntentInfo> getIntents()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedComponentImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genConstructor=false, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
similarity index 94%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
index 9322cf0..9e2548b 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
@@ -32,8 +32,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
/** @hide */
class ParsedComponentUtils {
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
similarity index 82%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
index 7bfad14..07322e9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +26,6 @@
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -112,7 +111,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -166,10 +165,10 @@
}
@DataClass.Generated(
- time = 1641431951575L,
+ time = 1701445763455L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedInstrumentationImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic android.content.pm.parsing.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetPackage\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetProcesses\nprivate boolean handleProfiling\nprivate boolean functionalTest\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedInstrumentationImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetPackage(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedInstrumentationImpl setTargetProcesses(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedInstrumentationImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedInstrumentation, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
similarity index 94%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
index a711694..661c8b4 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedInstrumentationUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.parsing.result.ParseInput;
@@ -26,7 +26,6 @@
import android.content.res.XmlResourceParser;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
similarity index 89%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
index ab94043..adb49e9 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -23,7 +23,6 @@
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.util.DataClass;
/**
@@ -54,7 +53,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -170,10 +169,10 @@
};
@DataClass.Generated(
- time = 1641431952314L,
+ time = 1701445800363L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java",
- inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoImpl.java",
+ inputSignatures = "private boolean mHasDefault\nprivate int mLabelRes\nprivate @android.annotation.Nullable java.lang.CharSequence mNonLocalizedLabel\nprivate int mIcon\nprivate @android.annotation.NonNull android.content.IntentFilter mIntentFilter\nclass ParsedIntentInfoImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedIntentInfo, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false, genConstructor=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
similarity index 96%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index e5e214d..c6683cf 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import android.annotation.NonNull;
import android.content.Intent;
@@ -31,10 +31,9 @@
import android.util.TypedValue;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
similarity index 85%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
index f322eef..bb8f565 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -25,7 +25,6 @@
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -133,7 +132,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -227,10 +226,10 @@
}
@DataClass.Generated(
- time = 1641414540422L,
+ time = 1701447884766L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedMainComponentImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentImpl.java",
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String processName\nprivate boolean directBootAware\nprivate boolean enabled\nprivate boolean exported\nprivate int order\nprivate @android.annotation.Nullable java.lang.String splitName\nprivate @android.annotation.Nullable java.lang.String[] attributionTags\npublic static final android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedMainComponentImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponentImpl setProcessName(java.lang.String)\npublic java.lang.String getClassName()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getAttributionTags()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedMainComponentImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedMainComponent, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
similarity index 95%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
index 8268f0f..7e56180 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedMainComponentUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,8 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
similarity index 85%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
index afe37bc..3622019 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
/**
@@ -75,7 +74,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -172,10 +171,10 @@
};
@DataClass.Generated(
- time = 1642132854167L,
+ time = 1701445837884L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java",
- inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override @com.android.internal.util.DataClass.Generated.Member void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.server.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionGroupImpl.java",
+ inputSignatures = "private int requestDetailRes\nprivate int backgroundRequestRes\nprivate int backgroundRequestDetailRes\nprivate int requestRes\nprivate int priority\npublic java.lang.String toString()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionGroupImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermissionGroup, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
similarity index 77%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
index 69e33c8..4dcce131 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,8 +24,6 @@
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -148,7 +146,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -162,7 +160,7 @@
int requestRes,
int protectionLevel,
boolean tree,
- @Nullable ParsedPermissionGroupImpl parsedPermissionGroup,
+ @Nullable ParsedPermissionGroup parsedPermissionGroup,
@Nullable Set<String> knownCerts) {
this.backgroundPermission = backgroundPermission;
this.group = group;
@@ -237,10 +235,10 @@
}
@DataClass.Generated(
- time = 1641414649731L,
+ time = 1701445829812L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java",
- inputSignatures = "private static com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable android.content.pm.parsing.component.ParsedPermissionGroupImpl parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedPermissionImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic android.content.pm.parsing.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends android.content.pm.parsing.component.ParsedComponentImpl implements [android.content.pm.parsing.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedPermissionImpl.java",
+ inputSignatures = "private static final com.android.internal.util.Parcelling.BuiltIn.ForStringSet sForStringSet\nprivate @android.annotation.Nullable java.lang.String backgroundPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String group\nprivate int requestRes\nprivate int protectionLevel\nprivate boolean tree\nprivate @android.annotation.Nullable com.android.internal.pm.pkg.component.ParsedPermissionGroup parsedPermissionGroup\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> knownCerts\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedPermissionImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedPermissionGroup getParsedPermissionGroup()\npublic com.android.internal.pm.pkg.component.ParsedPermissionImpl setGroup(java.lang.String)\nprotected void setKnownCert(java.lang.String)\nprotected void setKnownCerts(java.lang.String[])\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownCerts()\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedPermissionImpl extends com.android.internal.pm.pkg.component.ParsedComponentImpl implements [com.android.internal.pm.pkg.component.ParsedPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
similarity index 97%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
index 4b45d37..5651c1c 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedPermissionUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PermissionInfo;
@@ -31,10 +31,8 @@
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedPermission;
-import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
similarity index 93%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
index 40e3670..212fb86 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import static java.util.Collections.emptySet;
@@ -25,7 +25,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -98,7 +97,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -304,10 +303,10 @@
};
@DataClass.Generated(
- time = 1641431953775L,
+ time = 1701445656489L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java",
- inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedProcessImpl.java",
+ inputSignatures = "private @android.annotation.NonNull java.lang.String name\nprivate @android.annotation.NonNull android.util.ArrayMap<java.lang.String,java.lang.String> appClassNamesByPackage\nprivate @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprivate @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nprivate @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\nprivate @android.content.pm.ApplicationInfo.NativeHeapZeroInitialized int nativeHeapZeroInitialized\npublic void addStateFrom(com.android.internal.pm.pkg.component.ParsedProcess)\npublic void putAppClassNameForPackage(java.lang.String,java.lang.String)\nclass ParsedProcessImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedProcess, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genParcelable=true, genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
similarity index 97%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
index a849549..3b2056e 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProcessUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
@@ -27,11 +27,10 @@
import android.util.ArraySet;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
similarity index 90%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
index 81a3c17..987fd41 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,7 +28,6 @@
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -302,7 +301,7 @@
time = 1642560323360L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java",
- inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ inputSignatures = "private @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String authority\nprivate boolean syncable\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String readPermission\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String writePermission\nprivate boolean grantUriPermissions\nprivate boolean forceUriPermissions\nprivate boolean multiProcess\nprivate int initOrder\nprivate @android.annotation.NonNull java.util.List<android.os.PatternMatcher> uriPermissionPatterns\nprivate @android.annotation.NonNull java.util.List<android.content.pm.PathPermission> pathPermissions\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedProviderImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setReadPermission(java.lang.String)\npublic com.android.internal.pm.pkg.component.ParsedProviderImpl setWritePermission(java.lang.String)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addUriPermissionPattern(android.os.PatternMatcher)\npublic @android.annotation.NonNull com.android.internal.pm.pkg.component.ParsedProviderImpl addPathPermission(android.content.pm.PathPermission)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedProviderImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedProvider, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
similarity index 97%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
index 0b28a12..5d82d04 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,9 +34,8 @@
import android.util.Slog;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
similarity index 80%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
index ca8c45d..f4662d8 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.parsing.pkg.PackageImpl.sForInternedString;
+import static com.android.internal.pm.parsing.pkg.PackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,8 +26,6 @@
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedMainComponent;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
@@ -107,7 +105,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -141,10 +139,10 @@
}
@DataClass.Generated(
- time = 1641431954479L,
+ time = 1701445638370L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java",
- inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedServiceImpl> CREATOR\npublic android.content.pm.parsing.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedServiceImpl.java",
+ inputSignatures = "private int foregroundServiceType\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.internal.pm.pkg.component.ParsedServiceImpl> CREATOR\npublic com.android.internal.pm.pkg.component.ParsedMainComponent setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedServiceImpl extends com.android.internal.pm.pkg.component.ParsedMainComponentImpl implements [com.android.internal.pm.pkg.component.ParsedService, android.os.Parcelable]\n@com.android.internal.util.DataClass(genSetters=true, genGetters=true, genParcelable=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
similarity index 96%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
index 171ef59..a1dd19a3 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
-import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
+import static com.android.internal.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,9 +32,8 @@
import android.os.Build;
import com.android.internal.R;
-import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
similarity index 87%
rename from services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
rename to core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
index 78377a8..fd131df 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.component;
+package com.android.internal.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.pm.pkg.component.ParsedUsesPermission;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling;
@@ -51,7 +50,7 @@
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -158,10 +157,10 @@
};
@DataClass.Generated(
- time = 1641431955242L,
+ time = 1701445626268L,
codegenVersion = "1.0.23",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @android.content.pm.parsing.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
+ sourceFile = "frameworks/base/core/java/com/android/internal/pm/pkg/component/ParsedUsesPermissionImpl.java",
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.pm.pkg.component.ParsedUsesPermission.UsesPermissionFlags int usesPermissionFlags\nclass ParsedUsesPermissionImpl extends java.lang.Object implements [com.android.internal.pm.pkg.component.ParsedUsesPermission, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=true, genAidl=false)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
similarity index 97%
rename from services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
rename to core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index aa0fb27..dbe4fba 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -30,7 +30,7 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
+import static com.android.internal.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.AnyRes;
import android.annotation.CheckResult;
@@ -57,7 +57,6 @@
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -90,43 +89,40 @@
import com.android.internal.R;
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
+import com.android.internal.pm.pkg.component.InstallConstraintsTagParser;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceUtils;
import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedAttributionUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationUtils;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoUtils;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderUtils;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceUtils;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.internal.pm.split.DefaultSplitAssetLoader;
+import com.android.internal.pm.split.SplitAssetDependencyLoader;
+import com.android.internal.pm.split.SplitAssetLoader;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.SharedUidMigration;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.component.InstallConstraintsTagParser;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils;
-import com.android.server.pm.pkg.component.ParsedAttributionUtils;
-import com.android.server.pm.pkg.component.ParsedInstrumentationUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProcessUtils;
-import com.android.server.pm.pkg.component.ParsedProviderUtils;
-import com.android.server.pm.pkg.component.ParsedServiceUtils;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
-import com.android.server.pm.split.DefaultSplitAssetLoader;
-import com.android.server.pm.split.SplitAssetDependencyLoader;
-import com.android.server.pm.split.SplitAssetLoader;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -267,18 +263,6 @@
public @interface ParseFlags {}
/**
- * @see #parseDefault(ParseInput, File, int, List, boolean)
- */
- @NonNull
- public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
- @ParseFlags int parseFlags,
- @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
- return parseDefault(input, file, parseFlags, splitPermissions, collectCertificates);
- }
-
- /**
* For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
* request, without caching the input object and without querying the internal system state for
* feature support.
@@ -287,30 +271,10 @@
public static ParseResult<ParsedPackage> parseDefault(ParseInput input, File file,
@ParseFlags int parseFlags,
@NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
- boolean collectCertificates) {
- ParseResult<ParsedPackage> result;
+ boolean collectCertificates, Callback callback) {
ParsingPackageUtils parser = new ParsingPackageUtils(null /*separateProcesses*/,
- null /*displayMetrics*/, splitPermissions, new Callback() {
- @Override
- public boolean hasFeature(String feature) {
- // Assume the device doesn't support anything. This will affect permission
- // parsing and will force <uses-permission/> declarations to include all
- // requiredNotFeature permissions and exclude all requiredFeature
- // permissions. This mirrors the old behavior.
- return false;
- }
-
- @Override
- public ParsingPackage startParsingPackage(
- @NonNull String packageName,
- @NonNull String baseApkPath,
- @NonNull String path,
- @NonNull TypedArray manifestArray, boolean isCoreApp) {
- return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
- isCoreApp);
- }
- });
+ null /*displayMetrics*/, splitPermissions, callback);
var parseResult = parser.parsePackage(input, file, parseFlags);
if (parseResult.isError()) {
return input.error(parseResult);
@@ -1146,7 +1110,8 @@
case TAG_RESTRICT_UPDATE:
return parseRestrictUpdateHash(flags, input, pkg, res, parser);
case TAG_INSTALL_CONSTRAINTS:
- return parseInstallConstraints(input, pkg, res, parser);
+ return parseInstallConstraints(input, pkg, res, parser,
+ mCallback.getInstallConstraintsAllowlist());
case TAG_QUERIES:
return parseQueries(input, pkg, res, parser);
default:
@@ -1172,7 +1137,7 @@
}
boolean leaving = false;
- if (!SharedUidMigration.isDisabled()) {
+ if (PackageManager.ENABLE_SHARED_UID_MIGRATION) {
int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT);
}
@@ -1858,10 +1823,11 @@
return input.success(pkg);
}
- private static ParseResult<ParsingPackage> parseInstallConstraints(
- ParseInput input, ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ private static ParseResult<ParsingPackage> parseInstallConstraints(ParseInput input,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, Set<String> allowlist)
throws IOException, XmlPullParserException {
- return InstallConstraintsTagParser.parseInstallConstraints(input, pkg, res, parser);
+ return InstallConstraintsTagParser.parseInstallConstraints(
+ input, pkg, res, parser, allowlist);
}
private static ParseResult<ParsingPackage> parseQueries(ParseInput input, ParsingPackage pkg,
@@ -3485,5 +3451,9 @@
ParsingPackage startParsingPackage(@NonNull String packageName,
@NonNull String baseApkPath, @NonNull String path,
@NonNull TypedArray manifestArray, boolean isCoreApp);
+
+ @NonNull Set<String> getHiddenApiWhitelistedApps();
+
+ @NonNull Set<String> getInstallConstraintsAllowlist();
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
similarity index 95%
rename from services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
rename to core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
index 1d15955..26822c6 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.pm.pkg.parsing;
+package com.android.internal.pm.pkg.parsing;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -31,10 +31,9 @@
import android.util.Slog;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
-import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.util.Parcelling;
import com.android.internal.util.XmlUtils;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
similarity index 94%
rename from services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
rename to core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
index 0bb969f..50c6243 100644
--- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/DefaultSplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
@@ -21,9 +21,9 @@
import android.content.res.AssetManager;
import android.os.Build;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import com.android.internal.util.ArrayUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
similarity index 96%
rename from services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
rename to core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
index 56d92fb..c166cdc 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetDependencyLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.annotation.NonNull;
import android.content.pm.parsing.ApkLiteParseUtils;
@@ -24,8 +24,8 @@
import android.os.Build;
import android.util.SparseArray;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
similarity index 96%
rename from services/core/java/com/android/server/pm/split/SplitAssetLoader.java
rename to core/java/com/android/internal/pm/split/SplitAssetLoader.java
index 8450159..c7c409d 100644
--- a/services/core/java/com/android/server/pm/split/SplitAssetLoader.java
+++ b/core/java/com/android/internal/pm/split/SplitAssetLoader.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.pm.split;
+package com.android.internal.pm.split;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
diff --git a/core/java/com/android/server/pm/pkg/AndroidPackage.java b/core/java/com/android/server/pm/pkg/AndroidPackage.java
index f86595f..adb0c69 100644
--- a/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -58,6 +58,7 @@
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import java.security.PublicKey;
import java.util.List;
@@ -690,7 +691,7 @@
/**
* The names of packages to adopt ownership of permissions from, parsed under {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
+ * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
*
* @see R.styleable#AndroidManifestOriginalPackage_name
* @hide
@@ -795,7 +796,7 @@
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestKeySet
* @see R.styleable#AndroidManifestPublicKey
@@ -1266,7 +1267,7 @@
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * com.android.server.pm.pkg.parsing.ParsingPackageUtils#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestUpgradeKeySet
* @hide
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
index ba2ea88..d629f6a 100644
--- a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -19,15 +19,20 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.google.common.base.Strings;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +43,9 @@
public class AutomaticZenRuleTest {
private static final String CLASS = "android.app.AutomaticZenRule";
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Test
public void testLongFields_inConstructor() {
String longString = Strings.repeat("A", 65536);
@@ -100,6 +108,7 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
public void testLongInputsFromParcel() {
// Create a rule with long fields, set directly via reflection so that we can confirm that
// a rule with too-long fields that comes in via a parcel has its fields truncated directly.
@@ -152,6 +161,60 @@
fromParcel.getOwner().getPackageName().length());
assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
fromParcel.getOwner().getClassName().length());
- assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, rule.getTriggerDescription().length());
+ assertEquals(AutomaticZenRule.MAX_DESC_LENGTH, fromParcel.getTriggerDescription().length());
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_builderWithValidType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri"))
+ .setType(AutomaticZenRule.TYPE_BEDTIME)
+ .build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_builderWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_constructorWithoutType_succeeds() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule("rule", new ComponentName("pkg", "cps"),
+ new ComponentName("pkg", "activity"), Uri.parse("condition"), null,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ rule.validate(); // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidType_throws() throws Exception {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ // Set the field via reflection.
+ Field typeField = AutomaticZenRule.class.getDeclaredField("mType");
+ typeField.setAccessible(true);
+ typeField.set(rule, 100);
+
+ assertThrows(IllegalArgumentException.class, rule::validate);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setType_invalidType_throws() {
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")).build();
+
+ assertThrows(IllegalArgumentException.class, () -> rule.setType(100));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void setTypeBuilder_invalidType_throws() {
+ AutomaticZenRule.Builder builder = new AutomaticZenRule.Builder("rule", Uri.parse("uri"));
+
+ assertThrows(IllegalArgumentException.class, () -> builder.setType(100));
}
}
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
index 612562e..e94273e 100644
--- a/core/tests/coretests/src/android/service/notification/ConditionTest.java
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -21,9 +21,12 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertThrows;
+
import android.app.Flags;
import android.net.Uri;
import android.os.Parcel;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -36,6 +39,7 @@
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -194,4 +198,59 @@
Condition fromParcel = new Condition(parcel);
assertThat(fromParcel).isEqualTo(cond);
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_unspecifiedSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_validSource_succeeds() {
+ new Condition(Uri.parse("id"), "Summary", Condition.STATE_TRUE, Condition.SOURCE_CONTEXT);
+ // No exception.
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_invalidSource_throws() {
+ assertThrows(IllegalArgumentException.class,
+ () -> new Condition(Uri.parse("uri"), "Summary", Condition.STATE_TRUE, 1000));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void constructor_parcelWithInvalidSource_throws() {
+ Condition original = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+ Parcel parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+
+ // Tweak the parcel to contain and invalid source value.
+ parcel.setDataPosition(parcel.dataPosition() - 8); // going back two int fields.
+ parcel.writeInt(100);
+ parcel.setDataPosition(0);
+
+ assertThrows(IllegalArgumentException.class, () -> new Condition(parcel));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void validate_invalidSource_throws() throws Exception {
+ Condition condition = new Condition(Uri.parse("condition"), "Summary", Condition.STATE_TRUE,
+ Condition.SOURCE_SCHEDULE);
+
+ Field typeField = Condition.class.getDeclaredField("source");
+
+ // Reflection on reflection (ugh) to make a final field non-final
+ Field fieldAccessFlagsField = Field.class.getDeclaredField("accessFlags");
+ fieldAccessFlagsField.setAccessible(true);
+ fieldAccessFlagsField.setInt(typeField, typeField.getModifiers() & ~Modifier.FINAL);
+
+ typeField.setInt(condition, 30);
+
+ assertThrows(IllegalArgumentException.class, condition::validate);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index c980906..8d8dc10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -49,6 +49,11 @@
@BackEvent.SwipeEdge int swipeEdge);
/**
+ * Called when the input pointers are pilfered.
+ */
+ void onPilferPointers();
+
+ /**
* Sets whether the back gesture is past the trigger threshold or not.
*/
void setTriggerBack(boolean triggerBack);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cf858dc..d8c691b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -111,6 +111,7 @@
/** Tracks if we should start the back gesture on the next motion move event */
private boolean mShouldStartOnNextMoveEvent = false;
+ private boolean mOnBackStartDispatched = false;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -304,6 +305,11 @@
}
@Override
+ public void onPilferPointers() {
+ BackAnimationController.this.onPilferPointers();
+ }
+
+ @Override
public void setTriggerBack(boolean triggerBack) {
mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack));
}
@@ -384,6 +390,16 @@
return null;
}
+ @VisibleForTesting
+ void onPilferPointers() {
+ mCurrentTracker.updateStartLocation();
+ // Dispatch onBackStarted, only to app callbacks.
+ // System callbacks will receive onBackStarted when the remote animation starts.
+ if (!shouldDispatchToAnimator()) {
+ tryDispatchOnBackStarted(mActiveCallback, mCurrentTracker.createStartEvent(null));
+ }
+ }
+
/**
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
@@ -483,12 +499,15 @@
mActiveCallback = mBackNavigationInfo.getOnBackInvokedCallback();
// App is handling back animation. Cancel system animation latency tracking.
cancelLatencyTracking();
- dispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
+ tryDispatchOnBackStarted(mActiveCallback, touchTracker.createStartEvent(null));
}
}
private void onMove() {
- if (!mBackGestureStarted || mBackNavigationInfo == null || mActiveCallback == null) {
+ if (!mBackGestureStarted
+ || mBackNavigationInfo == null
+ || mActiveCallback == null
+ || !mOnBackStartDispatched) {
return;
}
// Skip dispatching if the move corresponds to the queued instead of the current gesture
@@ -524,13 +543,14 @@
&& mBackNavigationInfo.isPrepareRemoteAnimation();
}
- private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
+ private void tryDispatchOnBackStarted(IOnBackInvokedCallback callback,
BackMotionEvent backEvent) {
- if (callback == null) {
+ if (callback == null || mOnBackStartDispatched) {
return;
}
try {
callback.onBackStarted(backEvent);
+ mOnBackStartDispatched = true;
} catch (RemoteException e) {
Log.e(TAG, "dispatchOnBackStarted error: ", e);
}
@@ -828,6 +848,8 @@
void finishBackNavigation(boolean triggerBack) {
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishBackNavigation()");
mActiveCallback = null;
+ mShouldStartOnNextMoveEvent = false;
+ mOnBackStartDispatched = false;
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
@@ -909,7 +931,8 @@
::onBackAnimationFinished));
if (apps.length >= 1) {
- dispatchOnBackStarted(
+ mCurrentTracker.updateStartLocation();
+ tryDispatchOnBackStarted(
mActiveCallback,
mCurrentTracker.createStartEvent(apps[0]));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 19eb928..4bd56d4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -104,6 +104,15 @@
mStartThresholdX = mInitTouchX;
}
+ /** Update the start location used to compute the progress
+ * to the latest touch location.
+ */
+ void updateStartLocation() {
+ mInitTouchX = mLatestTouchX;
+ mInitTouchY = mLatestTouchY;
+ mStartThresholdX = mInitTouchX;
+ }
+
void reset() {
mInitTouchX = 0;
mInitTouchY = 0;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index f5c01d0..4c47737 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -769,7 +769,6 @@
getSurfaceTransactionHelper().crop(tx, leash, destBounds);
}
if (mContentOverlay != null) {
- mContentOverlay.onAnimationEnd(tx, destBounds);
clearContentOverlay();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index a2bd47c..e11e859 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -67,15 +67,6 @@
public abstract void onAnimationUpdate(SurfaceControl.Transaction atomicTx,
Rect currentBounds, float fraction);
- /**
- * Callback when reaches the end of animation on the internal {@link #mLeash}.
- * @param atomicTx {@link SurfaceControl.Transaction} to operate, you should not explicitly
- * call apply on this transaction, it should be applied on the caller side.
- * @param destinationBounds {@link Rect} of the final bounds.
- */
- public abstract void onAnimationEnd(SurfaceControl.Transaction atomicTx,
- Rect destinationBounds);
-
/** A {@link PipContentOverlay} uses solid color. */
public static final class PipColorOverlay extends PipContentOverlay {
private static final String TAG = PipColorOverlay.class.getSimpleName();
@@ -107,11 +98,6 @@
atomicTx.setAlpha(mLeash, fraction < 0.5f ? 0 : (fraction - 0.5f) * 2);
}
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Color overlay should be fully opaque by now, ready for fade out.
- }
-
private float[] getContentOverlayColor(Context context) {
final TypedArray ta = context.obtainStyledAttributes(new int[] {
android.R.attr.colorBackground });
@@ -164,11 +150,6 @@
Rect currentBounds, float fraction) {
// Do nothing. Keep the snapshot till animation ends.
}
-
- @Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Snapshot overlay should be fully opaque by now, ready for fade out.
- }
}
/** A {@link PipContentOverlay} shows app icon on solid color background. */
@@ -255,11 +236,6 @@
}
@Override
- public void onAnimationEnd(SurfaceControl.Transaction atomicTx, Rect destinationBounds) {
- // Do nothing. Icon overlay should be fully opaque by now, ready for fade out.
- }
-
- @Override
public void detach(SurfaceControl.Transaction tx) {
super.detach(tx);
if (mBitmap != null && !mBitmap.isRecycled()) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 743b1ea..3635165 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -329,15 +329,7 @@
private @Surface.Rotation int mCurrentRotation;
/**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is true, only in gesture nav.
- */
- @Nullable
- SurfaceControl mSwipePipToHomeOverlay;
-
- /**
- * An optional overlay used to mask content changing between an app in/out of PiP, only set if
- * {@link PipTransitionState#getInSwipePipToHomeTransition()} is false.
+ * An optional overlay used to mask content changing between an app in/out of PiP.
*/
@Nullable
SurfaceControl mPipOverlay;
@@ -480,7 +472,7 @@
return;
}
mPipBoundsState.setBounds(destinationBounds);
- mSwipePipToHomeOverlay = overlay;
+ mPipOverlay = overlay;
if (ENABLE_SHELL_TRANSITIONS && overlay != null) {
// With Shell transition, the overlay was attached to the remote transition leash, which
// will be removed when the current transition is finished, so we need to reparent it
@@ -892,7 +884,7 @@
}
final Rect destinationBounds = mPipBoundsState.getBounds();
- final SurfaceControl swipeToHomeOverlay = mSwipePipToHomeOverlay;
+ final SurfaceControl swipeToHomeOverlay = mPipOverlay;
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper
.resetScale(tx, mLeash, destinationBounds)
@@ -911,7 +903,7 @@
}
}, tx);
mPipTransitionState.setInSwipePipToHomeTransition(false);
- mSwipePipToHomeOverlay = null;
+ mPipOverlay = null;
}
private void applyEnterPipSyncTransaction(Rect destinationBounds, Runnable runnable,
@@ -1126,9 +1118,9 @@
}
clearWaitForFixedRotation();
- if (mSwipePipToHomeOverlay != null) {
- removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
- mSwipePipToHomeOverlay = null;
+ if (mPipOverlay != null) {
+ removeContentOverlay(mPipOverlay, null /* callback */);
+ mPipOverlay = null;
}
resetShadowRadius();
mPipTransitionState.setInSwipePipToHomeTransition(false);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 0f3c162..f5f15d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -465,7 +465,7 @@
mSurfaceTransactionHelper.crop(tx, leash, destinationBounds)
.resetScale(tx, leash, destinationBounds)
.round(tx, leash, true /* applyCornerRadius */);
- if (mPipOrganizer.mSwipePipToHomeOverlay != null && !mInitBounds.isEmpty()) {
+ if (mPipOrganizer.mPipOverlay != null && !mInitBounds.isEmpty()) {
// Resetting the scale for pinned task while re-adjusting its crop,
// also scales the overlay. So we need to update the overlay leash too.
Rect overlayBounds = new Rect(destinationBounds);
@@ -476,7 +476,7 @@
(destinationBounds.width() - overlaySize) / 2,
(destinationBounds.height() - overlaySize) / 2);
mSurfaceTransactionHelper.resetScale(tx,
- mPipOrganizer.mSwipePipToHomeOverlay, overlayBounds);
+ mPipOrganizer.mPipOverlay, overlayBounds);
}
}
mInitBounds.setEmpty();
@@ -615,9 +615,9 @@
}
}
// if overlay is present remove it immediately, as exit transition came before it faded out
- if (mPipOrganizer.mSwipePipToHomeOverlay != null) {
- startTransaction.remove(mPipOrganizer.mSwipePipToHomeOverlay);
- clearSwipePipToHomeOverlay();
+ if (mPipOrganizer.mPipOverlay != null) {
+ startTransaction.remove(mPipOrganizer.mPipOverlay);
+ clearPipOverlay();
}
if (pipChange == null) {
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -1077,7 +1077,7 @@
if (mFixedRotationState == FIXED_ROTATION_CALLBACK && appBounds != null) {
mInitBounds.set(appBounds);
}
- final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
+ final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mPipOverlay;
if (swipePipToHomeOverlay != null) {
// Launcher fade in the overlay on top of the fullscreen Task. It is possible we
// reparent the PIP activity to a new PIP task (in case there are other activities
@@ -1106,7 +1106,7 @@
sendOnPipTransitionFinished(TRANSITION_DIRECTION_TO_PIP);
if (swipePipToHomeOverlay != null) {
mPipOrganizer.fadeOutAndRemoveOverlay(swipePipToHomeOverlay,
- this::clearSwipePipToHomeOverlay /* callback */, false /* withStartDelay */);
+ this::clearPipOverlay /* callback */, false /* withStartDelay */);
}
mPipTransitionState.setInSwipePipToHomeTransition(false);
}
@@ -1250,8 +1250,8 @@
mPipMenuController.updateMenuBounds(destinationBounds);
}
- private void clearSwipePipToHomeOverlay() {
- mPipOrganizer.mSwipePipToHomeOverlay = null;
+ private void clearPipOverlay() {
+ mPipOrganizer.mPipOverlay = null;
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 0367ba1..d023cea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -995,16 +995,10 @@
t.show(mOpeningTasks.get(i).mTaskSurface);
}
for (int i = 0; i < mPausingTasks.size(); ++i) {
- if (!sendUserLeaveHint && mPausingTasks.get(i).isLeaf()) {
- // This means recents is not *actually* finishing, so of course we gotta
- // do special stuff in WMCore to accommodate.
- wct.setDoNotPip(mPausingTasks.get(i).mToken);
- }
- // Since we will reparent out of the leashes, pre-emptively hide the child
- // surface to match the leash. Otherwise, there will be a flicker before the
- // visibility gets committed in Core when using split-screen (in splitscreen,
- // the leaf-tasks are not "independent" so aren't hidden by normal setup).
- t.hide(mPausingTasks.get(i).mTaskSurface);
+ cleanUpPausingOrClosingTask(mPausingTasks.get(i), wct, t, sendUserLeaveHint);
+ }
+ for (int i = 0; i < mClosingTasks.size(); ++i) {
+ cleanUpPausingOrClosingTask(mClosingTasks.get(i), wct, t, sendUserLeaveHint);
}
if (mPipTransaction != null && sendUserLeaveHint) {
SurfaceControl pipLeash = null;
@@ -1053,6 +1047,20 @@
}
}
+ private void cleanUpPausingOrClosingTask(TaskState task, WindowContainerTransaction wct,
+ SurfaceControl.Transaction finishTransaction, boolean sendUserLeaveHint) {
+ if (!sendUserLeaveHint && task.isLeaf()) {
+ // This means recents is not *actually* finishing, so of course we gotta
+ // do special stuff in WMCore to accommodate.
+ wct.setDoNotPip(task.mToken);
+ }
+ // Since we will reparent out of the leashes, pre-emptively hide the child
+ // surface to match the leash. Otherwise, there will be a flicker before the
+ // visibility gets committed in Core when using split-screen (in splitscreen,
+ // the leaf-tasks are not "independent" so aren't hidden by normal setup).
+ finishTransaction.hide(task.mTaskSurface);
+ }
+
@Override
public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 77427d9..96e57e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -223,6 +223,7 @@
private boolean mExitSplitScreenOnHide;
private boolean mIsDividerRemoteAnimating;
private boolean mIsDropEntering;
+ private boolean mSkipEvictingMainStageChildren;
private boolean mIsExiting;
private boolean mIsRootTranslucent;
@VisibleForTesting
@@ -468,6 +469,7 @@
}
// Due to drag already pip task entering split by this method so need to reset flag here.
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
return true;
}
@@ -572,6 +574,15 @@
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -600,6 +611,15 @@
return;
}
+ // Don't evict the main stage children as this can race and happen after the activity is
+ // started into that stage
+ if (!isSplitScreenVisible()) {
+ mSkipEvictingMainStageChildren = true;
+ // Starting the split task without evicting children will bring the single root task
+ // container forward, so ensure that we hide the divider before we start animate it
+ setDividerVisibility(false, null);
+ }
+
// If split screen is not activated, we're expecting to open a pair of apps to split.
final int extraTransitType = mMainStage.isActive()
? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN;
@@ -1618,7 +1638,7 @@
// Ensure to evict old splitting tasks because the new split pair might be composed by
// one of the splitting tasks, evicting the task when finishing entering transition
// won't guarantee to put the task to the indicated new position.
- if (!mIsDropEntering) {
+ if (!mSkipEvictingMainStageChildren) {
mMainStage.evictAllChildren(wct);
}
mMainStage.reparentTopTask(wct);
@@ -1680,6 +1700,7 @@
finishT.show(mRootTaskLeash);
setSplitsVisible(true);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
mSplitRequest = null;
updateRecentTasksSplitPair();
if (!mLogger.hasStartedSession()) {
@@ -1929,6 +1950,7 @@
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -2123,6 +2145,7 @@
if (mIsDropEntering) {
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
mIsDropEntering = false;
+ mSkipEvictingMainStageChildren = false;
} else {
mShowDecorImmediately = true;
mSplitLayout.flingDividerToCenter();
@@ -3245,6 +3268,7 @@
public void onDroppedToSplit(@SplitPosition int position, InstanceId dragSessionId) {
if (!isSplitScreenVisible()) {
mIsDropEntering = true;
+ mSkipEvictingMainStageChildren = true;
}
if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index e03f825..34c015f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -330,6 +330,11 @@
continue;
}
if (isHide) {
+ if (pending.mType == TRANSIT_TO_BACK) {
+ // TO_BACK is only used when setting the task view visibility immediately,
+ // so in that case we can also hide the surface immediately
+ startTransaction.hide(chg.getLeash());
+ }
tv.prepareHideAnimation(finishTransaction);
} else {
tv.prepareCloseAnimation();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 20ff79f..98d343b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -18,6 +18,7 @@
import static android.view.WindowManager.KEYGUARD_VISIBILITY_TRANSIT_FLAGS;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
@@ -245,23 +246,29 @@
public boolean shouldPlayUnfoldAnimation(@NonNull TransitionInfo transitionInfo) {
// Unfold animation won't play when animations are disabled
if (!ValueAnimator.areAnimatorsEnabled()) return false;
+ // Only handle transitions that are marked as physical display switch
+ // See PhysicalDisplaySwitchTransitionLauncher for the conditions
+ if ((transitionInfo.getFlags() & TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH) == 0) return false;
for (int i = 0; i < transitionInfo.getChanges().size(); i++) {
final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
- if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) != 0) {
- if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
- continue;
- }
+ // We are interested only in display container changes
+ if ((change.getFlags() & TransitionInfo.FLAG_IS_DISPLAY) == 0) {
+ continue;
+ }
- // Handle only unfolding, currently we don't have an animation when folding
- final int afterArea =
- change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
- final int beforeArea = change.getStartAbsBounds().width()
- * change.getStartAbsBounds().height();
+ // Handle only unfolding, currently we don't have an animation when folding
+ if (change.getEndAbsBounds() == null || change.getStartAbsBounds() == null) {
+ continue;
+ }
- if (afterArea > beforeArea) {
- return true;
- }
+ final int afterArea =
+ change.getEndAbsBounds().width() * change.getEndAbsBounds().height();
+ final int beforeArea = change.getStartAbsBounds().width()
+ * change.getStartAbsBounds().height();
+
+ if (afterArea > beforeArea) {
+ return true;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 0395a9b..771876f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -182,8 +182,7 @@
}
private void triggerBackGesture() {
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 0);
+ doStartEvents(0, 0);
mController.setTriggerBack(true);
}
@@ -244,10 +243,7 @@
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -270,10 +266,8 @@
/* enableAnimation = */ true,
/* isAnimationCallback = */ true);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -359,8 +353,7 @@
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -399,8 +392,7 @@
.injectInputEvent(any(KeyEvent.class), any(Integer.class));
// Verify that we start accepting gestures again once transition finishes.
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -427,8 +419,7 @@
mShellExecutor.flushAll();
reset(mAnimatorCallback);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
}
@@ -441,9 +432,7 @@
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
- // Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
verify(mAnimatorCallback).onBackStarted(any());
@@ -563,10 +552,8 @@
/* enableAnimation = */ true,
/* isAnimationCallback = */ false);
- doMotionEvent(MotionEvent.ACTION_DOWN, 0);
-
// Check that back start and progress is dispatched when first move.
- doMotionEvent(MotionEvent.ACTION_MOVE, 100);
+ doStartEvents(0, 100);
simulateRemoteAnimationStart();
@@ -593,6 +580,15 @@
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
+ /**
+ * Simulate event sequence that starts a back navigation.
+ */
+ private void doStartEvents(int startX, int moveX) {
+ doMotionEvent(MotionEvent.ACTION_DOWN, startX);
+ mController.onPilferPointers();
+ doMotionEvent(MotionEvent.ACTION_MOVE, moveX);
+ }
+
private void simulateRemoteAnimationStart() throws RemoteException {
RemoteAnimationTarget animationTarget = createAnimationTarget();
RemoteAnimationTarget[] targets = new RemoteAnimationTarget[]{animationTarget};
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
index fc1fe1c..c5e229f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java
@@ -18,12 +18,11 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static android.view.WindowManager.TRANSIT_NONE;
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -40,22 +39,17 @@
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
-import com.android.window.flags.FakeFeatureFlagsImpl;
-import com.android.window.flags.FeatureFlags;
-import com.android.window.flags.Flags;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.TransitionInfoBuilder;
+import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.transition.Transitions.TransitionFinishCallback;
import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.List;
@@ -196,6 +190,22 @@
}
@Test
+ public void startAnimation_differentTransitionFromRequestWithResize_doesNotStartAnimation() {
+ mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
+ TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
+
+ boolean animationStarted = mUnfoldTransitionHandler.startAnimation(
+ mTransition,
+ createDisplayResizeTransitionInfo(),
+ mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class),
+ finishCallback
+ );
+
+ assertThat(animationStarted).isFalse();
+ }
+
+ @Test
public void startAnimation_differentTransitionFromRequestWithoutUnfold_doesNotStart() {
mUnfoldTransitionHandler.handleRequest(new Binder(), createNoneTransitionInfo());
TransitionFinishCallback finishCallback = mock(TransitionFinishCallback.class);
@@ -403,24 +413,18 @@
}
}
- static class TestCase {
- private final boolean mShouldHandleMixedUnfold;
-
- public TestCase(boolean shouldHandleMixedUnfold) {
- mShouldHandleMixedUnfold = shouldHandleMixedUnfold;
- }
-
- public boolean mixedUnfoldFlagEnabled() {
- return mShouldHandleMixedUnfold;
- }
-
- @Override
- public String toString() {
- return "shouldHandleMixedUnfold flag = " + mShouldHandleMixedUnfold;
- }
+ private TransitionInfo createUnfoldTransitionInfo() {
+ TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
+ TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
+ change.setStartAbsBounds(new Rect(0, 0, 10, 10));
+ change.setEndAbsBounds(new Rect(0, 0, 100, 100));
+ change.setFlags(TransitionInfo.FLAG_IS_DISPLAY);
+ transitionInfo.addChange(change);
+ transitionInfo.setFlags(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
+ return transitionInfo;
}
- private TransitionInfo createUnfoldTransitionInfo() {
+ private TransitionInfo createDisplayResizeTransitionInfo() {
TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0);
TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class));
change.setStartAbsBounds(new Rect(0, 0, 10, 10));
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 901ea46..a8ffd2b 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -110,6 +110,10 @@
void pauseRecording(in IBinder sessionToken, in Bundle params, int userId);
void resumeRecording(in IBinder sessionToken, in Bundle params, int userId);
+ // For playback control
+ void startPlayback(in IBinder sessionToken, int userId);
+ void stopPlayback(in IBinder sessionToken, int mode, int userId);
+
// For broadcast info
void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId);
void removeBroadcastInfo(in IBinder sessionToken, int id, int userId);
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 5246f5c4..e37ee6e 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -63,6 +63,9 @@
void timeShiftSetMode(int mode);
void timeShiftEnablePositionTracking(boolean enable);
+ void startPlayback();
+ void stopPlayback(int mode);
+
// For the recording session
void startRecording(in Uri programUri, in Bundle params);
void stopRecording();
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index d749b91..ae3ee65 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -79,6 +79,8 @@
private static final int DO_TIME_SHIFT_SET_MODE = 30;
private static final int DO_SET_TV_MESSAGE_ENABLED = 31;
private static final int DO_NOTIFY_TV_MESSAGE = 32;
+ private static final int DO_STOP_PLAYBACK = 33;
+ private static final int DO_START_PLAYBACK = 34;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -286,6 +288,14 @@
mTvInputSessionImpl.onTvMessageReceived((Integer) args.arg1, (Bundle) args.arg2);
break;
}
+ case DO_STOP_PLAYBACK: {
+ mTvInputSessionImpl.stopPlayback(msg.arg1);
+ break;
+ }
+ case DO_START_PLAYBACK: {
+ mTvInputSessionImpl.startPlayback();
+ break;
+ }
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -483,6 +493,17 @@
enabled));
}
+ @Override
+ public void stopPlayback(int mode) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode));
+ }
+
+ @Override
+ public void startPlayback() {
+ mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_START_PLAYBACK));
+ }
+
+
private final class TvInputEventReceiver extends InputEventReceiver {
TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 631ab9a..c685a5a 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -339,6 +339,14 @@
*/
public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = VIDEO_UNAVAILABLE_REASON_END;
+ /**
+ * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+ * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+ * it has been stopped by stopPlayback.
+ * @hide
+ */
+ public static final int VIDEO_UNAVAILABLE_REASON_STOPPED = 19;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
@@ -3302,6 +3310,30 @@
}
}
+ void stopPlayback(int mode) {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.stopPlayback(mToken, mode, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ void startPlayback() {
+ if (mToken == null) {
+ Log.w(TAG, "The session has been already released");
+ return;
+ }
+ try {
+ mService.startPlayback(mToken, mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* Sends TV messages to the service for testing purposes
*/
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 720d9a6..55fa517 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -34,6 +34,7 @@
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioPresentation;
import android.media.PlaybackParams;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -1531,6 +1532,32 @@
}
/**
+ * Called when the application requests playback of the Audio, Video, and CC streams to be
+ * stopped, but the metadata should continue to be filtered.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as should release the
+ * stream, making it impossible to resume from this position again.
+ * @param mode
+ * @hide
+ */
+ public void onStopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void onStartPlayback() {
+ }
+
+ /**
* Called when the application requests to play a given recorded TV program.
*
* @param recordedProgramUri The URI of a recorded TV program.
@@ -1993,6 +2020,20 @@
}
/**
+ * Calls {@link #onStopPlayback(int)}.
+ */
+ void stopPlayback(int mode) {
+ onStopPlayback(mode);
+ }
+
+ /**
+ * Calls {@link #onStartPlayback()}.
+ */
+ void startPlayback() {
+ onStartPlayback();
+ }
+
+ /**
* Calls {@link #onTimeShiftPlay(Uri)}.
*/
void timeShiftPlay(Uri recordedProgramUri) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 196b5c3..233f966 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -37,6 +37,7 @@
import android.media.tv.TvInputManager.Session;
import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
import android.media.tv.TvInputManager.SessionCallback;
+import android.media.tv.interactive.TvInteractiveAppService;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -643,6 +644,35 @@
}
}
+ /**
+ * Stops playback of the Audio, Video, and CC streams, but continue filtering the metadata.
+ *
+ * <p>The metadata that will continue to be filtered includes the PSI
+ * (Program specific information) and SI (Service Information), part of ISO/IEC 13818-1.
+ *
+ * <p> Note that this is different form {@link #timeShiftPause()} as this completely drops
+ * the stream, making it impossible to resume from this position again.
+ * @hide
+ */
+ public void stopPlayback(@TvInteractiveAppService.PlaybackCommandStopMode int mode) {
+ if (mSession != null) {
+ mSession.stopPlayback(mode);
+ }
+ }
+
+ /**
+ * Starts playback of the Audio, Video, and CC streams.
+ *
+ * <p> Note that this is different form {@link #timeShiftResume()} as this is intended to be
+ * used after stopping playback. This is used to restart playback from the current position
+ * in the live broadcast.
+ * @hide
+ */
+ public void startPlayback() {
+ if (mSession != null) {
+ mSession.startPlayback();
+ }
+ }
/**
* Sends TV messages to the session for testing purposes
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 0abf285..66282dc 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -527,6 +527,15 @@
final Drawable profileIcon = getIcon(this, PROFILE_ICONS.get(deviceProfile));
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
updatePermissionUi();
mProfileIcon.setImageDrawable(profileIcon);
@@ -598,6 +607,14 @@
Log.d(TAG, "onDeviceClicked(): " + mSelectedDevice.toShortString());
+ // No need to show permission consent dialog if it is a isSkipPrompt(true)
+ // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ Log.d(TAG, "Skipping the permission consent dialog.");
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
+
updatePermissionUi();
mSummary.setVisibility(View.VISIBLE);
@@ -615,14 +632,6 @@
this, PROFILE_TITLES.get(deviceProfile), mAppLabel, remoteDeviceName);
final Spanned summary;
- // No need to show permission consent dialog if it is a isSkipPrompt(true)
- // AssociationRequest. See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
- if (mRequest.isSkipPrompt()) {
- mSingleDeviceSpinner.setVisibility(View.GONE);
- onUserSelectedDevice(mSelectedDevice);
- return;
- }
-
if (deviceProfile == null && mRequest.isSingleDevice()) {
summary = getHtmlFromResources(this, summaryResourceId, remoteDeviceName);
mConstraintList.setVisibility(View.GONE);
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
index f216abb..66bd6f5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/card/CardPageProvider.kt
@@ -28,7 +28,14 @@
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
@@ -41,14 +48,14 @@
import com.android.settingslib.spa.widget.card.CardButton
import com.android.settingslib.spa.widget.card.CardModel
import com.android.settingslib.spa.widget.card.SettingsCard
-import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.card.SettingsCardContent
+import com.android.settingslib.spa.widget.card.SettingsCollapsibleCard
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
object CardPageProvider : SettingsPageProvider {
- override val name = "CardPage"
+ override val name = "Card"
override fun getTitle(arguments: Bundle?) = TITLE
@@ -79,10 +86,13 @@
@Composable
private fun SettingsCardWithoutIcon() {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCard(
CardModel(
title = stringResource(R.string.sample_title),
text = stringResource(R.string.sample_text),
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
buttons = listOf(
CardButton(text = "Action") {},
),
@@ -92,21 +102,23 @@
@Composable
fun SampleSettingsCollapsibleCard() {
- SettingsCollapsibleCard(
- title = "More alerts",
- imageVector = Icons.Outlined.Error,
- models = listOf(
+ val context = LocalContext.current
+ var isVisible0 by rememberSaveable { mutableStateOf(true) }
+ val cards = remember {
+ mutableStateListOf(
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.PowerOff,
+ isVisible = { isVisible0 },
+ onDismiss = { isVisible0 = false },
buttons = listOf(
CardButton(text = "Action") {},
)
),
CardModel(
- title = stringResource(R.string.sample_title),
- text = stringResource(R.string.sample_text),
+ title = context.getString(R.string.sample_title),
+ text = context.getString(R.string.sample_text),
imageVector = Icons.Outlined.Shield,
buttons = listOf(
CardButton(text = "Action") {},
@@ -114,6 +126,11 @@
)
)
)
+ }
+ SettingsCollapsibleCard(
+ title = "More alerts",
+ imageVector = Icons.Outlined.Error,
+ models = cards.toList()
)
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index c143390..993cb4a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -37,6 +37,7 @@
val itemPaddingAround = 8.dp
val itemDividerHeight = 32.dp
+ val iconSmall = 16.dp
val iconLarge = 48.dp
/** The size when app icon is displayed in list. */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
index c113f43..b18a1bc 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/CardModel.kt
@@ -28,5 +28,14 @@
val title: String,
val text: String,
val imageVector: ImageVector? = null,
+ val isVisible: () -> Boolean = { true },
+
+ /**
+ * A dismiss button will be displayed if this is not null.
+ *
+ * And this callback will be called when user clicks the button.
+ */
+ val onDismiss: (() -> Unit)? = null,
+
val buttons: List<CardButton> = emptyList(),
)
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
index 4379278..7eec888 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCard.kt
@@ -16,28 +16,35 @@
package com.android.settingslib.spa.widget.card
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.WarningAmber
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.debug.UiModePreviews
import com.android.settingslib.spa.framework.theme.SettingsDimension
@@ -87,20 +94,31 @@
@Composable
internal fun SettingsCardImpl(model: CardModel) {
- SettingsCardContent {
- Column(
- modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
- verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
- ) {
- CardIcon(model.imageVector)
- SettingsTitle(model.title)
- SettingsBody(model.text)
- Buttons(model.buttons)
+ AnimatedVisibility(visible = model.isVisible()) {
+ SettingsCardContent {
+ Column(
+ modifier = Modifier.padding(SettingsDimension.itemPaddingStart),
+ verticalArrangement = Arrangement.spacedBy(SettingsDimension.itemPaddingAround)
+ ) {
+ CardHeader(model.imageVector, model.onDismiss)
+ SettingsTitle(model.title)
+ SettingsBody(model.text)
+ Buttons(model.buttons)
+ }
}
}
}
@Composable
+fun CardHeader(imageVector: ImageVector?, onDismiss: (() -> Unit)? = null) {
+ Row(Modifier.fillMaxWidth()) {
+ CardIcon(imageVector)
+ Spacer(modifier = Modifier.weight(1f))
+ DismissButton(onDismiss)
+ }
+}
+
+@Composable
private fun CardIcon(imageVector: ImageVector?) {
if (imageVector != null) {
Icon(
@@ -113,6 +131,28 @@
}
@Composable
+private fun DismissButton(onDismiss: (() -> Unit)?) {
+ if (onDismiss == null) return
+ Surface(
+ shape = CircleShape,
+ color = MaterialTheme.colorScheme.secondaryContainer,
+ ) {
+ IconButton(
+ onClick = onDismiss,
+ modifier = Modifier.size(SettingsDimension.itemIconSize)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = stringResource(
+ androidx.compose.material3.R.string.m3c_snackbar_dismiss
+ ),
+ modifier = Modifier.size(SettingsDimension.iconSmall),
+ )
+ }
+ }
+}
+
+@Composable
private fun Buttons(buttons: List<CardButton>) {
if (buttons.isNotEmpty()) {
Row(
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
index bf192a1..6e36490 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCard.kt
@@ -58,7 +58,7 @@
var expanded by rememberSaveable { mutableStateOf(false) }
SettingsCard {
SettingsCardContent {
- Header(title, imageVector, models.size, expanded) { expanded = it }
+ Header(title, imageVector, models.count { it.isVisible() }, expanded) { expanded = it }
}
AnimatedVisibility(expanded) {
Column {
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
index fd3ae49..beb9433 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCardTest.kt
@@ -16,10 +16,18 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -31,6 +39,8 @@
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCard_titleDisplayed() {
composeTestRule.setContent {
@@ -96,6 +106,27 @@
assertThat(buttonClicked).isTrue()
}
+ @Test
+ fun settingsCard_dismiss() {
+ composeTestRule.setContent {
+ var isVisible by remember { mutableStateOf(true) }
+ SettingsCard(
+ CardModel(
+ title = TITLE,
+ text = "",
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
+ )
+ )
+ }
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(TEXT).isNotDisplayed()
+ }
+
private companion object {
const val TITLE = "Title"
const val TEXT = "Text"
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
index efe1c70..aba9d7be 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/card/SettingsCollapsibleCardTest.kt
@@ -16,12 +16,20 @@
package com.android.settingslib.spa.widget.card
+import android.content.Context
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Error
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.isNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
@@ -32,6 +40,8 @@
@get:Rule
val composeTestRule = createComposeRule()
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
@Test
fun settingsCollapsibleCard_titleDisplayed() {
setContent()
@@ -62,8 +72,22 @@
composeTestRule.onNodeWithText(CARD_TEXT).assertIsDisplayed()
}
+ @Test
+ fun settingsCollapsibleCard_dismiss() {
+ setContent()
+ composeTestRule.onNodeWithText(TITLE).performClick()
+
+ composeTestRule.onNodeWithContentDescription(
+ context.getString(androidx.compose.material3.R.string.m3c_snackbar_dismiss)
+ ).performClick()
+
+ composeTestRule.onNodeWithText(CARD_TEXT).isNotDisplayed()
+ composeTestRule.onNodeWithText("0").assertIsDisplayed()
+ }
+
private fun setContent() {
composeTestRule.setContent {
+ var isVisible by rememberSaveable { mutableStateOf(true) }
SettingsCollapsibleCard(
title = TITLE,
imageVector = Icons.Outlined.Error,
@@ -71,6 +95,8 @@
CardModel(
title = "",
text = CARD_TEXT,
+ isVisible = { isVisible },
+ onDismiss = { isVisible = false },
)
),
)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 2cb44ec..49ac0f8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -28,7 +28,9 @@
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.bluetooth.BluetoothLeBroadcastSettings;
import android.bluetooth.BluetoothLeBroadcastSubgroup;
+import android.bluetooth.BluetoothLeBroadcastSubgroupSettings;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.ContentResolver;
@@ -42,10 +44,13 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.android.settingslib.R;
+import com.google.common.collect.ImmutableList;
+
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -376,6 +381,77 @@
(mBroadcastCode != null && mBroadcastCode.length > 0) ? mBroadcastCode : null);
}
+ /**
+ * Start the private Broadcast for personal audio sharing or qr code sharing.
+ *
+ * <p>The broadcast will use random string for both broadcast name and subgroup program info;
+ * The broadcast will use random string for broadcast code; The broadcast will only have one
+ * subgroup due to system limitation; The subgroup language will be null.
+ *
+ * <p>If the system started the LE Broadcast, then the system calls the corresponding callback
+ * {@link BluetoothLeBroadcast.Callback}.
+ */
+ public void startPrivateBroadcast(int quality) {
+ mNewAppSourceName = "Sharing audio";
+ if (mServiceBroadcast == null) {
+ Log.d(TAG, "The BluetoothLeBroadcast is null when starting the private broadcast.");
+ return;
+ }
+ if (mServiceBroadcast.getAllBroadcastMetadata().size()
+ >= mServiceBroadcast.getMaximumNumberOfBroadcasts()) {
+ Log.d(TAG, "Skip starting the broadcast due to number limit.");
+ return;
+ }
+ String programInfo = getProgramInfo();
+ if (DEBUG) {
+ Log.d(TAG, "startBroadcast: language = null ,programInfo = " + programInfo);
+ }
+ // Current broadcast framework only support one subgroup
+ BluetoothLeBroadcastSubgroupSettings subgroupSettings =
+ buildBroadcastSubgroupSettings(/* language= */ null, programInfo, quality);
+ BluetoothLeBroadcastSettings settings =
+ buildBroadcastSettings(
+ true, // TODO: set to false after framework fix
+ TextUtils.isEmpty(programInfo) ? null : programInfo,
+ (mBroadcastCode != null && mBroadcastCode.length > 0)
+ ? mBroadcastCode
+ : null,
+ ImmutableList.of(subgroupSettings));
+ mServiceBroadcast.startBroadcast(settings);
+ }
+
+ private BluetoothLeBroadcastSettings buildBroadcastSettings(
+ boolean isPublic,
+ @Nullable String broadcastName,
+ @Nullable byte[] broadcastCode,
+ List<BluetoothLeBroadcastSubgroupSettings> subgroupSettingsList) {
+ BluetoothLeBroadcastSettings.Builder builder =
+ new BluetoothLeBroadcastSettings.Builder()
+ .setPublicBroadcast(isPublic)
+ .setBroadcastName(broadcastName)
+ .setBroadcastCode(broadcastCode);
+ for (BluetoothLeBroadcastSubgroupSettings subgroupSettings : subgroupSettingsList) {
+ builder.addSubgroupSettings(subgroupSettings);
+ }
+ return builder.build();
+ }
+
+ private BluetoothLeBroadcastSubgroupSettings buildBroadcastSubgroupSettings(
+ @Nullable String language, @Nullable String programInfo, int quality) {
+ BluetoothLeAudioContentMetadata metadata =
+ new BluetoothLeAudioContentMetadata.Builder()
+ .setLanguage(language)
+ .setProgramInfo(programInfo)
+ .build();
+ // Current broadcast framework only support one subgroup, thus we still maintain the latest
+ // metadata to keep legacy UI working.
+ mBluetoothLeAudioContentMetadata = metadata;
+ return new BluetoothLeBroadcastSubgroupSettings.Builder()
+ .setPreferredQuality(quality)
+ .setContentMetadata(mBluetoothLeAudioContentMetadata)
+ .build();
+ }
+
public String getProgramInfo() {
return mProgramInfo;
}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a26b311..facb244 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -61,6 +61,13 @@
}
flag {
+ name: "refactor_get_current_user"
+ namespace: "systemui"
+ description: "KeyguardUpdateMonitor.getCurrentUser() was providing outdated results."
+ bug: "305984787"
+}
+
+flag {
name: "notification_throttle_hun"
namespace: "systemui"
description: "During notification avalanche, throttle HUNs showing in fast succession."
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index e538e09..2944bd9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -174,8 +174,8 @@
lerp: (T, T, Float) -> T,
canOverflow: Boolean,
): T {
- val state = layoutImpl.state.transitionState
- if (state !is TransitionState.Transition || !layoutImpl.isTransitionReady(state)) {
+ val transition = layoutImpl.state.currentTransition
+ if (transition == null || !layoutImpl.isTransitionReady(transition)) {
return sharedValue.value
}
@@ -191,10 +191,11 @@
return value as Element.SharedValue<T>
}
- val fromValue = sceneValue(state.fromScene)
- val toValue = sceneValue(state.toScene)
+ val fromValue = sceneValue(transition.fromScene)
+ val toValue = sceneValue(transition.toScene)
return if (fromValue != null && toValue != null) {
- val progress = if (canOverflow) state.progress else state.progress.coerceIn(0f, 1f)
+ val progress =
+ if (canOverflow) transition.progress else transition.progress.coerceIn(0f, 1f)
lerp(fromValue.value, toValue.value, progress)
} else if (fromValue != null) {
fromValue.value
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
index de69c37..ba6d00e 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -28,11 +28,11 @@
* the currently running transition, if there is one.
*/
internal fun CoroutineScope.animateToScene(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
) {
- val state = layoutImpl.state.transitionState
- if (state.currentScene == target) {
+ val transitionState = layoutState.transitionState
+ if (transitionState.currentScene == target) {
// This can happen in 3 different situations, for which there isn't anything else to do:
// 1. There is no ongoing transition and [target] is already the current scene.
// 2. The user is swiping to [target] from another scene and released their pointer such
@@ -44,44 +44,47 @@
return
}
- when (state) {
- is TransitionState.Idle -> animate(layoutImpl, target)
+ when (transitionState) {
+ is TransitionState.Idle -> animate(layoutState, target)
is TransitionState.Transition -> {
// A transition is currently running: first check whether `transition.toScene` or
// `transition.fromScene` is the same as our target scene, in which case the transition
// can be accelerated or reversed to end up in the target state.
- if (state.toScene == target) {
+ if (transitionState.toScene == target) {
// The user is currently swiping to [target] but didn't release their pointer yet:
// animate the progress to `1`.
- check(state.fromScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.fromScene == transitionState.currentScene)
+ val progress = transitionState.progress
if ((1f - progress).absoluteValue < ProgressVisibilityThreshold) {
- // The transition is already finished (progress ~= 1): no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is already finished (progress ~= 1): no need to animate. We
+ // finish the current transition early to make sure that the current state
+ // change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// The transition is in progress: start the canned animation at the same
// progress as it was in.
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress)
+ animate(layoutState, target, startProgress = progress)
}
return
}
- if (state.fromScene == target) {
+ if (transitionState.fromScene == target) {
// There is a transition from [target] to another scene: simply animate the same
// transition progress to `0`.
- check(state.toScene == state.currentScene)
- val progress = state.progress
+ check(transitionState.toScene == transitionState.currentScene)
+ val progress = transitionState.progress
if (progress.absoluteValue < ProgressVisibilityThreshold) {
- // The transition is at progress ~= 0: no need to animate.
- layoutImpl.state.transitionState = TransitionState.Idle(state.currentScene)
+ // The transition is at progress ~= 0: no need to animate.We finish the current
+ // transition early to make sure that the current state change is committed.
+ layoutState.finishTransition(transitionState, transitionState.currentScene)
} else {
// TODO(b/290184746): Also take the current velocity into account.
- animate(layoutImpl, target, startProgress = progress, reversed = true)
+ animate(layoutState, target, startProgress = progress, reversed = true)
}
return
@@ -89,27 +92,22 @@
// Generic interruption; the current transition is neither from or to [target].
// TODO(b/290930950): Better handle interruptions here.
- animate(layoutImpl, target)
+ animate(layoutState, target)
}
}
}
private fun CoroutineScope.animate(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
target: SceneKey,
startProgress: Float = 0f,
reversed: Boolean = false,
) {
- val fromScene = layoutImpl.state.transitionState.currentScene
+ val fromScene = layoutState.transitionState.currentScene
val isUserInput =
- (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
+ (layoutState.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
?: false
- val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
- val visibilityThreshold =
- (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
- val animatable = Animatable(startProgress, visibilityThreshold = visibilityThreshold)
-
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
@@ -119,7 +117,6 @@
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
} else {
OneOffTransition(
@@ -128,21 +125,27 @@
currentScene = target,
isInitiatedByUserInput = isUserInput,
isUserInputOngoing = false,
- animatable = animatable,
)
}
- // Change the current layout state to use this new transition.
- layoutImpl.state.transitionState = transition
+ // Change the current layout state to start this new transition. This will compute the
+ // TransformationSpec associated to this transition, which we need to initialize the Animatable
+ // that will actually animate it.
+ layoutState.startTransition(transition)
+
+ // The transformation now contains the spec that we should use to instantiate the Animatable.
+ val animationSpec = layoutState.transformationSpec.progressSpec
+ val visibilityThreshold =
+ (animationSpec as? SpringSpec)?.visibilityThreshold ?: ProgressVisibilityThreshold
+ val animatable =
+ Animatable(startProgress, visibilityThreshold = visibilityThreshold).also {
+ transition.animatable = it
+ }
// Animate the progress to its target value.
launch {
animatable.animateTo(targetProgress, animationSpec)
-
- // Unless some other external state change happened, the state should now be idle.
- if (layoutImpl.state.transitionState == transition) {
- layoutImpl.state.transitionState = TransitionState.Idle(target)
- }
+ layoutState.finishTransition(transition, target)
}
}
@@ -152,8 +155,16 @@
override val currentScene: SceneKey,
override val isInitiatedByUserInput: Boolean,
override val isUserInputOngoing: Boolean,
- private val animatable: Animatable<Float, AnimationVector1D>,
) : TransitionState.Transition(fromScene, toScene) {
+ /**
+ * The animatable used to animate this transition.
+ *
+ * Note: This is lateinit because we need to first create this Transition object so that
+ * [SceneTransitionLayoutState] can compute the transformations and animation spec associated to
+ * it, which is need to initialize this Animatable.
+ */
+ lateinit var animatable: Animatable<Float, AnimationVector1D>
+
override val progress: Float
get() = animatable.value
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 431a8ae..5dc1079 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -181,15 +181,11 @@
}
internal class ElementNode(
- layoutImpl: SceneTransitionLayoutImpl,
- scene: Scene,
- element: Element,
- sceneValues: Element.TargetValues,
+ private var layoutImpl: SceneTransitionLayoutImpl,
+ private var scene: Scene,
+ private var element: Element,
+ private var sceneValues: Element.TargetValues,
) : Modifier.Node(), DrawModifierNode {
- private var layoutImpl: SceneTransitionLayoutImpl = layoutImpl
- private var scene: Scene = scene
- private var element: Element = element
- private var sceneValues: Element.TargetValues = sceneValues
override fun onAttach() {
super.onAttach()
@@ -283,26 +279,27 @@
scene: Scene,
element: Element,
): Boolean {
- val state = layoutImpl.state.transitionState
+ val transition = layoutImpl.state.currentTransition
// Always draw the element if there is no ongoing transition or if the element is not shared.
if (
- state !is TransitionState.Transition ||
- !layoutImpl.isTransitionReady(state) ||
- state.fromScene !in element.sceneValues ||
- state.toScene !in element.sceneValues
+ transition == null ||
+ !layoutImpl.isTransitionReady(transition) ||
+ transition.fromScene !in element.sceneValues ||
+ transition.toScene !in element.sceneValues
) {
return true
}
- val sharedTransformation = sharedElementTransformation(layoutImpl, state, element.key)
+ val sharedTransformation =
+ sharedElementTransformation(layoutImpl.state, transition, element.key)
if (sharedTransformation?.enabled == false) {
return true
}
return shouldDrawOrComposeSharedElement(
layoutImpl,
- state,
+ transition,
scene.key,
element.key,
sharedTransformation,
@@ -331,21 +328,21 @@
}
private fun isSharedElementEnabled(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): Boolean {
- return sharedElementTransformation(layoutImpl, transition, element)?.enabled ?: true
+ return sharedElementTransformation(layoutState, transition, element)?.enabled ?: true
}
internal fun sharedElementTransformation(
- layoutImpl: SceneTransitionLayoutImpl,
+ layoutState: SceneTransitionLayoutStateImpl,
transition: TransitionState.Transition,
element: ElementKey,
): SharedElementTransformation? {
- val spec = layoutImpl.transitions.transitionSpec(transition.fromScene, transition.toScene)
- val sharedInFromScene = spec.transformations(element, transition.fromScene).shared
- val sharedInToScene = spec.transformations(element, transition.toScene).shared
+ val transformationSpec = layoutState.transformationSpec
+ val sharedInFromScene = transformationSpec.transformations(element, transition.fromScene).shared
+ val sharedInToScene = transformationSpec.transformations(element, transition.toScene).shared
// The sharedElement() transformation must either be null or be the same in both scenes.
if (sharedInFromScene != sharedInToScene) {
@@ -371,13 +368,9 @@
scene: Scene,
sceneValues: Element.TargetValues,
): Boolean {
- val state = layoutImpl.state.transitionState
+ val transition = layoutImpl.state.currentTransition ?: return true
- if (state !is TransitionState.Transition) {
- return true
- }
-
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
val lastValue =
sceneValues.lastValues.alpha.takeIf { it != Element.AlphaUnspecified }
?: element.lastSharedValues.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f
@@ -385,8 +378,8 @@
return lastValue == 1f
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -395,14 +388,11 @@
}
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
return true
}
- return layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- .alpha == null
+ return layoutImpl.state.transformationSpec.transformations(element.key, scene.key).alpha == null
}
/**
@@ -607,24 +597,22 @@
lastValue: () -> T,
lerp: (T, T, Float) -> T,
): T {
- val state = layoutImpl.state.transitionState
-
- // There is no ongoing transition.
- if (state !is TransitionState.Transition) {
- // Even if this element SceneTransitionLayout is not animated, the layout itself might be
- // animated (e.g. by another parent SceneTransitionLayout), in which case this element still
- // need to participate in the layout phase.
- return currentValue()
- }
+ val transition =
+ layoutImpl.state.currentTransition
+ // There is no ongoing transition. Even if this element SceneTransitionLayout is not
+ // animated, the layout itself might be animated (e.g. by another parent
+ // SceneTransitionLayout), in which case this element still need to participate in the
+ // layout phase.
+ ?: return currentValue()
// A transition was started but it's not ready yet (not all elements have been composed/laid
// out yet). Use the last value that was set, to make sure elements don't unexpectedly jump.
- if (!layoutImpl.isTransitionReady(state)) {
+ if (!layoutImpl.isTransitionReady(transition)) {
return lastValue()
}
- val fromScene = state.fromScene
- val toScene = state.toScene
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromValues = element.sceneValues[fromScene]
val toValues = element.sceneValues[toScene]
@@ -638,21 +626,17 @@
// TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
// elements follow the finger direction.
val isSharedElement = fromValues != null && toValues != null
- if (isSharedElement && isSharedElementEnabled(layoutImpl, state, element.key)) {
+ if (isSharedElement && isSharedElementEnabled(layoutImpl.state, transition, element.key)) {
val start = sceneValue(fromValues!!)
val end = sceneValue(toValues!!)
// Make sure we don't read progress if values are the same and we don't need to interpolate,
// so we don't invalidate the phase where this is read.
- return if (start == end) start else lerp(start, end, state.progress)
+ return if (start == end) start else lerp(start, end, transition.progress)
}
val transformation =
- transformation(
- layoutImpl.transitions
- .transitionSpec(fromScene, toScene)
- .transformations(element.key, scene.key)
- )
+ transformation(layoutImpl.state.transformationSpec.transformations(element.key, scene.key))
// If there is no transformation explicitly associated to this element value, let's use
// the value given by the system (like the current position and size given by the layout
// pass).
@@ -675,7 +659,7 @@
scene,
element,
sceneValues,
- state,
+ transition,
idleValue,
)
@@ -685,7 +669,7 @@
return targetValue
}
- val progress = state.progress
+ val progress = transition.progress
// TODO(b/290184746): Make sure that we don't overflow transformations associated to a range.
val rangeProgress = transformation.range?.progress(progress) ?: progress
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 7029da2..306f276 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -120,17 +120,13 @@
scene: SceneKey,
element: Element,
): Boolean {
- val transitionState = layoutImpl.state.transitionState
-
- // If we are idle, there is only one [scene] that is composed so we can compose our movable
- // content here.
- if (transitionState is TransitionState.Idle) {
- check(transitionState.currentScene == scene)
- return true
- }
-
- val fromScene = (transitionState as TransitionState.Transition).fromScene
- val toScene = transitionState.toScene
+ val transition =
+ layoutImpl.state.currentTransition
+ // If we are idle, there is only one [scene] that is composed so we can compose our
+ // movable content here.
+ ?: return true
+ val fromScene = transition.fromScene
+ val toScene = transition.toScene
val fromReady = layoutImpl.isSceneReady(fromScene)
val toReady = layoutImpl.isSceneReady(toScene)
@@ -181,10 +177,10 @@
return shouldDrawOrComposeSharedElement(
layoutImpl,
- transitionState,
+ transition,
scene,
element.key,
- sharedElementTransformation(layoutImpl, transitionState, element.key),
+ sharedElementTransformation(layoutImpl.state, transition, element.key),
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
index 32025b4..e78f326 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt
@@ -179,7 +179,8 @@
bottomOrRightBehavior: NestedScrollBehavior,
) =
SceneNestedScrollHandler(
- gestureHandler = layoutImpl.gestureHandler(orientation = orientation),
+ layoutImpl = layoutImpl,
+ orientation = orientation,
topOrLeftBehavior = topOrLeftBehavior,
bottomOrRightBehavior = bottomOrRightBehavior,
)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 91decf4..338557d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -41,14 +41,9 @@
internal val orientation: Orientation,
private val coroutineScope: CoroutineScope,
) {
+ private val layoutState = layoutImpl.state
val draggable: DraggableHandler = SceneDraggableHandler(this)
- internal var transitionState
- get() = layoutImpl.state.transitionState
- set(value) {
- layoutImpl.state.transitionState = value
- }
-
private var _swipeTransition: SwipeTransition? = null
internal var swipeTransition: SwipeTransition
get() = _swipeTransition ?: error("SwipeTransition needs to be initialized")
@@ -57,27 +52,26 @@
}
private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
- if (isDrivingTransition || force) transitionState = newTransition
+ if (isDrivingTransition || force) layoutState.startTransition(newTransition)
swipeTransition = newTransition
}
- internal val currentScene: Scene
- get() = layoutImpl.scene(transitionState.currentScene)
-
internal val isDrivingTransition
- get() = transitionState == _swipeTransition
+ get() = layoutState.transitionState == _swipeTransition
/**
* The velocity threshold at which the intent of the user is to swipe up or down. It is the same
* as SwipeableV2Defaults.VelocityThreshold.
*/
- internal val velocityThreshold = with(layoutImpl.density) { 125.dp.toPx() }
+ internal val velocityThreshold: Float
+ get() = with(layoutImpl.density) { 125.dp.toPx() }
/**
* The positional threshold at which the intent of the user is to swipe to the next scene. It is
* the same as SwipeableV2Defaults.PositionalThreshold.
*/
- private val positionalThreshold = with(layoutImpl.density) { 56.dp.toPx() }
+ private val positionalThreshold
+ get() = with(layoutImpl.density) { 56.dp.toPx() }
internal var gestureWithPriority: Any? = null
@@ -98,18 +92,18 @@
return
}
- val transition = transitionState
- if (transition is TransitionState.Transition) {
+ val transitionState = layoutState.transitionState
+ if (transitionState is TransitionState.Transition) {
// TODO(b/290184746): Better handle interruptions here if state != idle.
Log.w(
TAG,
"start from TransitionState.Transition is not fully supported: from" +
- " ${transition.fromScene} to ${transition.toScene} " +
- "(progress ${transition.progress})"
+ " ${transitionState.fromScene} to ${transitionState.toScene} " +
+ "(progress ${transitionState.progress})"
)
}
- val fromScene = currentScene
+ val fromScene = layoutImpl.scene(transitionState.currentScene)
setCurrentActions(fromScene, startedPosition, pointersDown)
val (targetScene, distance) =
@@ -364,7 +358,7 @@
findTargetSceneAndDistanceStrict(fromScene, velocity)
?: run {
// We will not animate
- transitionState = TransitionState.Idle(fromScene.key)
+ layoutState.finishTransition(swipeTransition, idleScene = fromScene.key)
return
}
@@ -439,14 +433,7 @@
)
swipeTransition.finishOffsetAnimation()
-
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (isDrivingTransition) {
- transitionState = TransitionState.Idle(targetScene)
- }
+ layoutState.finishTransition(swipeTransition, targetScene)
}
}
}
@@ -539,10 +526,14 @@
}
internal class SceneNestedScrollHandler(
- private val gestureHandler: SceneGestureHandler,
+ private val layoutImpl: SceneTransitionLayoutImpl,
+ private val orientation: Orientation,
private val topOrLeftBehavior: NestedScrollBehavior,
private val bottomOrRightBehavior: NestedScrollBehavior,
) : NestedScrollHandler {
+ private val layoutState = layoutImpl.state
+ private val gestureHandler = layoutImpl.gestureHandler(orientation)
+
override val connection: PriorityNestedScrollConnection = nestedScrollConnection()
private fun nestedScrollConnection(): PriorityNestedScrollConnection {
@@ -553,7 +544,7 @@
val actionUpOrLeft =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Left
Orientation.Vertical -> SwipeDirection.Up
},
@@ -563,7 +554,7 @@
val actionDownOrRight =
Swipe(
direction =
- when (gestureHandler.orientation) {
+ when (orientation) {
Orientation.Horizontal -> SwipeDirection.Right
Orientation.Vertical -> SwipeDirection.Down
},
@@ -571,7 +562,7 @@
)
fun hasNextScene(amount: Float): Boolean {
- val fromScene = gestureHandler.currentScene
+ val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene)
val nextScene =
when {
amount < 0f -> fromScene.userActions[actionUpOrLeft]
@@ -582,7 +573,7 @@
}
return PriorityNestedScrollConnection(
- orientation = gestureHandler.orientation,
+ orientation = orientation,
canStartPreScroll = { offsetAvailable, offsetBeforeStart ->
canChangeScene = offsetBeforeStart == 0f
@@ -590,8 +581,9 @@
canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
- val progress = gestureHandler.swipeTransition.progress
- val threshold = gestureHandler.layoutImpl.transitionInterceptionThreshold
+ val swipeTransition = gestureHandler.swipeTransition
+ val progress = swipeTransition.progress
+ val threshold = layoutImpl.transitionInterceptionThreshold
fun isProgressCloseTo(value: Float) = (progress - value).absoluteValue <= threshold
// The transition is always between 0 and 1. If it is close to either of these
@@ -599,9 +591,8 @@
// The progress value can go beyond this range in the case of overscroll.
val shouldSnapToIdle = isProgressCloseTo(0f) || isProgressCloseTo(1f)
if (shouldSnapToIdle) {
- gestureHandler.swipeTransition.cancelOffsetAnimation()
- gestureHandler.transitionState =
- TransitionState.Idle(gestureHandler.swipeTransition.currentScene)
+ swipeTransition.cancelOffsetAnimation()
+ layoutState.finishTransition(swipeTransition, swipeTransition.currentScene)
}
// Start only if we cannot consume this event
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 239971f..3608e37 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -19,6 +19,8 @@
import androidx.annotation.FloatRange
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
@@ -27,6 +29,7 @@
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.platform.LocalDensity
+import kotlinx.coroutines.channels.Channel
/**
* [SceneTransitionLayout] is a container that automatically animates its content whenever
@@ -266,24 +269,45 @@
val coroutineScope = rememberCoroutineScope()
val layoutImpl = remember {
SceneTransitionLayoutImpl(
+ state = state as SceneTransitionLayoutStateImpl,
onChangeScene = onChangeScene,
- builder = scenes,
- transitions = transitions,
- state = state,
density = density,
edgeDetector = edgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenes,
coroutineScope = coroutineScope,
)
.also { onLayoutImpl?.invoke(it) }
}
- layoutImpl.onChangeScene = onChangeScene
- layoutImpl.transitions = transitions
- layoutImpl.density = density
- layoutImpl.edgeDetector = edgeDetector
+ val targetSceneChannel = remember { Channel<SceneKey>(Channel.CONFLATED) }
+ SideEffect {
+ if (state != layoutImpl.state) {
+ error(
+ "This SceneTransitionLayout was bound to a different SceneTransitionLayoutState" +
+ " that was used when creating it, which is not supported"
+ )
+ }
- layoutImpl.setScenes(scenes)
- layoutImpl.setCurrentScene(currentScene)
+ layoutImpl.onChangeScene = onChangeScene
+ (state as SceneTransitionLayoutStateImpl).transitions = transitions
+ layoutImpl.density = density
+ layoutImpl.edgeDetector = edgeDetector
+ layoutImpl.updateScenes(scenes)
+
+ state.transitions = transitions
+
+ targetSceneChannel.trySend(currentScene)
+ }
+
+ LaunchedEffect(targetSceneChannel) {
+ for (newKey in targetSceneChannel) {
+ // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
+ // late.
+ val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey
+ animateToScene(layoutImpl.state, newKey)
+ }
+ }
+
layoutImpl.Content(modifier)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 00e33e2..c99c325 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -22,13 +22,8 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.Stable
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -40,36 +35,40 @@
import androidx.compose.ui.util.fastForEach
import com.android.compose.ui.util.lerp
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.channels.Channel
@Stable
internal class SceneTransitionLayoutImpl(
- onChangeScene: (SceneKey) -> Unit,
+ internal val state: SceneTransitionLayoutStateImpl,
+ internal var onChangeScene: (SceneKey) -> Unit,
+ internal var density: Density,
+ internal var edgeDetector: EdgeDetector,
+ internal var transitionInterceptionThreshold: Float,
builder: SceneTransitionLayoutScope.() -> Unit,
- transitions: SceneTransitions,
- internal val state: SceneTransitionLayoutState,
- density: Density,
- edgeDetector: EdgeDetector,
- transitionInterceptionThreshold: Float,
coroutineScope: CoroutineScope,
) {
- internal val scenes = SnapshotStateMap<SceneKey, Scene>()
+ internal val scenes = mutableMapOf<SceneKey, Scene>()
+
+ /**
+ * The map of [Element]s.
+ *
+ * Note that this map is *mutated* directly during composition, so it is a [SnapshotStateMap] to
+ * make sure that mutations are reverted if composition is cancelled.
+ */
internal val elements = SnapshotStateMap<ElementKey, Element>()
- /** The scenes that are "ready", i.e. they were composed and fully laid-out at least once. */
+ /**
+ * The scenes that are "ready", i.e. they were composed and fully laid-out at least once.
+ *
+ * Note that this map is *read* during composition, so it is a [SnapshotStateMap] to make sure
+ * that we recompose when modifications are made to this map.
+ */
private val readyScenes = SnapshotStateMap<SceneKey, Boolean>()
- internal var onChangeScene by mutableStateOf(onChangeScene)
- internal var transitions by mutableStateOf(transitions)
- internal var density: Density by mutableStateOf(density)
- internal var edgeDetector by mutableStateOf(edgeDetector)
- internal var transitionInterceptionThreshold by mutableStateOf(transitionInterceptionThreshold)
-
private val horizontalGestureHandler: SceneGestureHandler
private val verticalGestureHandler: SceneGestureHandler
init {
- setScenes(builder)
+ updateScenes(builder)
// SceneGestureHandler must wait for the scenes to be initialized, in order to access the
// current scene (required for SwipeTransition).
@@ -98,7 +97,7 @@
return scenes[key] ?: error("Scene $key is not configured")
}
- internal fun setScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
+ internal fun updateScenes(builder: SceneTransitionLayoutScope.() -> Unit) {
// Keep a reference of the current scenes. After processing [builder], the scenes that were
// not configured will be removed.
val scenesToRemove = scenes.keys.toMutableSet()
@@ -141,20 +140,6 @@
}
@Composable
- internal fun setCurrentScene(key: SceneKey) {
- val channel = remember { Channel<SceneKey>(Channel.CONFLATED) }
- SideEffect { channel.trySend(key) }
- LaunchedEffect(channel) {
- for (newKey in channel) {
- // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame
- // late.
- val newKey = channel.tryReceive().getOrNull() ?: newKey
- animateToScene(this@SceneTransitionLayoutImpl, newKey)
- }
- }
- }
-
- @Composable
@OptIn(ExperimentalComposeUiApi::class)
internal fun Content(modifier: Modifier) {
Box(
@@ -171,14 +156,14 @@
val width: Int
val height: Int
- val state = state.transitionState
- if (state !is TransitionState.Transition) {
+ val transition = state.currentTransition
+ if (transition == null) {
width = placeable.width
height = placeable.height
} else {
// Interpolate the size.
- val fromSize = scene(state.fromScene).targetSize
- val toSize = scene(state.toScene).targetSize
+ val fromSize = scene(transition.fromScene).targetSize
+ val toSize = scene(transition.toScene).targetSize
// Optimization: make sure we don't read state.progress if fromSize ==
// toSize to avoid running this code every frame when the layout size does
@@ -187,7 +172,7 @@
width = fromSize.width
height = fromSize.height
} else {
- val size = lerp(fromSize, toSize, state.progress)
+ val size = lerp(fromSize, toSize, transition.progress)
width = size.width.coerceAtLeast(0)
height = size.height.coerceAtLeast(0)
}
@@ -228,13 +213,12 @@
scene.Content(
Modifier.drawWithContent {
- when (val state = state.transitionState) {
- is TransitionState.Idle -> drawContent()
- is TransitionState.Transition -> {
- // Don't draw scenes that are not ready yet.
- if (readyScenes.containsKey(key)) {
- drawContent()
- }
+ if (state.currentTransition == null) {
+ drawContent()
+ } else {
+ // Don't draw scenes that are not ready yet.
+ if (readyScenes.containsKey(key)) {
+ drawContent()
}
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 62372558..d1ba582 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -23,31 +23,32 @@
/** The state of a [SceneTransitionLayout]. */
@Stable
-class SceneTransitionLayoutState(initialScene: SceneKey) {
+sealed interface SceneTransitionLayoutState {
/**
* The current [TransitionState]. All values read here are backed by the Snapshot system.
*
* To observe those values outside of Compose/the Snapshot system, use
* [SceneTransitionLayoutState.observableTransitionState] instead.
*/
- var transitionState: TransitionState by mutableStateOf(TransitionState.Idle(initialScene))
+ val transitionState: TransitionState
+
+ /** The current transition, or `null` if we are idle. */
+ val currentTransition: TransitionState.Transition?
+ get() = transitionState as? TransitionState.Transition
/**
- * Whether we are transitioning, optionally restricting the check to the transition between
- * [from] and [to].
+ * Whether we are transitioning. If [from] or [to] is empty, we will also check that they match
+ * the scenes we are animating from and/or to.
*/
- fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean {
- val transition = transitionState as? TransitionState.Transition ?: return false
-
- return (from == null || transition.fromScene == from) &&
- (to == null || transition.toScene == to)
- }
+ fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean
/** Whether we are transitioning from [scene] to [other], or from [other] to [scene]. */
- fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
- return isTransitioning(from = scene, to = other) ||
- isTransitioning(from = other, to = scene)
- }
+ fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean
+}
+
+/** Create a new [SceneTransitionLayoutState] that is currently idle at scene [currentScene]. */
+fun SceneTransitionLayoutState(currentScene: SceneKey): SceneTransitionLayoutState {
+ return SceneTransitionLayoutStateImpl(currentScene, SceneTransitions.Empty)
}
@Stable
@@ -93,3 +94,50 @@
abstract val isUserInputOngoing: Boolean
}
}
+
+internal class SceneTransitionLayoutStateImpl(
+ initialScene: SceneKey,
+ internal var transitions: SceneTransitions,
+) : SceneTransitionLayoutState {
+ override var transitionState: TransitionState by
+ mutableStateOf(TransitionState.Idle(initialScene))
+ private set
+
+ /**
+ * The current [transformationSpec] associated to [transitionState]. Accessing this value makes
+ * sense only if [transitionState] is a [TransitionState.Transition].
+ */
+ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
+
+ override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean {
+ val transition = currentTransition ?: return false
+ return (from == null || transition.fromScene == from) &&
+ (to == null || transition.toScene == to)
+ }
+
+ override fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean {
+ return isTransitioning(from = scene, to = other) ||
+ isTransitioning(from = other, to = scene)
+ }
+
+ /** Start a new [transition], instantly interrupting any ongoing transition if there was one. */
+ internal fun startTransition(transition: TransitionState.Transition) {
+ // Compute the [TransformationSpec] when the transition starts.
+ transformationSpec =
+ transitions
+ .transitionSpec(transition.fromScene, transition.toScene)
+ .transformationSpec()
+
+ transitionState = transition
+ }
+
+ /**
+ * Notify that [transition] was finished and that we should settle to [idleScene]. This will do
+ * nothing if [transition] was interrupted since it was started.
+ */
+ internal fun finishTransition(transition: TransitionState.Transition, idleScene: SceneKey) {
+ if (transitionState == transition) {
+ transitionState = TransitionState.Idle(idleScene)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index f91895b..3a55567 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -18,11 +18,9 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
-import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
-import androidx.compose.ui.util.fastMap
import com.android.compose.animation.scene.transformation.AnchoredSize
import com.android.compose.animation.scene.transformation.AnchoredTranslate
import com.android.compose.animation.scene.transformation.DrawScale
@@ -36,16 +34,17 @@
import com.android.compose.animation.scene.transformation.Translate
/** The transitions configuration of a [SceneTransitionLayout]. */
-class SceneTransitions(
- internal val transitionSpecs: List<TransitionSpec>,
+class SceneTransitions
+internal constructor(
+ internal val transitionSpecs: List<TransitionSpecImpl>,
) {
- private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>()
+ private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpecImpl>>()
- internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ internal fun transitionSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
return cache.getOrPut(from) { mutableMapOf() }.getOrPut(to) { findSpec(from, to) }
}
- private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpec {
+ private fun findSpec(from: SceneKey, to: SceneKey): TransitionSpecImpl {
val spec = transition(from, to) { it.from == from && it.to == to }
if (spec != null) {
return spec
@@ -53,7 +52,7 @@
val reversed = transition(from, to) { it.from == to && it.to == from }
if (reversed != null) {
- return reversed.reverse()
+ return reversed.reversed()
}
val relaxedSpec =
@@ -67,16 +66,16 @@
return transition(from, to) {
(it.from == to && it.to == null) || (it.to == from && it.from == null)
}
- ?.reverse()
+ ?.reversed()
?: defaultTransition(from, to)
}
private fun transition(
from: SceneKey,
to: SceneKey,
- filter: (TransitionSpec) -> Boolean,
- ): TransitionSpec? {
- var match: TransitionSpec? = null
+ filter: (TransitionSpecImpl) -> Boolean,
+ ): TransitionSpecImpl? {
+ var match: TransitionSpecImpl? = null
transitionSpecs.fastForEach { spec ->
if (filter(spec)) {
if (match != null) {
@@ -89,28 +88,88 @@
}
private fun defaultTransition(from: SceneKey, to: SceneKey) =
- TransitionSpec(from, to, emptyList(), snap())
+ TransitionSpecImpl(from, to, TransformationSpec.EmptyProvider)
+
+ companion object {
+ val Empty = SceneTransitions(transitionSpecs = emptyList())
+ }
}
/** The definition of a transition between [from] and [to]. */
-@Stable
-data class TransitionSpec(
- val from: SceneKey?,
- val to: SceneKey?,
- val transformations: List<Transformation>,
- val spec: AnimationSpec<Float>,
-) {
- // TODO(b/302300957): Make sure this cache does not infinitely grow.
- private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+interface TransitionSpec {
+ /**
+ * The scene we are transitioning from. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val from: SceneKey?
- internal fun reverse(): TransitionSpec {
- return copy(
+ /**
+ * The scene we are transitioning to. If `null`, this spec can be used to animate from any
+ * scene.
+ */
+ val to: SceneKey?
+
+ /**
+ * Return a reversed version of this [TransitionSpec] for a transition going from [to] to
+ * [from].
+ */
+ fun reversed(): TransitionSpec
+
+ /*
+ * The [TransformationSpec] associated to this [TransitionSpec].
+ *
+ * Note that this is called once every a transition associated to this [TransitionSpec] is
+ * started.
+ */
+ fun transformationSpec(): TransformationSpec
+}
+
+interface TransformationSpec {
+ /** The [AnimationSpec] used to animate the associated transition progress. */
+ val progressSpec: AnimationSpec<Float>
+
+ /** The list of [Transformation] applied to elements during this transition. */
+ val transformations: List<Transformation>
+
+ companion object {
+ internal val Empty =
+ TransformationSpecImpl(progressSpec = snap(), transformations = emptyList())
+ internal val EmptyProvider = { Empty }
+ }
+}
+
+internal class TransitionSpecImpl(
+ override val from: SceneKey?,
+ override val to: SceneKey?,
+ private val transformationSpec: () -> TransformationSpecImpl,
+) : TransitionSpec {
+ override fun reversed(): TransitionSpecImpl {
+ return TransitionSpecImpl(
from = to,
to = from,
- transformations = transformations.fastMap { it.reverse() },
+ transformationSpec = {
+ val reverse = transformationSpec.invoke()
+ TransformationSpecImpl(
+ progressSpec = reverse.progressSpec,
+ transformations = reverse.transformations.map { it.reversed() }
+ )
+ }
)
}
+ override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke()
+}
+
+/**
+ * An implementation of [TransformationSpec] that allows the quick retrieval of an element
+ * [ElementTransformations].
+ */
+internal class TransformationSpecImpl(
+ override val progressSpec: AnimationSpec<Float>,
+ override val transformations: List<Transformation>,
+) : TransformationSpec {
+ private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
+
internal fun transformations(element: ElementKey, scene: SceneKey): ElementTransformations {
return cache
.getOrPut(element) { mutableMapOf() }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index 116a666..0d3bc7d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -27,7 +27,8 @@
fun Scene.shouldEnableSwipes(orientation: Orientation): Boolean =
userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
- val currentScene = gestureHandler.currentScene
+ val layoutImpl = gestureHandler.layoutImpl
+ val currentScene = layoutImpl.scene(layoutImpl.state.transitionState.currentScene)
val orientation = gestureHandler.orientation
val canSwipe = currentScene.shouldEnableSwipes(orientation)
val canOppositeSwipe =
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 8f4a36e..7046866 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -44,7 +44,7 @@
}
private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
- val transitionSpecs = mutableListOf<TransitionSpec>()
+ val transitionSpecs = mutableListOf<TransitionSpecImpl>()
override fun to(to: SceneKey, builder: TransitionBuilder.() -> Unit): TransitionSpec {
return transition(from = null, to = to, builder)
@@ -63,14 +63,15 @@
to: SceneKey?,
builder: TransitionBuilder.() -> Unit,
): TransitionSpec {
- val impl = TransitionBuilderImpl().apply(builder)
- val spec =
- TransitionSpec(
- from,
- to,
- impl.transformations,
- impl.spec,
+ fun transformationSpec(): TransformationSpecImpl {
+ val impl = TransitionBuilderImpl().apply(builder)
+ return TransformationSpecImpl(
+ progressSpec = impl.spec,
+ transformations = impl.transformations,
)
+ }
+
+ val spec = TransitionSpecImpl(from, to, ::transformationSpec)
transitionSpecs.add(spec)
return spec
}
@@ -143,7 +144,7 @@
transformations.add(
if (reversed) {
- transformation.reverse()
+ transformation.reversed()
} else {
transformation
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 20693555..0cd11b9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -42,7 +42,7 @@
* Reverse this transformation. This is called when we use Transition(from = A, to = B) when
* animating from B to A and there is no Transition(from = B, to = A) defined.
*/
- fun reverse(): Transformation = this
+ fun reversed(): Transformation = this
}
internal class SharedElementTransformation(
@@ -77,10 +77,10 @@
val delegate: PropertyTransformation<T>,
override val range: TransformationRange,
) : PropertyTransformation<T> by delegate {
- override fun reverse(): Transformation {
+ override fun reversed(): Transformation {
return RangedPropertyTransformation(
- delegate.reverse() as PropertyTransformation<T>,
- range.reverse()
+ delegate.reversed() as PropertyTransformation<T>,
+ range.reversed()
)
}
}
@@ -102,7 +102,7 @@
}
/** Reverse this range. */
- fun reverse() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
+ fun reversed() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
/** Get the progress of this range given the global [transitionProgress]. */
fun progress(transitionProgress: Float): Float {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index e6224df..d9ce519 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -55,8 +55,8 @@
) {
private var internalCurrentScene: SceneKey by mutableStateOf(SceneA)
- private val layoutState: SceneTransitionLayoutState =
- SceneTransitionLayoutState(internalCurrentScene)
+ private val layoutState =
+ SceneTransitionLayoutStateImpl(internalCurrentScene, EmptyTestTransitions)
val mutableUserActionsA: MutableMap<UserAction, SceneKey> =
mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC)
@@ -93,36 +93,24 @@
private val layoutImpl =
SceneTransitionLayoutImpl(
- onChangeScene = { internalCurrentScene = it },
- builder = scenesBuilder,
- transitions = EmptyTestTransitions,
state = layoutState,
+ onChangeScene = { internalCurrentScene = it },
density = Density(1f),
edgeDetector = DefaultEdgeDetector,
transitionInterceptionThreshold = transitionInterceptionThreshold,
+ builder = scenesBuilder,
coroutineScope = coroutineScope,
)
.apply { setScenesTargetSizeForTest(LAYOUT_SIZE) }
- val sceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Vertical,
- coroutineScope = coroutineScope,
- )
-
- val horizontalSceneGestureHandler =
- SceneGestureHandler(
- layoutImpl = layoutImpl,
- orientation = Orientation.Horizontal,
- coroutineScope = coroutineScope,
- )
-
+ val sceneGestureHandler = layoutImpl.gestureHandler(Orientation.Vertical)
+ val horizontalSceneGestureHandler = layoutImpl.gestureHandler(Orientation.Horizontal)
val draggable = sceneGestureHandler.draggable
fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) =
SceneNestedScrollHandler(
- gestureHandler = sceneGestureHandler,
+ layoutImpl,
+ orientation = sceneGestureHandler.orientation,
topOrLeftBehavior = nestedScrollBehavior,
bottomOrRightBehavior = nestedScrollBehavior,
)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index eeda8d46..c5b8d9a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -40,8 +40,8 @@
@Test
fun isTransitioningTo_transition() {
- val state = SceneTransitionLayoutState(TestScenes.SceneA)
- state.transitionState = transition(from = TestScenes.SceneA, to = TestScenes.SceneB)
+ val state = SceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty)
+ state.startTransition(transition(from = TestScenes.SceneA, to = TestScenes.SceneB))
assertThat(state.isTransitioning()).isTrue()
assertThat(state.isTransitioning(from = TestScenes.SceneA)).isTrue()
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index fa94b250..ef72992 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -55,7 +55,7 @@
assertThat(transitions.transitionSpecs)
.comparingElementsUsing(
- Correspondence.transforming<TransitionSpec, Pair<SceneKey?, SceneKey?>>(
+ Correspondence.transforming<TransitionSpecImpl, Pair<SceneKey?, SceneKey?>>(
{ it?.from to it?.to },
"has (from, to) equal to"
)
@@ -70,8 +70,8 @@
@Test
fun defaultTransitionSpec() {
val transitions = transitions { from(TestScenes.SceneA, to = TestScenes.SceneB) }
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(SpringSpec::class.java)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(SpringSpec::class.java)
}
@Test
@@ -79,9 +79,9 @@
val transitions = transitions {
from(TestScenes.SceneA, to = TestScenes.SceneB) { spec = tween(durationMillis = 42) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.spec).isInstanceOf(TweenSpec::class.java)
- assertThat((transition.spec as TweenSpec).durationMillis).isEqualTo(42)
+ val transformationSpec = transitions.transitionSpecs.single().transformationSpec()
+ assertThat(transformationSpec.progressSpec).isInstanceOf(TweenSpec::class.java)
+ assertThat((transformationSpec.progressSpec as TweenSpec).durationMillis).isEqualTo(42)
}
@Test
@@ -90,9 +90,10 @@
from(TestScenes.SceneA, to = TestScenes.SceneB) { fade(TestElements.Foo) }
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations.size).isEqualTo(1)
- assertThat(transition.transformations.single().range).isEqualTo(null)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations.size).isEqualTo(1)
+ assertThat(transformations.single().range).isEqualTo(null)
}
@Test
@@ -105,8 +106,9 @@
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 0.1f, end = 0.8f),
@@ -127,8 +129,9 @@
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 100 / 500f, end = 300 / 500f),
@@ -149,8 +152,9 @@
}
}
- val transition = transitions.transitionSpecs.single()
- assertThat(transition.transformations)
+ val transformations =
+ transitions.transitionSpecs.single().transformationSpec().transformations
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
@@ -170,9 +174,13 @@
// Fetch the transition from B to A, which will automatically reverse the transition from A
// to B we defined.
- val transition =
- transitions.transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
- assertThat(transition.transformations)
+ val transformations =
+ transitions
+ .transitionSpec(from = TestScenes.SceneB, to = TestScenes.SceneA)
+ .transformationSpec()
+ .transformations
+
+ assertThat(transformations)
.comparingElementsUsing(TRANSFORMATION_RANGE)
.containsExactly(
TransformationRange(start = 1f - 0.8f, end = 1f - 0.1f),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 695d888..f170135 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -18,7 +18,7 @@
package com.android.keyguard
import android.content.res.Configuration
-import android.hardware.biometrics.BiometricOverlayConstants
+import android.hardware.biometrics.BiometricRequestConstants
import android.media.AudioManager
import android.telephony.TelephonyManager
import android.testing.TestableLooper.RunWithLooper
@@ -59,6 +59,7 @@
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -235,6 +236,7 @@
sceneInteractor = sceneInteractor,
)
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest =
KeyguardSecurityContainerController(
view,
@@ -763,16 +765,18 @@
@Test
fun sideFpsControllerShow() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ true)
verify(sideFpsController)
.show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
)
}
@Test
fun sideFpsControllerHide() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
underTest.updateSideFpsVisibility(/* isVisible= */ false)
verify(sideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
new file mode 100644
index 0000000..74f50d8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2023 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.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionRepositoryImplTest : SysuiTestCase() {
+ companion object {
+ val TEST_USER_1 = UserHandle.of(1)!!
+ val TEST_USER_2 = UserHandle.of(2)!!
+ }
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val settings: FakeSettings = FakeSettings()
+
+ private lateinit var underTest: ColorCorrectionRepository
+
+ @Before
+ fun setUp() {
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+ }
+
+ @Test
+ fun isEnabled_initiallyGetsSettingsValue() =
+ scope.runTest {
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ 1,
+ TEST_USER_1.identifier
+ )
+
+ underTest =
+ ColorCorrectionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ runCurrent()
+
+ val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first()
+ Truth.assertThat(actualValue).isTrue()
+ }
+
+ @Test
+ fun isEnabled_settingUpdated_valueUpdated() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ }
+
+ @Test
+ fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_1.identifier
+ )
+ underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope)
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.DISABLED,
+ TEST_USER_2.identifier
+ )
+
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+
+ settings.putIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ ColorCorrectionRepositoryImpl.ENABLED,
+ TEST_USER_1.identifier
+ )
+ runCurrent()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+ Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+ }
+
+ @Test
+ fun setEnabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(true, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.ENABLED)
+ }
+
+ @Test
+ fun setDisabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(false, TEST_USER_1)
+ runCurrent()
+ Truth.assertThat(success).isTrue()
+
+ val actualValue =
+ settings.getIntForUser(
+ ColorCorrectionRepositoryImpl.SETTING_NAME,
+ TEST_USER_1.identifier
+ )
+ Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.DISABLED)
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index a1b801c..f8321b7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -22,9 +22,9 @@
import android.content.ComponentName
import android.graphics.Insets
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.biometrics.SensorProperties
import android.hardware.display.DisplayManager
@@ -65,6 +65,7 @@
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -144,6 +145,7 @@
@Before
fun setup() {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
displayRepository = FakeDisplayRepository()
displayStateRepository = FakeDisplayStateRepository()
keyguardBouncerRepository = FakeKeyguardBouncerRepository()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 90d36e7..a726b7c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -17,12 +17,12 @@
package com.android.systemui.biometrics
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
@@ -135,7 +135,7 @@
}
private fun withReason(
- @ShowReason reason: Int,
+ @RequestReason reason: Int,
isDebuggable: Boolean = false,
enableDeviceEntryUdfpsRefactor: Boolean = false,
block: () -> Unit,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 97ee526..dddcf18 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -43,7 +43,7 @@
import android.graphics.Rect;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.SensorProperties;
import android.hardware.display.DisplayManager;
@@ -359,7 +359,7 @@
@Test
public void dozeTimeTick() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
mUdfpsController.dozeTimeTick();
verify(mUdfpsView).dozeTimeTick();
@@ -455,7 +455,7 @@
public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
// GIVEN overlay was showing and the udfps bouncer is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
// WHEN the overlay is hidden
@@ -469,7 +469,7 @@
@Test
public void showUdfpsOverlay_callsListener() throws RemoteException {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mFingerprintManager).onUdfpsUiEvent(FingerprintManager.UDFPS_UI_OVERLAY_SHOWN,
@@ -479,7 +479,7 @@
@Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong());
@@ -520,7 +520,7 @@
reset(mWindowManager);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID,
mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING,
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING,
mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -555,7 +555,7 @@
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -637,7 +637,7 @@
// Show the overlay.
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -720,7 +720,7 @@
initUdfpsController(testParams.sensorProps);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// WHEN ACTION_DOWN is received
@@ -778,7 +778,7 @@
// GIVEN that the overlay is showing and screen is on and fp is running
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
// WHEN fingerprint is requested because of AOD interrupt
@@ -808,7 +808,7 @@
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -886,7 +886,7 @@
// GIVEN overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
@@ -917,7 +917,7 @@
// GIVEN AOD interrupt
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
@@ -958,7 +958,7 @@
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
givenFingerEvent(InteractionEvent.DOWN, InteractionEvent.UP, false);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
if (testParams.sensorProps.sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL) {
// Configure UdfpsView to accept the ACTION_UP event
@@ -1019,7 +1019,7 @@
// GIVEN screen off
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOff();
mFgExecutor.runAllReady();
@@ -1041,7 +1041,7 @@
// GIVEN showing overlay
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, testParams.sensorProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
@@ -1126,7 +1126,7 @@
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(a11y);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
if (a11y) {
@@ -1148,7 +1148,7 @@
// GIVEN that the overlay is showing and a11y touch exploration NOT enabled
when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1197,7 +1197,7 @@
-1 /* pointerId */, touchData);
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
@@ -1289,7 +1289,7 @@
public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
@@ -1316,7 +1316,7 @@
throws RemoteException {
// GIVEN UDFPS overlay is showing
mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
mFgExecutor.runAllReady();
// GIVEN there's been an AoD interrupt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
index 90e0c19..a3bf3f4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModelTest.kt
@@ -33,6 +33,7 @@
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.utils.os.FakeHandler
@@ -105,8 +106,10 @@
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_show() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
repository.setPrimaryShow(true)
@@ -116,8 +119,10 @@
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun shouldUpdateSideFps_hide() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
repository.setPrimaryShow(true)
var count = 0
val job = underTest.shouldUpdateSideFps.onEach { count++ }.launchIn(this)
@@ -128,8 +133,10 @@
job.cancel()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun sideFpsShowing() = runTest {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
var sideFpsIsShowing = false
val job = underTest.sideFpsShowing.onEach { sideFpsIsShowing = it }.launchIn(this)
repository.setSideFpsShowing(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
index 45aca17..d6d5b23 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt
@@ -827,25 +827,6 @@
}
@Test
- fun isAuthenticatedIsResetToFalseWhenKeyguardIsGoingAway() =
- testScope.runTest {
- initCollectors()
- allPreconditionsToRunFaceAuthAreTrue()
-
- triggerFaceAuth(false)
-
- authenticationCallback.value.onAuthenticationSucceeded(
- mock(FaceManager.AuthenticationResult::class.java)
- )
-
- assertThat(authenticated()).isTrue()
-
- keyguardRepository.setKeyguardGoingAway(true)
-
- assertThat(authenticated()).isFalse()
- }
-
- @Test
fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() =
testScope.runTest {
initCollectors()
@@ -906,6 +887,25 @@
}
@Test
+ fun isAuthenticatedIsResetToFalseWhenKeyguardDoneAnimationsFinished() =
+ testScope.runTest {
+ initCollectors()
+ allPreconditionsToRunFaceAuthAreTrue()
+
+ triggerFaceAuth(false)
+
+ authenticationCallback.value.onAuthenticationSucceeded(
+ mock(FaceManager.AuthenticationResult::class.java)
+ )
+
+ assertThat(authenticated()).isTrue()
+
+ keyguardRepository.keyguardDoneAnimationsFinished()
+
+ assertThat(authenticated()).isFalse()
+ }
+
+ @Test
fun detectDoesNotRunWhenFaceIsNotUsuallyAllowed() =
testScope.runTest {
testGatingCheckForDetect {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index 2b7221e..6b7d263 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -304,4 +304,34 @@
)
assertThat(authenticationStatus).isNull()
}
+
+ @Test
+ fun onBiometricRunningStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback {
+ it.onBiometricRunningStateChanged(false, BiometricSourceType.FINGERPRINT)
+ }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
+
+ @Test
+ fun onStrongAuthStateChanged_shouldUpdateIndicatorVisibility() =
+ testScope.runTest {
+ val shouldUpdateIndicatorVisibility by
+ collectLastValue(underTest.shouldUpdateIndicatorVisibility)
+ runCurrent()
+
+ verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+ assertThat(shouldUpdateIndicatorVisibility).isFalse()
+
+ invokeOnCallback { it.onStrongAuthStateChanged(0) }
+ assertThat(shouldUpdateIndicatorVisibility).isTrue()
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
new file mode 100644
index 0000000..8ee6d20
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapperTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.impl.colorcorrection.qsColorCorrectionTileConfig
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val colorCorrectionTileConfig = kosmos.qsColorCorrectionTileConfig
+ private val subtitleArray =
+ context.resources.getStringArray(R.array.tile_states_color_correction)
+ // Using lazy (versus =) to make sure we override the right context -- see b/311612168
+ private val mapper by lazy {
+ ColorCorrectionTileMapper(
+ context.orCreateTestableResources
+ .apply { addOverride(R.drawable.ic_qs_color_correction, TestStubDrawable()) }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun disabledModel() {
+ val inputModel = ColorCorrectionTileModel(false)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.INACTIVE, subtitleArray[1])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun enabledModel() {
+ val inputModel = ColorCorrectionTileModel(true)
+
+ val outputState = mapper.map(colorCorrectionTileConfig, inputModel)
+
+ val expectedState =
+ createColorCorrectionTileState(QSTileState.ActivationState.ACTIVE, subtitleArray[2])
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createColorCorrectionTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String
+ ): QSTileState {
+ val label = context.getString(R.string.quick_settings_color_correction_label)
+ return QSTileState(
+ { Icon.Loaded(context.getDrawable(R.drawable.ic_qs_color_correction)!!, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.None,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
new file mode 100644
index 0000000..8c612ac
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileDataInteractorTest : SysuiTestCase() {
+
+ private val colorCorrectionRepository = FakeColorCorrectionRepository()
+ private val underTest: ColorCorrectionTileDataInteractor =
+ ColorCorrectionTileDataInteractor(colorCorrectionRepository)
+
+ @Test
+ fun alwaysAvailable() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).hasSize(1)
+ assertThat(availability.last()).isTrue()
+ }
+
+ @Test
+ fun dataMatchesTheRepository() = runTest {
+ val dataList: List<ColorCorrectionTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(true, TEST_USER)
+ runCurrent()
+
+ colorCorrectionRepository.setIsEnabled(false, TEST_USER)
+ runCurrent()
+
+ assertThat(dataList).hasSize(3)
+ assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false))
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
new file mode 100644
index 0000000..3049cc0
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.CURRENT
+ private val repository = FakeColorCorrectionRepository()
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+ private val underTest =
+ ColorCorrectionUserActionInteractor(
+ repository,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorCorrectionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorCorrectionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ }
+ }
+}
diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 4d95220..fc4bf8a 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.biometrics.SideFpsLottieViewWrapper
+<com.android.systemui.biometrics.SideFpsIndicatorView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sidefps_animation"
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
index 80f70a0..3064829 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/BiometricModalities.kt
@@ -37,6 +37,10 @@
val hasSfps: Boolean
get() = hasFingerprint && fingerprintProperties!!.isAnySidefpsType
+ /** If UDFPS authentication is available. */
+ val hasUdfps: Boolean
+ get() = hasFingerprint && fingerprintProperties!!.isAnyUdfpsType
+
/** If fingerprint authentication is available (and [faceProperties] is non-null). */
val hasFace: Boolean
get() = faceProperties != null
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
index df7182b..0169f59 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InteractionJankMonitorWrapper.java
@@ -49,6 +49,7 @@
public static final int CUJ_APP_SWIPE_TO_RECENTS = Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS;
public static final int CUJ_OPEN_SEARCH_RESULT = Cuj.CUJ_LAUNCHER_OPEN_SEARCH_RESULT;
public static final int CUJ_LAUNCHER_UNFOLD_ANIM = Cuj.CUJ_LAUNCHER_UNFOLD_ANIM;
+ public static final int CUJ_SEARCH_QSB_OPEN = Cuj.CUJ_LAUNCHER_SEARCH_QSB_OPEN;
@IntDef({
CUJ_APP_LAUNCH_FROM_RECENTS,
@@ -66,6 +67,7 @@
CUJ_CLOSE_ALL_APPS_TO_HOME,
CUJ_OPEN_SEARCH_RESULT,
CUJ_LAUNCHER_UNFOLD_ANIM,
+ CUJ_SEARCH_QSB_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0a4378e..cce2018 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -38,7 +38,7 @@
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Resources;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.media.AudioManager;
import android.metrics.LogMaker;
import android.os.SystemClock;
@@ -74,6 +74,7 @@
import com.android.systemui.biometrics.FaceAuthAccessibilityDelegate;
import com.android.systemui.biometrics.SideFpsController;
import com.android.systemui.biometrics.SideFpsUiRequestSource;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.classifier.FalsingA11yDelegate;
@@ -486,7 +487,11 @@
mSceneContainerFlags = sceneContainerFlags;
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
- mSideFpsController = sideFpsController;
+ if (SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = Optional.empty();
+ } else {
+ mSideFpsController = sideFpsController;
+ }
mFalsingA11yDelegate = falsingA11yDelegate;
mTelephonyManager = telephonyManager;
mViewMediatorCallback = viewMediatorCallback;
@@ -569,12 +574,14 @@
mView.clearFocus();
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Shows and hides the side finger print sensor animation.
*
* @param isVisible sets whether we show or hide the side fps animation
*/
public void updateSideFpsVisibility(boolean isVisible) {
+ SideFpsControllerRefactor.assertInLegacyMode();
if (!mSideFpsController.isPresent()) {
return;
}
@@ -582,7 +589,7 @@
if (isVisible) {
mSideFpsController.get().show(
SideFpsUiRequestSource.PRIMARY_BOUNCER,
- BiometricOverlayConstants.REASON_AUTH_KEYGUARD
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD
);
} else {
mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
index ca859de..24aa11e 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -16,61 +16,16 @@
package com.android.systemui.accessibility
-import com.android.systemui.qs.tileimpl.QSTileImpl
-import com.android.systemui.qs.tiles.ColorCorrectionTile
-import com.android.systemui.qs.tiles.ColorInversionTile
-import com.android.systemui.qs.tiles.DreamTile
-import com.android.systemui.qs.tiles.FontScalingTile
-import com.android.systemui.qs.tiles.NightDisplayTile
-import com.android.systemui.qs.tiles.OneHandedModeTile
-import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
-import dagger.multibindings.IntoMap
-import dagger.multibindings.StringKey
-@Module
+@Module(includes = [QSAccessibilityModule::class])
interface AccessibilityModule {
-
- /** Inject ColorInversionTile into tileMap in QSModule */
@Binds
- @IntoMap
- @StringKey(ColorInversionTile.TILE_SPEC)
- fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
-
- /** Inject NightDisplayTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(NightDisplayTile.TILE_SPEC)
- fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
-
- /** Inject ReduceBrightColorsTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ReduceBrightColorsTile.TILE_SPEC)
- fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
-
- /** Inject OneHandedModeTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(OneHandedModeTile.TILE_SPEC)
- fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
-
- /** Inject ColorCorrectionTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(ColorCorrectionTile.TILE_SPEC)
- fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
-
- /** Inject DreamTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(DreamTile.TILE_SPEC)
- fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
-
- /** Inject FontScalingTile into tileMap in QSModule */
- @Binds
- @IntoMap
- @StringKey(FontScalingTile.TILE_SPEC)
- fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+ abstract fun colorCorrectionRepository(
+ impl: ColorCorrectionRepositoryImpl
+ ): ColorCorrectionRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt
new file mode 100644
index 0000000..6483ae4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 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.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings.Secure
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Provides data related to color correction. */
+interface ColorCorrectionRepository {
+ /** Observable for whether color correction is enabled */
+ fun isEnabled(userHandle: UserHandle): Flow<Boolean>
+
+ /** Sets color correction enabled state. */
+ suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
+}
+
+@SysUISingleton
+class ColorCorrectionRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ private val secureSettings: SecureSettings,
+) : ColorCorrectionRepository {
+
+ companion object {
+ const val SETTING_NAME = Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED
+ const val DISABLED = 0
+ const val ENABLED = 1
+ }
+
+ override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
+ secureSettings
+ .observerFlow(userHandle.identifier, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getIntForUser(SETTING_NAME, userHandle.identifier) == ENABLED }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
+ withContext(bgCoroutineContext) {
+ secureSettings.putIntForUser(
+ SETTING_NAME,
+ if (isEnabled) ENABLED else DISABLED,
+ userHandle.identifier
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
new file mode 100644
index 0000000..df7fdb8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2023 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.systemui.accessibility.qs
+
+import com.android.systemui.qs.QsEventLogger
+import com.android.systemui.qs.pipeline.shared.TileSpec
+import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.qs.tiles.ColorCorrectionTile
+import com.android.systemui.qs.tiles.ColorInversionTile
+import com.android.systemui.qs.tiles.DreamTile
+import com.android.systemui.qs.tiles.FontScalingTile
+import com.android.systemui.qs.tiles.NightDisplayTile
+import com.android.systemui.qs.tiles.OneHandedModeTile
+import com.android.systemui.qs.tiles.ReduceBrightColorsTile
+import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrectionTileMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
+import com.android.systemui.res.R
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+@Module
+interface QSAccessibilityModule {
+
+ /** Inject ColorInversionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorInversionTile.TILE_SPEC)
+ fun bindColorInversionTile(colorInversionTile: ColorInversionTile): QSTileImpl<*>
+
+ /** Inject NightDisplayTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(NightDisplayTile.TILE_SPEC)
+ fun bindNightDisplayTile(nightDisplayTile: NightDisplayTile): QSTileImpl<*>
+
+ /** Inject ReduceBrightColorsTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ReduceBrightColorsTile.TILE_SPEC)
+ fun bindReduceBrightColorsTile(reduceBrightColorsTile: ReduceBrightColorsTile): QSTileImpl<*>
+
+ /** Inject OneHandedModeTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(OneHandedModeTile.TILE_SPEC)
+ fun bindOneHandedModeTile(oneHandedModeTile: OneHandedModeTile): QSTileImpl<*>
+
+ /** Inject ColorCorrectionTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(ColorCorrectionTile.TILE_SPEC)
+ fun bindColorCorrectionTile(colorCorrectionTile: ColorCorrectionTile): QSTileImpl<*>
+
+ /** Inject DreamTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(DreamTile.TILE_SPEC)
+ fun bindDreamTile(dreamTile: DreamTile): QSTileImpl<*>
+
+ /** Inject FontScalingTile into tileMap in QSModule */
+ @Binds
+ @IntoMap
+ @StringKey(FontScalingTile.TILE_SPEC)
+ fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
+
+ companion object {
+
+ const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
+
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.ic_qs_color_correction,
+ labelRes = R.string.quick_settings_color_correction_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject ColorCorrectionTile into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_CORRECTION_TILE_SPEC)
+ fun provideColorCorrectionTileViewModel(
+ factory: QSTileViewModelFactory.Static<ColorCorrectionTileModel>,
+ mapper: ColorCorrectionTileMapper,
+ stateInteractor: ColorCorrectionTileDataInteractor,
+ userActionInteractor: ColorCorrectionUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(COLOR_CORRECTION_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 877afce7..5fba761 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -70,6 +70,7 @@
import com.android.systemui.biometrics.domain.interactor.LogContextInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor;
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor;
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor;
import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
@@ -88,6 +89,8 @@
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -101,7 +104,6 @@
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
import kotlinx.coroutines.CoroutineScope;
/**
@@ -317,7 +319,9 @@
mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
if (mSidefpsProps != null) {
- mSideFpsController = mSidefpsControllerFactory.get();
+ if (!SideFpsControllerRefactor.isEnabled()) {
+ mSideFpsController = mSidefpsControllerFactory.get();
+ }
}
mFingerprintManager.registerBiometricStateListener(new BiometricStateListener() {
@@ -1194,7 +1198,7 @@
* Whether the passed userId has enrolled SFPS.
*/
public boolean isSfpsEnrolled(int userId) {
- if (mSideFpsController == null) {
+ if (mSidefpsProps == null) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 91cee9e..ac99fc6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -23,9 +23,9 @@
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.SensorLocationInternal
import android.hardware.display.DisplayManager
import android.hardware.fingerprint.FingerprintManager
@@ -58,6 +58,7 @@
import com.android.keyguard.KeyguardPINView
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -91,7 +92,7 @@
@Main private val mainExecutor: DelayableExecutor,
@Main private val handler: Handler,
private val alternateBouncerInteractor: AlternateBouncerInteractor,
- @Application private val scope: CoroutineScope,
+ @Application private val applicationScope: CoroutineScope,
dumpManager: DumpManager,
fpsUnlockTracker: FpsUnlockTracker
) : Dumpable {
@@ -110,7 +111,7 @@
handler,
sensorProps,
{ reason -> onOrientationChanged(reason) },
- BiometricOverlayConstants.REASON_UNKNOWN
+ BiometricRequestConstants.REASON_UNKNOWN
)
@VisibleForTesting val orientationListener = orientationReasonListener.orientationListener
@@ -169,25 +170,27 @@
}
init {
- fpsUnlockTracker.startTracking()
- fingerprintManager?.setSidefpsController(
- object : ISidefpsController.Stub() {
- override fun show(
- sensorId: Int,
- @BiometricOverlayConstants.ShowReason reason: Int
- ) =
- if (reason.isReasonToAutoShow(activityTaskManager)) {
- show(SideFpsUiRequestSource.AUTO_SHOW, reason)
- } else {
- hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
+ if (!SideFpsControllerRefactor.isEnabled) {
+ fpsUnlockTracker.startTracking()
+ fingerprintManager?.setSidefpsController(
+ object : ISidefpsController.Stub() {
+ override fun show(
+ sensorId: Int,
+ @BiometricRequestConstants.RequestReason reason: Int
+ ) =
+ if (reason.isReasonToAutoShow(activityTaskManager)) {
+ show(SideFpsUiRequestSource.AUTO_SHOW, reason)
+ } else {
+ hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
- override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
- }
- )
- listenForAlternateBouncerVisibility()
+ override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW)
+ }
+ )
+ listenForAlternateBouncerVisibility()
- dumpManager.registerDumpable(this)
+ dumpManager.registerDumpable(this)
+ }
}
private fun listenForAlternateBouncerVisibility() {
@@ -195,7 +198,7 @@
alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, "SideFpsController")
}
- scope.launch {
+ applicationScope.launch {
alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
if (isVisible) {
show(SideFpsUiRequestSource.ALTERNATE_BOUNCER, REASON_AUTH_KEYGUARD)
@@ -209,8 +212,10 @@
/** Shows the side fps overlay if not already shown. */
fun show(
request: SideFpsUiRequestSource,
- @BiometricOverlayConstants.ShowReason reason: Int = BiometricOverlayConstants.REASON_UNKNOWN
+ @BiometricRequestConstants.RequestReason
+ reason: Int = BiometricRequestConstants.REASON_UNKNOWN
) {
+ SideFpsControllerRefactor.assertInLegacyMode()
if (!displayStateInteractor.isInRearDisplayMode.value) {
requests.add(request)
mainExecutor.execute {
@@ -229,6 +234,7 @@
/** Hides the fps overlay if shown. */
fun hide(request: SideFpsUiRequestSource) {
+ SideFpsControllerRefactor.assertInLegacyMode()
requests.remove(request)
mainExecutor.execute {
if (requests.isEmpty()) {
@@ -239,6 +245,7 @@
/** Hide the arrow indicator. */
fun hideIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = INVISIBLE
@@ -246,6 +253,7 @@
/** Show the arrow indicator. */
fun showIndicator() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val lottieAnimationView =
overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView?
lottieAnimationView?.visibility = VISIBLE
@@ -279,13 +287,13 @@
pw.println("currentRotation=${displayInfo.rotation}")
}
- private fun onOrientationChanged(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun onOrientationChanged(@BiometricRequestConstants.RequestReason reason: Int) {
if (overlayView != null) {
createOverlayForDisplay(reason)
}
}
- private fun createOverlayForDisplay(@BiometricOverlayConstants.ShowReason reason: Int) {
+ private fun createOverlayForDisplay(@BiometricRequestConstants.RequestReason reason: Int) {
val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
overlayView = view
val display = context.display!!
@@ -395,7 +403,7 @@
/** Returns [True] when the device has a side fingerprint sensor. */
fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null
-@BiometricOverlayConstants.ShowReason
+@BiometricRequestConstants.RequestReason
private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean =
when (this) {
REASON_AUTH_KEYGUARD -> false
@@ -434,7 +442,7 @@
private fun LottieAnimationView.addOverlayDynamicColor(
context: Context,
- @BiometricOverlayConstants.ShowReason reason: Int
+ @BiometricRequestConstants.RequestReason reason: Int
) {
fun update() {
val isKeyguard = reason == REASON_AUTH_KEYGUARD
@@ -501,7 +509,7 @@
handler: Handler,
sensorProps: FingerprintSensorPropertiesInternal,
onOrientationChanged: (reason: Int) -> Unit,
- @BiometricOverlayConstants.ShowReason var reason: Int
+ @BiometricRequestConstants.RequestReason var reason: Int
) {
val orientationListener =
BiometricDisplayListener(
@@ -516,7 +524,7 @@
/**
* The source of a request to show the side fps visual indicator. This is distinct from
- * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is
+ * [BiometricRequestConstants] which corresponds with the reason fingerprint authentication is
* requested.
*/
enum class SideFpsUiRequestSource {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
rename to packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
index e98f6db..d5e25ac 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsIndicatorView.kt
@@ -19,6 +19,6 @@
import android.util.AttributeSet
import com.android.systemui.util.wrapper.LottieViewWrapper
-class SideFpsLottieViewWrapper
+class SideFpsIndicatorView
@JvmOverloads
constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index bb6ef41..65668b56 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -19,10 +19,10 @@
import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
-import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING;
+import static android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
import static com.android.internal.util.LatencyTracker.ACTION_UDFPS_ILLUMINATE;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -106,6 +106,8 @@
import dagger.Lazy;
+import kotlin.Unit;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashSet;
@@ -115,8 +117,6 @@
import javax.inject.Inject;
import javax.inject.Provider;
-import kotlin.Unit;
-
import kotlinx.coroutines.ExperimentalCoroutinesApi;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 452cd6a..dae6d08 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -21,13 +21,13 @@
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.RequestReason
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.os.Build
import android.os.RemoteException
@@ -96,7 +96,7 @@
private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
val requestId: Long,
- @ShowReason val requestReason: Int,
+ @RequestReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
private val activityLaunchAnimator: ActivityLaunchAnimator,
@@ -461,7 +461,7 @@
}
}
-@ShowReason
+@RequestReason
private fun Int.isImportantForAccessibility() =
this == REASON_ENROLL_FIND_SENSOR ||
this == REASON_ENROLL_ENROLLING ||
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
index e3dbcb5..88b9e1b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
@@ -18,13 +18,13 @@
import android.content.Context
import android.graphics.Rect
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
-import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.hardware.biometrics.BiometricRequestConstants.REASON_UNKNOWN
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.util.Log
import android.view.LayoutInflater
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
index 72fcfe7..8ae6f87 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
@@ -18,8 +18,11 @@
import android.content.res.Resources
import com.android.internal.R
+import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.EllipseOverlapDetectorParams
import com.android.systemui.biometrics.UdfpsUtils
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepositoryImpl
import com.android.systemui.biometrics.data.repository.DisplayStateRepository
import com.android.systemui.biometrics.data.repository.DisplayStateRepositoryImpl
import com.android.systemui.biometrics.data.repository.FacePropertyRepository
@@ -33,11 +36,14 @@
import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
import com.android.systemui.biometrics.udfps.OverlapDetector
+import com.android.systemui.biometrics.ui.binder.SideFpsOverlayViewBinder
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.util.concurrency.ThreadFactory
import dagger.Binds
import dagger.Module
import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
import java.util.concurrent.Executor
import javax.inject.Qualifier
@@ -46,6 +52,11 @@
interface BiometricsModule {
@Binds
+ @IntoMap
+ @ClassKey(SideFpsOverlayViewBinder::class)
+ fun bindsSideFpsOverlayViewBinder(viewBinder: SideFpsOverlayViewBinder): CoreStartable
+
+ @Binds
@SysUISingleton
fun faceSettings(impl: FaceSettingsRepositoryImpl): FaceSettingsRepository
@@ -57,6 +68,10 @@
@Binds
@SysUISingleton
+ fun biometricStatusRepository(impl: BiometricStatusRepositoryImpl): BiometricStatusRepository
+
+ @Binds
+ @SysUISingleton
fun fingerprintRepository(
impl: FingerprintPropertyRepositoryImpl
): FingerprintPropertyRepository
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
new file mode 100644
index 0000000..ad2136a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepository.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.shareIn
+
+/** A repository for the state of biometric authentication. */
+interface BiometricStatusRepository {
+ /**
+ * The logical reason for the current fingerprint auth operation if one is on-going, otherwise
+ * [NotRunning].
+ */
+ val fingerprintAuthenticationReason: Flow<AuthenticationReason>
+}
+
+@SysUISingleton
+class BiometricStatusRepositoryImpl
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ private val biometricManager: BiometricManager?
+) : BiometricStatusRepository {
+
+ override val fingerprintAuthenticationReason: Flow<AuthenticationReason> =
+ conflatedCallbackFlow {
+ val updateFingerprintAuthenticateReason = { reason: AuthenticationReason ->
+ trySendWithFailureLogging(
+ reason,
+ TAG,
+ "Error sending fingerprintAuthenticateReason reason"
+ )
+ }
+
+ val authenticationStateListener =
+ object : AuthenticationStateListener.Stub() {
+ override fun onAuthenticationStarted(requestReason: Int) {
+ val authenticationReason =
+ when (requestReason) {
+ REASON_AUTH_BP ->
+ AuthenticationReason.BiometricPromptAuthentication
+ REASON_AUTH_KEYGUARD ->
+ AuthenticationReason.DeviceEntryAuthentication
+ REASON_AUTH_OTHER -> AuthenticationReason.OtherAuthentication
+ REASON_AUTH_SETTINGS ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.OTHER
+ )
+ REASON_ENROLL_ENROLLING ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_ENROLLING
+ )
+ REASON_ENROLL_FIND_SENSOR ->
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ else -> AuthenticationReason.Unknown
+ }
+ updateFingerprintAuthenticateReason(authenticationReason)
+ }
+
+ override fun onAuthenticationStopped() {
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ }
+ }
+
+ updateFingerprintAuthenticateReason(AuthenticationReason.NotRunning)
+ biometricManager?.registerAuthenticationStateListener(authenticationStateListener)
+ awaitClose {
+ biometricManager?.unregisterAuthenticationStateListener(
+ authenticationStateListener
+ )
+ }
+ }
+ .shareIn(applicationScope, started = SharingStarted.Eagerly, replay = 1)
+
+ companion object {
+ private const val TAG = "BiometricStatusRepositoryImpl"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
index b9b2fd8..ec3fd9f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/BiometricsDomainLayerModule.kt
@@ -15,6 +15,8 @@
*/
package com.android.systemui.biometrics.domain
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
import com.android.systemui.biometrics.domain.interactor.CredentialInteractor
import com.android.systemui.biometrics.domain.interactor.CredentialInteractorImpl
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -38,6 +40,12 @@
@Binds
@SysUISingleton
+ fun providesBiometricStatusInteractor(
+ impl: BiometricStatusInteractorImpl
+ ): BiometricStatusInteractor
+
+ @Binds
+ @SysUISingleton
fun providesCredentialInteractor(impl: CredentialInteractorImpl): CredentialInteractor
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
new file mode 100644
index 0000000..55a2d3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractor.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.domain.interactor
+
+import android.app.ActivityTaskManager
+import com.android.systemui.biometrics.data.repository.BiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** Encapsulates business logic for interacting with biometric authentication state. */
+interface BiometricStatusInteractor {
+ /**
+ * The logical reason for the current side fingerprint sensor auth operation if one is on-going,
+ * filtered for when the overlay should be shown, otherwise [NotRunning].
+ */
+ val sfpsAuthenticationReason: Flow<AuthenticationReason>
+}
+
+class BiometricStatusInteractorImpl
+@Inject
+constructor(
+ private val activityTaskManager: ActivityTaskManager,
+ biometricStatusRepository: BiometricStatusRepository,
+) : BiometricStatusInteractor {
+
+ override val sfpsAuthenticationReason: Flow<AuthenticationReason> =
+ biometricStatusRepository.fingerprintAuthenticationReason.map { reason: AuthenticationReason
+ ->
+ if (reason.isReasonToAlwaysUpdateSfpsOverlay(activityTaskManager)) {
+ reason
+ } else {
+ AuthenticationReason.NotRunning
+ }
+ }
+
+ companion object {
+ private const val TAG = "BiometricStatusInteractor"
+ }
+}
+
+/** True if the sfps overlay should always be updated for this request source, false otherwise. */
+private fun AuthenticationReason.isReasonToAlwaysUpdateSfpsOverlay(
+ activityTaskManager: ActivityTaskManager
+): Boolean =
+ when (this) {
+ AuthenticationReason.DeviceEntryAuthentication -> false
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER) ->
+ when (activityTaskManager.topClass()) {
+ // TODO(b/186176653): exclude fingerprint overlays from this list view
+ "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false
+ else -> true
+ }
+ else -> true
+ }
+
+internal fun ActivityTaskManager.topClass(): String =
+ getTasks(1).firstOrNull()?.topActivity?.className ?: ""
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
index f513799..f4231ac 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
@@ -141,7 +141,6 @@
}
}
}
-
SideFpsSensorLocation(
left = sensorLeft,
top = sensorTop,
@@ -149,7 +148,15 @@
isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
)
}
- .distinctUntilChanged()
+ .distinctUntilChanged(
+ areEquivalent = { old: SideFpsSensorLocation, new: SideFpsSensorLocation ->
+ old.left == new.left &&
+ old.top == new.top &&
+ old.length == new.length &&
+ old.isSensorVerticalInDefaultOrientation ==
+ new.isSensorVerticalInDefaultOrientation
+ }
+ )
.onEach {
logger.sensorLocationStateChanged(
it.left,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
new file mode 100644
index 0000000..899b07e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/SideFpsControllerRefactor.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.shared
+
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+import com.android.systemui.shared.Flags
+
+/** Helper for reading or using the sidefps controller refactor flag state. */
+@Suppress("NOTHING_TO_INLINE")
+object SideFpsControllerRefactor {
+ /** The aconfig flag name */
+ const val FLAG_NAME = Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Is the refactor enabled */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.sidefpsControllerRefactor()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
new file mode 100644
index 0000000..0c3debbe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/AuthenticationReason.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.shared.model
+
+/**
+ * The logical reason for a fingerprint auth operation if one is on-going, otherwise [NotRunning].
+ */
+sealed interface AuthenticationReason {
+ /** Device entry requested authentication */
+ data object DeviceEntryAuthentication : AuthenticationReason
+
+ /** Settings requested authentication */
+ data class SettingsAuthentication(val settingsOperation: SettingsOperations) :
+ AuthenticationReason
+
+ /** App requested authentication */
+ data object BiometricPromptAuthentication : AuthenticationReason
+
+ /** Authentication requested for other reason */
+ data object OtherAuthentication : AuthenticationReason
+
+ /** Authentication requested for unknown reason */
+ data object Unknown : AuthenticationReason
+
+ /** Authentication is not running */
+ data object NotRunning : AuthenticationReason
+
+ /** Settings operations that request biometric authentication */
+ enum class SettingsOperations {
+ ENROLL_ENROLLING,
+ ENROLL_FIND_SENSOR,
+ OTHER
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
similarity index 66%
copy from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
copy to packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
index e98f6db..0b30055 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/LottieCallback.kt
@@ -13,12 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.biometrics
-import android.content.Context
-import android.util.AttributeSet
-import com.android.systemui.util.wrapper.LottieViewWrapper
+package com.android.systemui.biometrics.shared.model
-class SideFpsLottieViewWrapper
-@JvmOverloads
-constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
+import com.airbnb.lottie.model.KeyPath
+
+/** Represents properties of a LottieAnimationView callback */
+data class LottieCallback(val keypath: KeyPath, val color: Int)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 32d9067b..90e4a38 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -376,6 +376,22 @@
}
}
+ // Talkback directional guidance
+ backgroundView.setOnHoverListener { _, event ->
+ launch {
+ viewModel.onAnnounceAccessibilityHint(
+ event,
+ accessibilityManager.isTouchExplorationEnabled
+ )
+ }
+ false
+ }
+ launch {
+ viewModel.accessibilityHint.collect { message ->
+ if (message.isNotBlank()) view.announceForAccessibility(message)
+ }
+ }
+
// Play haptics
launch {
viewModel.hapticsToPlay.collect { hapticFeedbackConstant ->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
new file mode 100644
index 0000000..a8c9446
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinder.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.ui.binder
+
+import android.content.Context
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.view.LayoutInflater
+import android.view.View
+import android.view.WindowManager
+import android.view.accessibility.AccessibilityEvent
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieComposition
+import com.airbnb.lottie.LottieProperty
+import com.android.app.animation.Interpolators
+import com.android.keyguard.KeyguardPINView
+import com.android.systemui.CoreStartable
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.NotRunning
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+/** Binds the side fingerprint sensor indicator view to [SideFpsOverlayViewModel]. */
+@SysUISingleton
+class SideFpsOverlayViewBinder
+@Inject
+constructor(
+ @Application private val applicationScope: CoroutineScope,
+ @Application private val applicationContext: Context,
+ private val biometricStatusInteractor: BiometricStatusInteractor,
+ private val displayStateInteractor: DisplayStateInteractor,
+ private val deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ private val fpsUnlockTracker: FpsUnlockTracker,
+ private val layoutInflater: LayoutInflater,
+ private val sideFpsProgressBarViewModel: SideFpsProgressBarViewModel,
+ private val sfpsSensorInteractor: SideFpsSensorInteractor,
+ private val windowManager: WindowManager
+) : CoreStartable {
+
+ override fun start() {
+ if (!SideFpsControllerRefactor.isEnabled) {
+ return
+ }
+ applicationScope
+ .launch {
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry,
+ sideFpsProgressBarViewModel.isVisible,
+ ::Triple
+ )
+ .sample(displayStateInteractor.isInRearDisplayMode, ::Pair)
+ .collect { (combinedFlows, isInRearDisplayMode: Boolean) ->
+ val (
+ systemServerAuthReason,
+ showIndicatorForDeviceEntry,
+ progressBarIsVisible) =
+ combinedFlows
+ if (!isInRearDisplayMode) {
+ if (progressBarIsVisible) {
+ hide()
+ } else if (systemServerAuthReason != NotRunning) {
+ show()
+ } else if (showIndicatorForDeviceEntry) {
+ show()
+ } else {
+ hide()
+ }
+ }
+ }
+ }
+ .invokeOnCompletion { fpsUnlockTracker.stopTracking() }
+ }
+
+ private var overlayView: View? = null
+ private var lottie: LottieAnimationView? = null
+
+ /** Show the side fingerprint sensor indicator */
+ private fun show() {
+ overlayView?.let {
+ if (it.isAttachedToWindow) {
+ lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie?.pauseAnimation()
+ windowManager.removeView(it)
+ }
+ }
+
+ overlayView = layoutInflater.inflate(R.layout.sidefps_view, null, false)
+ val overlayViewModel =
+ SideFpsOverlayViewModel(
+ applicationContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+ bind(overlayView!!, overlayViewModel, fpsUnlockTracker, windowManager)
+ overlayView!!.visibility = View.INVISIBLE
+ windowManager.addView(overlayView, overlayViewModel.defaultOverlayViewParams)
+ }
+
+ /** Hide the side fingerprint sensor indicator */
+ private fun hide() {
+ if (overlayView != null) {
+ windowManager.removeView(overlayView)
+ overlayView = null
+ }
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewBinder"
+
+ /** Binds overlayView (side fingerprint sensor indicator view) to SideFpsOverlayViewModel */
+ fun bind(
+ overlayView: View,
+ viewModel: SideFpsOverlayViewModel,
+ fpsUnlockTracker: FpsUnlockTracker,
+ windowManager: WindowManager
+ ) {
+ overlayView.repeatWhenAttached {
+ fpsUnlockTracker.startTracking()
+
+ val lottie = it.requireViewById<LottieAnimationView>(R.id.sidefps_animation)
+ lottie.addLottieOnCompositionLoadedListener { composition: LottieComposition ->
+ viewModel.setLottieBounds(composition.bounds)
+ overlayView.visibility = View.VISIBLE
+ }
+ it.alpha = 0f
+ val overlayShowAnimator =
+ it.animate()
+ .alpha(1f)
+ .setDuration(KeyguardPINView.ANIMATION_DURATION)
+ .setInterpolator(Interpolators.ALPHA_IN)
+
+ overlayShowAnimator.start()
+
+ it.setAccessibilityDelegate(
+ object : View.AccessibilityDelegate() {
+ override fun dispatchPopulateAccessibilityEvent(
+ host: View,
+ event: AccessibilityEvent
+ ): Boolean {
+ return if (
+ event.getEventType() ===
+ android.view.accessibility.AccessibilityEvent
+ .TYPE_WINDOW_STATE_CHANGED
+ ) {
+ true
+ } else {
+ super.dispatchPopulateAccessibilityEvent(host, event)
+ }
+ }
+ }
+ )
+
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.lottieCallbacks.collect { callbacks ->
+ lottie.addOverlayDynamicColor(callbacks)
+ }
+ }
+
+ launch {
+ viewModel.overlayViewParams.collect { params ->
+ windowManager.updateViewLayout(it, params)
+ lottie.resumeAnimation()
+ }
+ }
+
+ launch {
+ viewModel.overlayViewProperties.collect { properties ->
+ it.rotation = properties.overlayViewRotation
+ lottie.setAnimation(properties.indicatorAsset)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+private fun LottieAnimationView.addOverlayDynamicColor(colorCallbacks: List<LottieCallback>) {
+ addLottieOnCompositionLoadedListener {
+ for (callback in colorCallbacks) {
+ addValueCallback(callback.keypath, LottieProperty.COLOR_FILTER) {
+ PorterDuffColorFilter(callback.color, PorterDuff.Mode.SRC_ATOP)
+ }
+ }
+ resumeAnimation()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 647aaf3..6d0a58e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -21,9 +21,12 @@
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
+import com.android.systemui.Flags.bpTalkback
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -35,7 +38,9 @@
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -49,7 +54,9 @@
constructor(
displayStateInteractor: DisplayStateInteractor,
promptSelectorInteractor: PromptSelectorInteractor,
- @Application context: Context,
+ @Application private val context: Context,
+ private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+ private val udfpsUtils: UdfpsUtils
) {
/** The set of modalities available for this prompt */
val modalities: Flow<BiometricModalities> =
@@ -69,6 +76,11 @@
val faceIconHeight: Int =
context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
+ private val _accessibilityHint = MutableSharedFlow<String>()
+
+ /** Hint for talkback directional guidance */
+ val accessibilityHint: Flow<String> = _accessibilityHint.asSharedFlow()
+
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
/** If the user is currently authenticating (i.e. at least one biometric is scanning). */
@@ -516,6 +528,40 @@
return false
}
+ /** Sets the message used for UDFPS directional guidance */
+ suspend fun onAnnounceAccessibilityHint(
+ event: MotionEvent,
+ touchExplorationEnabled: Boolean,
+ ): Boolean {
+ if (bpTalkback() && modalities.first().hasUdfps && touchExplorationEnabled) {
+ // TODO(b/315184924): Remove uses of UdfpsUtils
+ val scaledTouch =
+ udfpsUtils.getTouchInNativeCoordinates(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ if (
+ !udfpsUtils.isWithinSensorArea(
+ event.getPointerId(0),
+ event,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ ) {
+ _accessibilityHint.emit(
+ udfpsUtils.onTouchOutsideOfSensorArea(
+ touchExplorationEnabled,
+ context,
+ scaledTouch.x,
+ scaledTouch.y,
+ udfpsOverlayInteractor.udfpsOverlayParams.value
+ )
+ )
+ }
+ }
+ return false
+ }
+
/**
* Switch to the credential view.
*
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
new file mode 100644
index 0000000..ce72603
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.Gravity
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+import com.airbnb.lottie.model.KeyPath
+import com.android.systemui.biometrics.Utils
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+
+/** Models UI of the side fingerprint sensor indicator view. */
+class SideFpsOverlayViewModel
+@Inject
+constructor(
+ @Application private val applicationContext: Context,
+ biometricStatusInteractor: BiometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor: DisplayStateInteractor,
+ sfpsSensorInteractor: SideFpsSensorInteractor,
+ sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+) {
+ /** Contains properties of the side fingerprint sensor indicator */
+ data class OverlayViewProperties(
+ /** The raw asset for the indicator animation */
+ val indicatorAsset: Int,
+ /** Rotation of the overlayView */
+ val overlayViewRotation: Float,
+ )
+
+ private val _lottieBounds: MutableStateFlow<Rect?> = MutableStateFlow(null)
+
+ /** Used for setting lottie bounds once the composition has loaded. */
+ fun setLottieBounds(bounds: Rect) {
+ _lottieBounds.value = bounds
+ }
+
+ private val displayRotation = displayStateInteractor.currentRotation
+ private val sensorLocation = sfpsSensorInteractor.sensorLocation
+
+ /** Default LayoutParams for the overlayView */
+ val defaultOverlayViewParams: WindowManager.LayoutParams
+ get() =
+ WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
+ PixelFormat.TRANSLUCENT
+ )
+ .apply {
+ title = TAG
+ fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
+ gravity = Gravity.TOP or Gravity.LEFT
+ layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION
+ }
+
+ private val indicatorAsset: Flow<Int> =
+ combine(displayRotation, sensorLocation) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ val newAsset: Int =
+ when (rotation) {
+ DisplayRotation.ROTATION_0 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ DisplayRotation.ROTATION_180 ->
+ if (yAligned) {
+ R.raw.sfps_pulse
+ } else {
+ R.raw.sfps_pulse_landscape
+ }
+ else ->
+ if (yAligned) {
+ R.raw.sfps_pulse_landscape
+ } else {
+ R.raw.sfps_pulse
+ }
+ }
+ newAsset
+ }
+ .distinctUntilChanged()
+
+ private val overlayViewRotation: Flow<Float> =
+ combine(
+ displayRotation,
+ sensorLocation,
+ ) { rotation: DisplayRotation, sensorLocation ->
+ val yAligned = sensorLocation.isSensorVerticalInDefaultOrientation
+ when (rotation) {
+ DisplayRotation.ROTATION_90 -> if (yAligned) 0f else 180f
+ DisplayRotation.ROTATION_180 -> 180f
+ DisplayRotation.ROTATION_270 -> if (yAligned) 180f else 0f
+ else -> 0f
+ }
+ }
+ .distinctUntilChanged()
+
+ /** Contains properties (animation asset and view rotation) for overlayView */
+ val overlayViewProperties: Flow<OverlayViewProperties> =
+ combine(indicatorAsset, overlayViewRotation) { asset: Int, rotation: Float ->
+ OverlayViewProperties(asset, rotation)
+ }
+
+ /** LayoutParams for placement of overlayView (the side fingerprint sensor indicator view) */
+ val overlayViewParams: Flow<WindowManager.LayoutParams> =
+ combine(
+ _lottieBounds,
+ sensorLocation,
+ displayRotation,
+ ) { bounds: Rect?, sensorLocation: SideFpsSensorLocation, displayRotation: DisplayRotation
+ ->
+ val topLeft = Point(sensorLocation.left, sensorLocation.top)
+
+ if (sensorLocation.isSensorVerticalInDefaultOrientation) {
+ if (displayRotation == DisplayRotation.ROTATION_0) {
+ topLeft.x -= bounds!!.width()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.y -= bounds!!.height()
+ }
+ } else {
+ if (displayRotation == DisplayRotation.ROTATION_180) {
+ topLeft.y -= bounds!!.height()
+ } else if (displayRotation == DisplayRotation.ROTATION_270) {
+ topLeft.x -= bounds!!.width()
+ }
+ }
+ defaultOverlayViewParams.apply {
+ x = topLeft.x
+ y = topLeft.y
+ }
+ }
+
+ /** List of LottieCallbacks use for adding dynamic color to the overlayView */
+ val lottieCallbacks: Flow<List<LottieCallback>> =
+ combine(
+ biometricStatusInteractor.sfpsAuthenticationReason,
+ deviceEntrySideFpsOverlayInteractor.showIndicatorForDeviceEntry.distinctUntilChanged(),
+ sideFpsProgressBarViewModel.isVisible,
+ ) { reason: AuthenticationReason, showIndicatorForDeviceEntry: Boolean, progressBarIsVisible
+ ->
+ val callbacks = mutableListOf<LottieCallback>()
+ if (showIndicatorForDeviceEntry) {
+ val indicatorColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ val outerRimColor =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ val chevronFill =
+ com.android.settingslib.Utils.getColorAttrDefaultColor(
+ applicationContext,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ callbacks.add(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ callbacks.add(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ } else {
+ if (!isDarkMode(applicationContext)) {
+ callbacks.add(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ }
+ for (key in listOf(".blue600", ".blue400")) {
+ callbacks.add(
+ LottieCallback(
+ KeyPath(key, "**"),
+ applicationContext.getColor(
+ com.android.settingslib.color.R.color.settingslib_color_blue400
+ ),
+ )
+ )
+ }
+ }
+ callbacks
+ }
+
+ companion object {
+ private const val TAG = "SideFpsOverlayViewModel"
+ }
+}
+
+private fun isDarkMode(context: Context): Boolean {
+ val darkMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ return darkMode == Configuration.UI_MODE_NIGHT_YES
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
index 1e0e16c..c2a1d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt
@@ -18,6 +18,7 @@
import android.os.Build
import android.util.Log
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -121,6 +122,7 @@
fun setAlternateBouncerUIAvailable(isAvailable: Boolean)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun setSideFpsShowing(isShowing: Boolean)
}
@@ -261,7 +263,9 @@
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
index aa7758f..621ca5d 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt
@@ -28,6 +28,7 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.DejankUtils
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN
@@ -116,9 +117,11 @@
/** Allow for interaction when just about fully visible */
val isInteractable: Flow<Boolean> = bouncerExpansion.map { it > 0.9 }
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
val sideFpsShowing: Flow<Boolean> = repository.sideFpsShowing
private var currentUserActiveUnlockRunning = false
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** This callback needs to be a class field so it does not get garbage collected. */
val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
@@ -135,7 +138,10 @@
}
init {
- keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ }
applicationScope.launch {
trustRepository.isCurrentUserActiveUnlockRunning.collect {
currentUserActiveUnlockRunning = it
@@ -333,8 +339,10 @@
repository.setPrimaryStartDisappearAnimation(runnable)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Determine whether to show the side fps animation. */
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
val sfpsEnabled: Boolean =
context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
val fpsDetectionRunning: Boolean = keyguardUpdateMonitor.isFingerprintDetectionRunning
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
index ac3d4b6..5dcd661 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/KeyguardBouncerViewBinder.kt
@@ -27,6 +27,7 @@
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.dagger.KeyguardBouncerComponent
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.bouncer.ui.BouncerViewDelegate
@@ -233,15 +234,21 @@
.collect { view.systemUiVisibility = it }
}
- launch {
- viewModel.shouldUpdateSideFps.collect {
- viewModel.updateSideFpsVisibility()
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.shouldUpdateSideFps.collect {
+ viewModel.updateSideFpsVisibility()
+ }
}
}
- launch {
- viewModel.sideFpsShowing.collect {
- securityContainerController.updateSideFpsVisibility(it)
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ if (!SideFpsControllerRefactor.isEnabled) {
+ launch {
+ viewModel.sideFpsShowing.collect {
+ securityContainerController.updateSideFpsVisibility(it)
+ }
}
}
awaitCancellation()
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
index 649ae2fb..1c9d1f0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/KeyguardBouncerViewModel.kt
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.ui.viewmodel
import android.view.View
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.bouncer.ui.BouncerView
@@ -61,9 +62,11 @@
/** Observe whether keyguard is authenticated already. */
val keyguardAuthenticated: Flow<Boolean> = interactor.keyguardAuthenticatedBiometrics
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether the side fps is showing. */
val sideFpsShowing: Flow<Boolean> = interactor.sideFpsShowing
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/** Observe whether we should update fps is showing. */
val shouldUpdateSideFps: Flow<Unit> =
merge(
@@ -87,7 +90,9 @@
interactor.onMessageShown()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
fun updateSideFpsVisibility() {
+ SideFpsControllerRefactor.assertInLegacyMode()
interactor.updateSideFpsVisibility()
}
diff --git a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
index 7ac1cc7..9d4ed20 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/DreamHomeControlsComplication.java
@@ -25,11 +25,15 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.Utils;
import com.android.systemui.CoreStartable;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.complication.dagger.DreamHomeControlsComplicationComponent;
@@ -43,6 +47,7 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.condition.ConditionalCoreStartable;
@@ -195,34 +200,70 @@
private final ActivityStarter mActivityStarter;
private final Context mContext;
+ private final ConfigurationController mConfigurationController;
private final ControlsComponent mControlsComponent;
private final UiEventLogger mUiEventLogger;
+ private final ConfigurationController.ConfigurationListener mConfigurationListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onUiModeChanged() {
+ reloadResources();
+ }
+ };
+
@Inject
DreamHomeControlsChipViewController(
@Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
ActivityStarter activityStarter,
Context context,
+ ConfigurationController configurationController,
ControlsComponent controlsComponent,
UiEventLogger uiEventLogger) {
super(view);
mActivityStarter = activityStarter;
mContext = context;
+ mConfigurationController = configurationController;
mControlsComponent = controlsComponent;
mUiEventLogger = uiEventLogger;
}
@Override
protected void onViewAttached() {
- mView.setImageResource(mControlsComponent.getTileImageId());
- mView.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
+ reloadResources();
mView.setOnClickListener(this::onClickHomeControls);
+ mConfigurationController.addCallback(mConfigurationListener);
}
@Override
- protected void onViewDetached() {}
+ protected void onViewDetached() {
+ mConfigurationController.removeCallback(mConfigurationListener);
+ }
+
+ private void reloadResources() {
+ final String title = getControlsTitle();
+ if (title != null) {
+ mView.setContentDescription(title);
+ }
+ mView.setImageResource(mControlsComponent.getTileImageId());
+ mView.setImageTintList(Utils.getColorAttr(mContext, android.R.attr.textColorPrimary));
+ final Drawable background = mView.getBackground();
+ if (background != null) {
+ background.setTintList(
+ Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface));
+ }
+ }
+
+ @Nullable
+ private String getControlsTitle() {
+ try {
+ return mContext.getString(mControlsComponent.getTileTitleId());
+ } catch (Resources.NotFoundException e) {
+ return null;
+ }
+ }
private void onClickHomeControls(View v) {
if (DEBUG) Log.d(TAG, "home controls complication tapped");
diff --git a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
index 08d0595..b6dcfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -24,9 +24,8 @@
import android.view.LayoutInflater;
import android.widget.ImageView;
-import com.android.settingslib.Utils;
-import com.android.systemui.res.R;
import com.android.systemui.complication.DreamHomeControlsComplication;
+import com.android.systemui.res.R;
import com.android.systemui.shared.shadow.DoubleShadowIconDrawable;
import com.android.systemui.shared.shadow.DoubleShadowTextHelper;
@@ -98,7 +97,7 @@
@DreamHomeControlsComplicationScope
@Named(DREAM_HOME_CONTROLS_BACKGROUND_DRAWABLE)
static Drawable providesHomeControlsBackground(Context context, Resources resources) {
- final Drawable background = new DoubleShadowIconDrawable(createShadowInfo(
+ return new DoubleShadowIconDrawable(createShadowInfo(
resources,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_radius,
R.dimen.dream_overlay_bottom_affordance_key_text_shadow_dx,
@@ -117,11 +116,6 @@
R.dimen.dream_overlay_bottom_affordance_width),
resources.getDimensionPixelSize(R.dimen.dream_overlay_bottom_affordance_inset)
);
-
- background.setTintList(
- Utils.getColorAttr(context, com.android.internal.R.attr.colorSurface));
-
- return background;
}
private static DoubleShadowTextHelper.ShadowInfo createShadowInfo(Resources resources,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
index ae67e60..4d89a82 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
@@ -79,6 +79,22 @@
check(!isEnabled) { "Legacy code path not supported when $flagName is enabled." }
/**
+ * Called to ensure the new code is only run when the flag is enabled. This will throw an
+ * exception if the flag is disabled to ensure that the refactor author catches issues in
+ * testing.
+ *
+ * Example usage:
+ * ```
+ * public void setSomeNewController(SomeController someController) {
+ * SomeRefactor.assertInNewMode();
+ * mSomeController = someController;
+ * }
+ * ````
+ */
+ inline fun assertInNewMode(isEnabled: Boolean, flagName: Any) =
+ check(isEnabled) { "New code path not supported when $flagName is disabled." }
+
+ /**
* This will [Log.wtf] with the given message, assuming [ASSERT_TAG] is loggable at that level.
* This means an engineer can prevent this from crashing by running the command:
* ```
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 33dd3d9..edf9648 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -35,7 +35,7 @@
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -609,7 +609,7 @@
public void setCurrentUser(int userId) {
trace("Deprecated/NOT USED: setCurrentUser userId=" + userId);
checkPermission();
- if (!mFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
mKeyguardViewMediator.setCurrentUser(userId);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b7260f2..d7a1906 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -38,7 +38,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER;
+import static com.android.systemui.Flags.refactorGetCurrentUser;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -141,6 +141,7 @@
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
@@ -616,7 +617,7 @@
public void onUserSwitching(int userId) {
if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
synchronized (KeyguardViewMediator.this) {
- if (mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (refactorGetCurrentUser()) {
notifyTrustedChangedLocked(mUpdateMonitor.getUserHasTrust(userId));
}
resetKeyguardDonePendingLocked();
@@ -1319,6 +1320,7 @@
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
private SelectedUserInteractor mSelectedUserInteractor;
+ private KeyguardInteractor mKeyguardInteractor;
private final KeyguardStateController mKeyguardStateController;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
@@ -1400,7 +1402,8 @@
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
mContext = context;
mUserTracker = userTracker;
mFalsingCollector = falsingCollector;
@@ -1441,6 +1444,7 @@
}));
mDozeParameters = dozeParameters;
mSelectedUserInteractor = selectedUserInteractor;
+ mKeyguardInteractor = keyguardInteractor;
mStatusBarStateController = statusBarStateController;
statusBarStateController.addCallback(this);
@@ -1498,7 +1502,7 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- if (!mFeatureFlags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ if (!refactorGetCurrentUser()) {
KeyguardUpdateMonitor.setCurrentUser(mUserTracker.getUserId());
}
@@ -2618,6 +2622,7 @@
setPendingLock(false); // user may have authenticated during the screen off animation
handleHide();
+ mKeyguardInteractor.keyguardDoneAnimationsFinished();
mUpdateMonitor.clearFingerprintRecognizedWhenKeyguardDone(currentUser);
Trace.endSection();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index 331d892..3925dd1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -52,6 +52,7 @@
import com.android.systemui.keyguard.data.quickaffordance.KeyguardDataQuickAffordanceModule;
import com.android.systemui.keyguard.data.repository.KeyguardFaceAuthModule;
import com.android.systemui.keyguard.data.repository.KeyguardRepositoryModule;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLogger;
import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancesMetricsLoggerImpl;
@@ -154,7 +155,8 @@
Lazy<DreamingToLockscreenTransitionViewModel> dreamingToLockscreenTransitionViewModel,
SystemPropertiesHelper systemPropertiesHelper,
Lazy<WindowManagerLockscreenVisibilityManager> wmLockscreenVisibilityManager,
- SelectedUserInteractor selectedUserInteractor) {
+ SelectedUserInteractor selectedUserInteractor,
+ KeyguardInteractor keyguardInteractor) {
return new KeyguardViewMediator(
context,
uiEventLogger,
@@ -199,7 +201,8 @@
dreamingToLockscreenTransitionViewModel,
systemPropertiesHelper,
wmLockscreenVisibilityManager,
- selectedUserInteractor);
+ selectedUserInteractor,
+ keyguardInteractor);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
index c090688..4d60dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt
@@ -304,14 +304,14 @@
}
private fun observeFaceAuthResettingConditions() {
- // Clear auth status when keyguard is going away or when the user is switching or device
- // starts going to sleep.
+ // Clear auth status when keyguard done animations finished or when the user is switching
+ // or device starts going to sleep.
merge(
powerInteractor.isAsleep,
if (featureFlags.isEnabled(Flags.KEYGUARD_WM_STATE_REFACTOR)) {
keyguardTransitionInteractor.isInTransitionToState(KeyguardState.GONE)
} else {
- keyguardRepository.isKeyguardGoingAway
+ keyguardRepository.keyguardDoneAnimationsFinished.map { true }
},
userRepository.selectedUser.map {
it.selectionStatus == SelectionStatus.SELECTION_IN_PROGRESS
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index 96386f3..9a13558d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -41,6 +41,7 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
@@ -61,6 +62,9 @@
/** Provide the current status of fingerprint authentication. */
val authenticationStatus: Flow<FingerprintAuthenticationStatus>
+
+ /** Indicates whether to update the side fingerprint sensor indicator visibility. */
+ val shouldUpdateIndicatorVisibility: Flow<Boolean>
}
/**
@@ -256,6 +260,37 @@
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean> =
+ conflatedCallbackFlow {
+ val sendShouldUpdateIndicatorVisibility =
+ { shouldUpdateIndicatorVisibility: Boolean ->
+ trySendWithFailureLogging(
+ shouldUpdateIndicatorVisibility,
+ TAG,
+ "Error sending shouldUpdateIndicatorVisibility " +
+ "$shouldUpdateIndicatorVisibility"
+ )
+ }
+
+ val callback =
+ object : KeyguardUpdateMonitorCallback() {
+ override fun onBiometricRunningStateChanged(
+ running: Boolean,
+ biometricSourceType: BiometricSourceType?
+ ) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ override fun onStrongAuthStateChanged(userId: Int) {
+ sendShouldUpdateIndicatorVisibility(true)
+ }
+ }
+ sendShouldUpdateIndicatorVisibility(false)
+ keyguardUpdateMonitor.registerCallback(callback)
+ awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+ }
+ .flowOn(mainDispatcher)
+ .shareIn(scope, started = SharingStarted.WhileSubscribed(), replay = 1)
+
companion object {
const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 0df7f9b..31ef100 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -192,6 +192,17 @@
/** Observable updated when keyguardDone should be called either now or soon. */
val keyguardDone: Flow<KeyguardDone>
+ /**
+ * Emits after the keyguard is done animating away.
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ val keyguardDoneAnimationsFinished: Flow<Unit>
+
/** Receive whether clock should be centered on lockscreen. */
val clockShouldBeCentered: Flow<Boolean>
@@ -239,6 +250,17 @@
suspend fun setKeyguardDone(keyguardDoneType: KeyguardDone)
fun setClockShouldBeCentered(shouldBeCentered: Boolean)
+
+ /**
+ * Updates signal that the keyguard done animations are finished
+ *
+ * TODO(b/278086361): Remove once KEYGUARD_WM_STATE_REFACTOR flag is removed.
+ */
+ @Deprecated(
+ "Use KeyguardTransitionInteractor flows instead. The closest match for " +
+ "'keyguardDoneAnimationsFinished' is when the GONE transition is finished."
+ )
+ fun keyguardDoneAnimationsFinished()
}
/** Encapsulates application state for the keyguard. */
@@ -269,6 +291,11 @@
_keyguardDone.emit(keyguardDoneType)
}
+ override val keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> = MutableSharedFlow()
+ override fun keyguardDoneAnimationsFinished() {
+ keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
_animateBottomAreaDozingTransitions.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
new file mode 100644
index 0000000..de15fd6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2023 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.systemui.keyguard.domain.interactor
+
+import android.content.Context
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+
+/**
+ * Encapsulates business logic for device entry events that impact the side fingerprint sensor
+ * overlay.
+ */
+@SysUISingleton
+class DeviceEntrySideFpsOverlayInteractor
+@Inject
+constructor(
+ @Application private val context: Context,
+ deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
+ private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+ alternateBouncerInteractor: AlternateBouncerInteractor,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+) {
+
+ init {
+ alternateBouncerInteractor.setAlternateBouncerUIAvailable(true, TAG)
+ }
+
+ private val showIndicatorForPrimaryBouncer: Flow<Boolean> =
+ merge(
+ primaryBouncerInteractor.isShowing,
+ primaryBouncerInteractor.startingToHide,
+ primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(),
+ deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }
+ )
+ .map { shouldShowIndicatorForPrimaryBouncer() }
+
+ private val showIndicatorForAlternateBouncer: Flow<Boolean> =
+ alternateBouncerInteractor.isVisible
+
+ /**
+ * Indicates whether the primary or alternate bouncers request showing the side fingerprint
+ * sensor indicator.
+ */
+ val showIndicatorForDeviceEntry: Flow<Boolean> =
+ combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) {
+ showForPrimaryBouncer,
+ showForAlternateBouncer ->
+ showForPrimaryBouncer || showForAlternateBouncer
+ }
+
+ private fun shouldShowIndicatorForPrimaryBouncer(): Boolean {
+ val sfpsEnabled: Boolean =
+ context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
+ val sfpsDetectionRunning = keyguardUpdateMonitor.isFingerprintDetectionRunning
+ val isUnlockingWithFpAllowed = keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed
+ return primaryBouncerInteractor.isBouncerShowing() &&
+ sfpsEnabled &&
+ sfpsDetectionRunning &&
+ isUnlockingWithFpAllowed &&
+ !primaryBouncerInteractor.isAnimatingAway()
+ }
+
+ companion object {
+ private const val TAG = "DeviceEntrySideFpsOverlayInteractor"
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index defca18..21651ba2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -318,6 +318,10 @@
repository.ambientIndicationVisible.value = isVisible
}
+ fun keyguardDoneAnimationsFinished() {
+ repository.keyguardDoneAnimationsFinished()
+ }
+
companion object {
private const val TAG = "KeyguardInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
index 560e4ad..9a6dca3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
@@ -21,6 +21,7 @@
import com.android.systemui.CoreStartable
import com.android.systemui.Flags
import com.android.systemui.biometrics.SideFpsController
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.view.SideFpsProgressBar
@@ -46,6 +47,7 @@
private val viewModel: SideFpsProgressBarViewModel,
private val view: SideFpsProgressBar,
@Application private val applicationScope: CoroutineScope,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
private val sfpsController: dagger.Lazy<SideFpsController>,
private val logger: SideFpsLogger,
private val commandRegistry: CommandRegistry,
@@ -109,12 +111,14 @@
view.updateView(visible, location, length, thickness, rotation)
// We have to hide the SFPS indicator as the progress bar will
// be shown at the same location
- if (visible) {
- logger.hidingSfpsIndicator()
- sfpsController.get().hideIndicator()
- } else if (fpDetectRunning) {
- logger.showingSfpsIndicator()
- sfpsController.get().showIndicator()
+ if (!SideFpsControllerRefactor.isEnabled) {
+ if (visible) {
+ logger.hidingSfpsIndicator()
+ sfpsController.get().hideIndicator()
+ } else if (fpDetectRunning) {
+ logger.showingSfpsIndicator()
+ sfpsController.get().showIndicator()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index 2d0712c..1dbf1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -19,6 +19,7 @@
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Point
+import androidx.annotation.VisibleForTesting
import androidx.core.animation.doOnEnd
import com.android.systemui.Flags
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
@@ -213,4 +214,9 @@
}
}
}
+
+ @VisibleForTesting
+ fun setVisible(isVisible: Boolean) {
+ _visible.value = isVisible
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 9846f4b..e660b97 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -69,7 +69,6 @@
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.systemui.res.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.FeatureFlags;
@@ -81,6 +80,7 @@
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.res.R;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputChannelCompat;
@@ -1113,6 +1113,7 @@
// Capture inputs
mInputMonitor.pilferPointers();
if (mBackAnimation != null) {
+ mBackAnimation.onPilferPointers();
// Notify FalsingManager that an intentional gesture has occurred.
mFalsingManager.isFalseTouch(BACK_GESTURE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
index 6d55d05..de490a5 100644
--- a/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfig.kt
@@ -27,7 +27,6 @@
import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
-import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -43,6 +42,7 @@
import com.android.systemui.notetask.NoteTaskEnabledKey
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import dagger.Lazy
import java.util.concurrent.Executor
@@ -100,7 +100,8 @@
isEnabled &&
isUserUnlocked &&
isDefaultNotesAppSet &&
- (isConfigSelected || isStylusEverUsed)
+ isConfigSelected &&
+ isStylusEverUsed
) {
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6c930b1..3e50dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -43,6 +43,9 @@
import com.android.systemui.util.ViewController;
import com.android.systemui.util.animation.DisappearParameters;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,9 +53,6 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
-import kotlin.Unit;
-import kotlin.jvm.functions.Function1;
-
/**
* Controller for QSPanel views.
*
@@ -232,7 +232,7 @@
mQsTileRevealController.updateRevealedTiles(tiles);
}
boolean shouldChange = false;
- if (tiles.size() == mRecords.size()) {
+ if (tiles.size() <= mRecords.size()) {
int i = 0;
for (QSTile tile : tiles) {
if (tile != mRecords.get(i).tile) {
@@ -241,6 +241,17 @@
}
i++;
}
+
+ // If the first tiles are the same as the new ones, remove any extras.
+ if (!shouldChange) {
+ while (i < mRecords.size()) {
+ QSPanelControllerBase.TileRecord record = mRecords.get(i);
+ mView.removeTile(record);
+ record.tile.removeCallback(record.callback);
+ i++;
+ }
+ mCachedSpecs = getTilesSpecs();
+ }
} else {
shouldChange = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
index 935d072..42bee3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
@@ -22,8 +22,8 @@
AconfigFlags.FLAG_QS_NEW_PIPELINE
)
- fun assertNewTilesInLegacyMode() =
- RefactorFlagUtils.assertInLegacyMode(
+ fun assertNewTiles() =
+ RefactorFlagUtils.assertInNewMode(
AconfigFlags.qsNewTiles(),
AconfigFlags.FLAG_QS_NEW_TILES
)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 38bbce4..17e6375 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -19,6 +19,7 @@
import androidx.annotation.Nullable;
+import com.android.systemui.accessibility.qs.QSAccessibilityModule;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.qs.QSFactory;
import com.android.systemui.plugins.qs.QSTile;
@@ -41,7 +42,7 @@
* com.android.systemui.qs.tiles.DreamTile#TILE_SPEC})
*
* After, create or find an existing Module class to house the tile's binding method (e.g. {@link
- * com.android.systemui.accessibility.AccessibilityModule}). If creating a new module, add your
+ * QSAccessibilityModule}). If creating a new module, add your
* module to the SystemUI dagger graph by including it in an appropriate module.
*/
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
index 52e49f9..382cfe2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt
@@ -45,7 +45,7 @@
) : QSFactory {
init {
- QSPipelineFlagsRepository.assertNewTilesInLegacyMode()
+ QSPipelineFlagsRepository.assertNewTiles()
for (viewModelTileSpec in tileMap.keys) {
require(qsTileConfigProvider.hasConfig(viewModelTileSpec)) {
"No config for $viewModelTileSpec"
@@ -56,7 +56,7 @@
override fun createTile(tileSpec: String): QSTile? {
val viewModel: QSTileViewModel =
when (val spec = TileSpec.create(tileSpec)) {
- is TileSpec.CustomTileSpec -> createCustomTileViewModel(spec)
+ is TileSpec.CustomTileSpec -> null
is TileSpec.PlatformTileSpec -> tileMap[tileSpec]?.get()
is TileSpec.Invalid -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt
new file mode 100644
index 0000000..1efbfd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/ColorCorrectionTileMapper.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain
+
+import android.content.res.Resources
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [ColorCorrectionTileModel] to [QSTileState]. */
+class ColorCorrectionTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Resources.Theme,
+) : QSTileDataToStateMapper<ColorCorrectionTileModel> {
+
+ override fun map(config: QSTileConfig, data: ColorCorrectionTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val subtitleArray = resources.getStringArray(R.array.tile_states_color_correction)
+
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = subtitleArray[2]
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = subtitleArray[1]
+ }
+ contentDescription = label
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
new file mode 100644
index 0000000..cd33d45
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Observes color correction state changes providing the [ColorCorrectionTileModel]. */
+class ColorCorrectionTileDataInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+) : QSTileDataInteractor<ColorCorrectionTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<ColorCorrectionTileModel> {
+ return colorCorrectionRepository.isEnabled(user).map { ColorCorrectionTileModel(it) }
+ }
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
new file mode 100644
index 0000000..d183802
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 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.systemui.qs.tiles.impl.colorcorrection.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles color correction tile clicks. */
+class ColorCorrectionUserActionInteractor
+@Inject
+constructor(
+ private val colorCorrectionRepository: ColorCorrectionRepository,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<ColorCorrectionTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<ColorCorrectionTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ colorCorrectionRepository.setIsEnabled(
+ !data.isEnabled,
+ user,
+ )
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
similarity index 66%
copy from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
copy to packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
index e98f6db..66487e1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/model/ColorCorrectionTileModel.kt
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.biometrics
-import android.content.Context
-import android.util.AttributeSet
-import com.android.systemui.util.wrapper.LottieViewWrapper
+package com.android.systemui.qs.tiles.impl.colorcorrection.domain.model
-class SideFpsLottieViewWrapper
-@JvmOverloads
-constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
+/**
+ * Color correction tile model.
+ *
+ * @param isEnabled is true when the color correction is enabled;
+ */
+@JvmInline value class ColorCorrectionTileModel(val isEnabled: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 756c440..0c5472f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -41,6 +41,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.log.core.LogLevel;
import com.android.systemui.res.R;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
@@ -49,6 +50,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
+import java.util.function.Consumer;
import javax.inject.Inject;
@@ -210,23 +212,33 @@
private void notifyKeyguardChanged() {
Trace.beginSection("KeyguardStateController#notifyKeyguardChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardShowingChanged);
+ invokeForEachCallback(Callback::onKeyguardShowingChanged);
Trace.endSection();
}
private void notifyKeyguardFaceAuthEnabledChanged() {
+ invokeForEachCallback(Callback::onFaceEnrolledChanged);
+ }
+
+ private void invokeForEachCallback(Consumer<Callback> consumer) {
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(callback -> {
+ ArrayList<Callback> copyOfCallbacks = new ArrayList<>(mCallbacks);
+ for (int i = 0; i < copyOfCallbacks.size(); i++) {
+ Callback callback = copyOfCallbacks.get(i);
+ // Temporary fix for b/315731775, callback is null even though only non-null callbacks
+ // are added to the list by addCallback
if (callback != null) {
- callback.onFaceEnrolledChanged();
+ consumer.accept(callback);
+ } else {
+ mLogger.log("KeyguardStateController callback is null", LogLevel.DEBUG);
}
- });
+ }
}
private void notifyUnlockedChanged() {
Trace.beginSection("KeyguardStateController#notifyUnlockedChanged");
// Copy the list to allow removal during callback.
- new ArrayList<>(mCallbacks).forEach(Callback::onUnlockedChanged);
+ invokeForEachCallback(Callback::onUnlockedChanged);
Trace.endSection();
}
@@ -242,10 +254,7 @@
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardFadingAway",
keyguardFadingAway ? 1 : 0);
mKeyguardFadingAway = keyguardFadingAway;
- ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).onKeyguardFadingAwayChanged();
- }
+ invokeForEachCallback(Callback::onKeyguardFadingAwayChanged);
}
}
@@ -359,7 +368,7 @@
Trace.traceCounter(Trace.TRACE_TAG_APP, "keyguardGoingAway",
keyguardGoingAway ? 1 : 0);
mKeyguardGoingAway = keyguardGoingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardGoingAwayChanged);
+ invokeForEachCallback(Callback::onKeyguardGoingAwayChanged);
}
}
@@ -368,7 +377,7 @@
if (mPrimaryBouncerShowing != showing) {
mPrimaryBouncerShowing = showing;
- new ArrayList<>(mCallbacks).forEach(Callback::onPrimaryBouncerShowingChanged);
+ invokeForEachCallback(Callback::onPrimaryBouncerShowingChanged);
}
}
@@ -392,13 +401,13 @@
boolean dismissingFromTouch) {
mDismissAmount = dismissAmount;
mDismissingFromTouch = dismissingFromTouch;
- new ArrayList<>(mCallbacks).forEach(Callback::onKeyguardDismissAmountChanged);
+ invokeForEachCallback(Callback::onKeyguardDismissAmountChanged);
}
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
- new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
+ invokeForEachCallback(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 886fa70..2b9ad50 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -18,8 +18,8 @@
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
-import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.Flags.themeOverlayControllerWakefulnessDeprecation;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_HOME;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_LOCK;
import static com.android.systemui.theme.ThemeOverlayApplier.COLOR_SOURCE_PRESET;
@@ -364,15 +364,23 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean isManagedProfile = mUserManager.isManagedProfile(
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- if (newWorkProfile) {
- if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
+ boolean newProfile = Intent.ACTION_PROFILE_ADDED.equals(intent.getAction());
+ if (newProfile) {
+ UserHandle newUserHandle = intent.getParcelableExtra(Intent.EXTRA_USER,
+ android.os.UserHandle.class);
+ boolean isManagedProfile =
+ mUserManager.isManagedProfile(newUserHandle.getIdentifier());
+ if (!mDeviceProvisionedController.isUserSetup(newUserHandle.getIdentifier())
+ && isManagedProfile) {
Log.i(TAG, "User setup not finished when " + intent.getAction()
+ " was received. Deferring... Managed profile? " + isManagedProfile);
return;
}
+ if (android.os.Flags.allowPrivateProfile() && isPrivateProfile(newUserHandle)) {
+ mDeferredThemeEvaluation = true;
+ Log.i(TAG, "Deferring theme for private profile till user setup is complete");
+ return;
+ }
if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
reevaluateSystemTheme(true /* forceReload */);
} else if (Intent.ACTION_WALLPAPER_CHANGED.equals(intent.getAction())) {
@@ -432,7 +440,7 @@
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(Intent.ACTION_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
UserHandle.ALL);
@@ -608,6 +616,15 @@
return new FabricatedOverlay.Builder("com.android.systemui", name, "android").build();
}
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ Context usercontext = mContext.createContextAsUser(userHandle,0);
+ if (usercontext.getSystemService(UserManager.class).isPrivateProfile()) {
+ return true;
+ }
+ return false;
+ }
+
private void createOverlays(int color) {
boolean nightMode = isNightMode();
mColorScheme = new ColorScheme(color, nightMode, mThemeStyle);
@@ -784,7 +801,7 @@
Set<UserHandle> managedProfiles = new HashSet<>();
for (UserInfo userInfo : mUserManager.getEnabledProfiles(currentUser)) {
- if (userInfo.isManagedProfile()) {
+ if (userInfo.isProfile()) {
managedProfiles.add(userInfo.getUserHandle());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
index 3ed05aa..0fb4b43 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/SelectedUserInteractor.kt
@@ -2,9 +2,8 @@
import android.annotation.UserIdInt
import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags.refactorGetCurrentUser
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags.REFACTOR_GETCURRENTUSER
import com.android.systemui.user.data.repository.UserRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -12,12 +11,7 @@
/** Encapsulates business logic to interact the selected user */
@SysUISingleton
-class SelectedUserInteractor
-@Inject
-constructor(
- private val repository: UserRepository,
- private val flags: FeatureFlagsClassic,
-) {
+class SelectedUserInteractor @Inject constructor(private val repository: UserRepository) {
/** Flow providing the ID of the currently selected user. */
val selectedUser = repository.selectedUserInfo.map { it.id }.distinctUntilChanged()
@@ -34,7 +28,7 @@
@UserIdInt
@JvmOverloads
fun getSelectedUserId(bypassFlag: Boolean = false): Int {
- return if (bypassFlag || flags.isEnabled(REFACTOR_GETCURRENTUSER)) {
+ return if (bypassFlag || refactorGetCurrentUser()) {
repository.getSelectedUserInfo().id
} else {
KeyguardUpdateMonitor.getCurrentUser()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index ea20d29..91219f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -47,12 +47,14 @@
import com.android.systemui.biometrics.domain.interactor.FakeCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.VibratorHelper
import com.android.systemui.statusbar.events.ANIMATING_OUT
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -101,6 +103,12 @@
lateinit var interactionJankMonitor: InteractionJankMonitor
@Mock
lateinit var vibrator: VibratorHelper
+ @Mock
+ lateinit var udfpsUtils: UdfpsUtils
+ @Mock
+ lateinit var authController: AuthController
+ @Mock
+ lateinit var selectedUserInteractor: SelectedUserInteractor
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
@@ -123,6 +131,7 @@
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor)
@@ -140,6 +149,12 @@
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope,
+ )
}
@After
@@ -532,6 +547,8 @@
displayStateInteractor,
promptSelectorInteractor,
context,
+ udfpsOverlayInteractor,
+ udfpsUtils
),
{ credentialViewModel },
Handler(TestableLooper.get(this).looper),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 8e54eb7..4c510ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -27,6 +27,7 @@
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.Flags.FLAG_LIGHT_REVEAL_MIGRATION
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FeatureFlags
@@ -40,6 +41,7 @@
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.leak.RotationUtils
import com.android.systemui.util.mockito.any
+import javax.inject.Provider
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@@ -51,14 +53,14 @@
import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
import org.mockito.MockitoSession
import org.mockito.quality.Strictness
-import javax.inject.Provider
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -246,6 +248,7 @@
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_fingerprint() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val fpsLocation = Point(5, 5)
`when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
controller.onViewAttached()
@@ -266,6 +269,7 @@
@Test
@RunWithLooper(setAsMainLooper = true)
fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() {
+ mSetFlagsRule.disableFlags(FLAG_LIGHT_REVEAL_MIGRATION)
val faceLocation = Point(5, 5)
`when`(authController.faceSensorLocation).thenReturn(faceLocation)
controller.onViewAttached()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
new file mode 100644
index 0000000..27d93eb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.data.repository
+
+import android.hardware.biometrics.AuthenticationStateListener
+import android.hardware.biometrics.BiometricManager
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_BP
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_KEYGUARD
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_OTHER
+import android.hardware.biometrics.BiometricRequestConstants.REASON_AUTH_SETTINGS
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_ENROLLING
+import android.hardware.biometrics.BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusRepositoryTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var biometricManager: BiometricManager
+
+ private lateinit var underTest: BiometricStatusRepository
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setUp() {
+ underTest = BiometricStatusRepositoryImpl(testScope.backgroundScope, biometricManager)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_KEYGUARD)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.DeviceEntryAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_OTHER)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_AUTH_SETTINGS)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER))
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ listener.onAuthenticationStarted(REASON_ENROLL_FIND_SENSOR)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ listener.onAuthenticationStarted(REASON_ENROLL_ENROLLING)
+ assertThat(fingerprintAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val fingerprintAuthenticationReason by
+ collectLastValue(underTest.fingerprintAuthenticationReason)
+ runCurrent()
+
+ val listener = biometricManager.captureListener()
+
+ listener.onAuthenticationStarted(REASON_AUTH_BP)
+ listener.onAuthenticationStopped()
+ assertThat(fingerprintAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun BiometricManager.captureListener() =
+ withArgCaptor<AuthenticationStateListener> {
+ verify(this@captureListener).registerAuthenticationStateListener(capture())
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
new file mode 100644
index 0000000..6978923
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorImplTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.domain.interactor
+
+import android.app.ActivityManager
+import android.app.ActivityTaskManager
+import android.content.ComponentName
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.AuthenticationReason.SettingsOperations
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class BiometricStatusInteractorImplTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+
+ private lateinit var biometricStatusRepository: FakeBiometricStatusRepository
+ private lateinit var underTest: BiometricStatusInteractorImpl
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ biometricStatusRepository = FakeBiometricStatusRepository()
+ underTest = BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenBiometricPromptAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(AuthenticationReason.BiometricPromptAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenDeviceEntryAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.DeviceEntryAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenOtherAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.OtherAuthentication
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.OtherAuthentication)
+ }
+
+ @Test
+ fun doesNotUpdateSfpsAuthenticationReason_whenOtherSettingsAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ `when`(activityTaskManager.getTasks(Mockito.anyInt()))
+ .thenReturn(listOf(fpSettingsTask()))
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.OTHER)
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+
+ @Test
+ fun updatesSfpsAuthenticationReason_whenEnrollmentAuthenticationStarted() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_FIND_SENSOR)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(
+ SettingsOperations.ENROLL_FIND_SENSOR
+ )
+ )
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ assertThat(sfpsAuthenticationReason)
+ .isEqualTo(
+ AuthenticationReason.SettingsAuthentication(SettingsOperations.ENROLL_ENROLLING)
+ )
+ }
+
+ @Test
+ fun updatesFingerprintAuthenticationReason_whenAuthenticationStopped() =
+ testScope.runTest {
+ val sfpsAuthenticationReason by collectLastValue(underTest.sfpsAuthenticationReason)
+ runCurrent()
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ assertThat(sfpsAuthenticationReason).isEqualTo(AuthenticationReason.NotRunning)
+ }
+}
+
+private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings")
+
+private fun settingsTask(cls: String) =
+ ActivityManager.RunningTaskInfo().apply {
+ topActivity = ComponentName.createRelative("com.android.settings", cls)
+ }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
index 22e3e7f..74c4313 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/shared/model/BiometricModalitiesTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.biometrics.shared.model
+import android.hardware.fingerprint.FingerprintSensorProperties
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.faceSensorPropertiesInternal
@@ -35,6 +36,46 @@
}
@Test
+ fun hasUdfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isTrue()
+ assertThat(hasSfps).isFalse()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
+ fun hasSfps() {
+ with(
+ BiometricModalities(
+ fingerprintProperties = fingerprintSensorPropertiesInternal(
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ ).first(),
+ )
+ ) {
+ assertThat(isEmpty).isFalse()
+ assertThat(hasUdfps).isFalse()
+ assertThat(hasSfps).isTrue()
+ assertThat(hasFace).isFalse()
+ assertThat(hasFaceOnly).isFalse()
+ assertThat(hasFingerprint).isTrue()
+ assertThat(hasFingerprintOnly).isTrue()
+ assertThat(hasFaceAndFingerprint).isFalse()
+ }
+ }
+
+ @Test
fun fingerprintOnly() {
with(
BiometricModalities(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
new file mode 100644
index 0000000..b4ae00d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/binder/SideFpsOverlayViewBinderTest.kt
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.ui.binder
+
+import android.animation.Animator
+import android.app.ActivityTaskManager
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManager
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.testing.TestableLooper
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.LottieAnimationView
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.FpsUnlockTracker
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.biometrics.ui.viewmodel.SideFpsOverlayViewModel
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class SideFpsOverlayViewBinderTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var displayManager: DisplayManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var fpsUnlockTracker: FpsUnlockTracker
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var layoutInflater: LayoutInflater
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var sideFpsView: View
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private lateinit var underTest: SideFpsOverlayViewBinder
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var viewModel: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ viewModel =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel
+ )
+
+ underTest =
+ SideFpsOverlayViewBinder(
+ testScope.backgroundScope,
+ mContext,
+ biometricStatusInteractor,
+ displayStateInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ fpsUnlockTracker,
+ layoutInflater,
+ sideFpsProgressBarViewModel,
+ sfpsSensorInteractor,
+ windowManager
+ )
+
+ context.addMockSystemService(DisplayManager::class.java, displayManager)
+ context.addMockSystemService(WindowManager::class.java, windowManager)
+
+ `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sideFpsView)
+ `when`(sideFpsView.requireViewById<LottieAnimationView>(eq(R.id.sidefps_animation)))
+ .thenReturn(mock(LottieAnimationView::class.java))
+ with(mock(ViewPropertyAnimator::class.java)) {
+ `when`(sideFpsView.animate()).thenReturn(this)
+ `when`(alpha(Mockito.anyFloat())).thenReturn(this)
+ `when`(setStartDelay(Mockito.anyLong())).thenReturn(this)
+ `when`(setDuration(Mockito.anyLong())).thenReturn(this)
+ `when`(setListener(any())).thenAnswer {
+ (it.arguments[0] as Animator.AnimatorListener).onAnimationEnd(
+ mock(Animator::class.java)
+ )
+ this
+ }
+ }
+ }
+
+ @Test
+ fun verifyIndicatorNotAdded_whenInRearDisplayMode() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = true
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager, never()).addView(any(), any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onPrimaryBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show primary bouncer
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide primary bouncer
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShowAndHide_onAlternateBouncerShowAndHide() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ // Show alternate bouncer
+ bouncerRepository.setAlternateVisible(true)
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // Hide alternate bouncer
+ bouncerRepository.setAlternateVisible(false)
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ @Test
+ fun verifyIndicatorShownAndHidden_onSystemServerAuthenticationStartedAndStopped() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ // System server authentication started
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ runCurrent()
+
+ verify(windowManager).addView(any(), any())
+
+ // System server authentication stopped
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ runCurrent()
+
+ verify(windowManager).removeView(any())
+ }
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewBinderTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+ displayStateRepository.setCurrentRotation(rotation)
+ displayRepository.emitDisplayChangeEvent(0)
+ underTest.start()
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index d06cbbb..7475235 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.ui.viewmodel
import android.content.res.Configuration
+import android.graphics.Point
import android.hardware.biometrics.PromptInfo
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
@@ -25,7 +26,10 @@
import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
+import com.android.systemui.Flags.FLAG_BP_TALKBACK
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
+import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
@@ -33,6 +37,7 @@
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.biometrics.extractAuthenticatorTypes
import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
@@ -45,8 +50,10 @@
import com.android.systemui.coroutines.collectValues
import com.android.systemui.display.data.repository.FakeDisplayRepository
import com.android.systemui.res.R
-import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -77,7 +84,9 @@
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
@Mock private lateinit var lockPatternUtils: LockPatternUtils
- @Mock private lateinit var vibrator: VibratorHelper
+ @Mock private lateinit var authController: AuthController
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var udfpsUtils: UdfpsUtils
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val testScope = TestScope()
@@ -87,6 +96,7 @@
private lateinit var displayStateRepository: FakeDisplayStateRepository
private lateinit var displayRepository: FakeDisplayRepository
private lateinit var displayStateInteractor: DisplayStateInteractor
+ private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
private lateinit var selector: PromptSelectorInteractor
private lateinit var viewModel: PromptViewModel
@@ -116,11 +126,24 @@
displayStateRepository,
displayRepository,
)
+ udfpsOverlayInteractor =
+ UdfpsOverlayInteractor(
+ authController,
+ selectedUserInteractor,
+ testScope.backgroundScope
+ )
selector =
PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
selector.resetPrompt()
- viewModel = PromptViewModel(displayStateInteractor, selector, mContext)
+ viewModel =
+ PromptViewModel(
+ displayStateInteractor,
+ selector,
+ mContext,
+ udfpsOverlayInteractor,
+ udfpsUtils
+ )
iconViewModel = viewModel.iconViewModel
}
@@ -1153,6 +1176,29 @@
assertThat(size).isEqualTo(PromptSize.LARGE)
}
+ @Test
+ fun hint_for_talkback_guidance() = runGenericTest {
+ mSetFlagsRule.enableFlags(FLAG_BP_TALKBACK)
+ val hint by collectLastValue(viewModel.accessibilityHint)
+
+ // Touches should fall outside of sensor area
+ whenever(udfpsUtils.getTouchInNativeCoordinates(any(), any(), any()))
+ .thenReturn(Point(0, 0))
+ whenever(udfpsUtils.onTouchOutsideOfSensorArea(any(), any(), any(), any(), any()))
+ .thenReturn("Direction")
+
+ viewModel.onAnnounceAccessibilityHint(
+ obtainMotionEvent(MotionEvent.ACTION_HOVER_ENTER),
+ true
+ )
+
+ if (testCase.modalities.hasUdfps) {
+ assertThat(hint?.isNotBlank()).isTrue()
+ } else {
+ assertThat(hint.isNullOrBlank()).isTrue()
+ }
+ }
+
/** Asserts that the selected buttons are visible now. */
private suspend fun TestScope.assertButtonsVisible(
tryAgain: Boolean = false,
@@ -1220,14 +1266,19 @@
authenticatedModality = BiometricModality.Face,
),
TestCase(
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
),
TestCase(
fingerprint =
fingerprintSensorPropertiesInternal(
strong = true,
- sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
)
.first(),
authenticatedModality = BiometricModality.Fingerprint,
@@ -1264,20 +1315,30 @@
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
- authenticatedModality = BiometricModality.Fingerprint,
- ),
- TestCase(
- face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
authenticatedModality = BiometricModality.Face,
confirmationRequested = true,
),
TestCase(
face = faceSensorPropertiesInternal(strong = true).first(),
- fingerprint = fingerprintSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON
+ )
+ .first(),
authenticatedModality = BiometricModality.Fingerprint,
confirmationRequested = true,
),
+ TestCase(
+ face = faceSensorPropertiesInternal(strong = true).first(),
+ fingerprint =
+ fingerprintSensorPropertiesInternal(
+ strong = true,
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ )
+ .first(),
+ authenticatedModality = BiometricModality.Fingerprint,
+ ),
)
}
}
@@ -1309,6 +1370,9 @@
else -> false
}
+ val modalities: BiometricModalities
+ get() = BiometricModalities(fingerprint, face)
+
val authenticatedByFingerprint: Boolean
get() = authenticatedModality == BiometricModality.Fingerprint
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
new file mode 100644
index 0000000..2267bdc
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.ui.viewmodel
+
+import android.app.ActivityTaskManager
+import android.content.res.Configuration.UI_MODE_NIGHT_NO
+import android.content.res.Configuration.UI_MODE_NIGHT_YES
+import android.graphics.Color
+import android.graphics.Rect
+import android.hardware.biometrics.SensorLocationInternal
+import android.hardware.display.DisplayManagerGlobal
+import android.os.Handler
+import android.view.Display
+import android.view.DisplayInfo
+import android.view.WindowInsets
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.airbnb.lottie.model.KeyPath
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.settingslib.Utils
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
+import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository
+import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor
+import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractorImpl
+import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import com.android.systemui.biometrics.shared.model.DisplayRotation
+import com.android.systemui.biometrics.shared.model.FingerprintSensorType
+import com.android.systemui.biometrics.shared.model.LottieCallback
+import com.android.systemui.biometrics.shared.model.SensorStrength
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.display.data.repository.FakeDisplayRepository
+import com.android.systemui.dump.logcatLogBuffer
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.keyguard.domain.interactor.DeviceEntrySideFpsOverlayInteractor
+import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
+import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class SideFpsOverlayViewModelTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var activityTaskManager: ActivityTaskManager
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock
+ private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var screenSizeFoldProvider: ScreenSizeFoldProvider
+ @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var windowManager: WindowManager
+
+ private val contextDisplayInfo = DisplayInfo()
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val biometricStatusRepository = FakeBiometricStatusRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
+ private val displayRepository = FakeDisplayRepository()
+ private val displayStateRepository = FakeDisplayStateRepository()
+ private val fingerprintPropertyRepository = FakeFingerprintPropertyRepository()
+
+ private val indicatorColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ )
+ private val outerRimColor =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorPrimaryFixedDim
+ )
+ private val chevronFill =
+ Utils.getColorAttrDefaultColor(
+ context,
+ com.android.internal.R.attr.materialColorOnPrimaryFixed
+ )
+ private val color_blue400 =
+ context.getColor(com.android.settingslib.color.R.color.settingslib_color_blue400)
+
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+ private lateinit var biometricStatusInteractor: BiometricStatusInteractor
+ private lateinit var deviceEntrySideFpsOverlayInteractor: DeviceEntrySideFpsOverlayInteractor
+ private lateinit var displayStateInteractor: DisplayStateInteractorImpl
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var sfpsSensorInteractor: SideFpsSensorInteractor
+
+ private lateinit var sideFpsProgressBarViewModel: SideFpsProgressBarViewModel
+
+ private lateinit var underTest: SideFpsOverlayViewModel
+
+ private var displayWidth: Int = 0
+ private var displayHeight: Int = 0
+ private var boundsWidth: Int = 0
+ private var boundsHeight: Int = 0
+
+ private lateinit var deviceConfig: DeviceConfig
+ private lateinit var sensorLocation: SensorLocationInternal
+
+ private val testScope = TestScope(StandardTestDispatcher())
+ private val fakeExecutor = FakeExecutor(FakeSystemClock())
+
+ enum class DeviceConfig {
+ X_ALIGNED,
+ Y_ALIGNED,
+ }
+
+ @Before
+ fun setup() {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+
+ mContext = spy(mContext)
+
+ val resources = mContext.resources
+ whenever(mContext.display)
+ .thenReturn(
+ Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
+ )
+
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ fingerprintPropertyRepository,
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+
+ biometricStatusInteractor =
+ BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository)
+
+ displayStateInteractor =
+ DisplayStateInteractorImpl(
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
+ )
+ displayStateInteractor.setScreenSizeFoldProvider(screenSizeFoldProvider)
+
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ selectedUserInteractor,
+ faceAuthInteractor
+ )
+
+ deviceEntrySideFpsOverlayInteractor =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+
+ whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
+ .thenReturn(MutableStateFlow(false))
+
+ sfpsSensorInteractor =
+ SideFpsSensorInteractor(
+ mContext,
+ fingerprintPropertyRepository,
+ windowManager,
+ displayStateInteractor,
+ Optional.of(fingerprintInteractiveToAuthProvider),
+ SideFpsLogger(logcatLogBuffer("SfpsLogger"))
+ )
+
+ sideFpsProgressBarViewModel =
+ SideFpsProgressBarViewModel(
+ mContext,
+ deviceEntryFingerprintAuthRepository,
+ sfpsSensorInteractor,
+ displayStateInteractor,
+ testScope.backgroundScope,
+ )
+
+ underTest =
+ SideFpsOverlayViewModel(
+ mContext,
+ biometricStatusInteractor,
+ deviceEntrySideFpsOverlayInteractor,
+ displayStateInteractor,
+ sfpsSensorInteractor,
+ sideFpsProgressBarViewModel,
+ )
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewProperties_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewProperties by collectLastValue(underTest.overlayViewProperties)
+
+ runCurrent()
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_0)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(0f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+
+ assertThat(overlayViewProperties?.indicatorAsset).isEqualTo(R.raw.sfps_pulse_landscape)
+ assertThat(overlayViewProperties?.overlayViewRotation).isEqualTo(180f)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_xAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.X_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationX)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationX - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationX)
+ }
+ }
+
+ @Test
+ fun updatesOverlayViewParams_onDisplayRotationChange_yAlignedSensor() {
+ testScope.runTest {
+ setupTestConfiguration(
+ DeviceConfig.Y_ALIGNED,
+ rotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode = false
+ )
+
+ val overlayViewParams by collectLastValue(underTest.overlayViewParams)
+
+ underTest.setLottieBounds(Rect(0, 0, boundsWidth, boundsHeight))
+ runCurrent()
+
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(displayWidth - boundsWidth)
+ assertThat(overlayViewParams!!.y).isEqualTo(sensorLocation.sensorLocationY)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_90)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(sensorLocation.sensorLocationY)
+ assertThat(overlayViewParams!!.y).isEqualTo(0)
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_180)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x).isEqualTo(0)
+ assertThat(overlayViewParams!!.y)
+ .isEqualTo(
+ displayHeight - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+
+ displayStateRepository.setCurrentRotation(DisplayRotation.ROTATION_270)
+ assertThat(overlayViewParams).isNotNull()
+ assertThat(overlayViewParams!!.x)
+ .isEqualTo(
+ displayWidth - sensorLocation.sensorLocationY - sensorLocation.sensorRadius * 2
+ )
+ assertThat(overlayViewParams!!.y).isEqualTo(displayHeight - boundsHeight)
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForDeviceEntry() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.NotRunning
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), indicatorColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), outerRimColor))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), chevronFill))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inDarkMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(true)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ @Test
+ fun updatesLottieCallbacks_onShowIndicatorForSystemServer_inLightMode() {
+ testScope.runTest {
+ val lottieCallbacks by collectLastValue(underTest.lottieCallbacks)
+ setDarkMode(false)
+
+ biometricStatusRepository.setFingerprintAuthenticationReason(
+ AuthenticationReason.BiometricPromptAuthentication
+ )
+ sideFpsProgressBarViewModel.setVisible(false)
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ runCurrent()
+
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".black", "**"), Color.WHITE))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue600", "**"), color_blue400))
+ assertThat(lottieCallbacks)
+ .contains(LottieCallback(KeyPath(".blue400", "**"), color_blue400))
+ }
+ }
+
+ private fun setDarkMode(inDarkMode: Boolean) {
+ val uiMode =
+ if (inDarkMode) {
+ UI_MODE_NIGHT_YES
+ } else {
+ UI_MODE_NIGHT_NO
+ }
+
+ mContext.resources.configuration.uiMode = uiMode
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+
+ private suspend fun TestScope.setupTestConfiguration(
+ deviceConfig: DeviceConfig,
+ rotation: DisplayRotation = DisplayRotation.ROTATION_0,
+ isInRearDisplayMode: Boolean,
+ ) {
+ this@SideFpsOverlayViewModelTest.deviceConfig = deviceConfig
+
+ when (deviceConfig) {
+ DeviceConfig.X_ALIGNED -> {
+ displayWidth = 3000
+ displayHeight = 1500
+ boundsWidth = 200
+ boundsHeight = 100
+ sensorLocation = SensorLocationInternal("", 2500, 0, boundsWidth / 2)
+ }
+ DeviceConfig.Y_ALIGNED -> {
+ displayWidth = 2500
+ displayHeight = 2000
+ boundsWidth = 100
+ boundsHeight = 200
+ sensorLocation = SensorLocationInternal("", displayWidth, 300, boundsHeight / 2)
+ }
+ }
+
+ whenever(windowManager.maximumWindowMetrics)
+ .thenReturn(
+ WindowMetrics(
+ Rect(0, 0, displayWidth, displayHeight),
+ mock(WindowInsets::class.java),
+ )
+ )
+
+ contextDisplayInfo.uniqueId = DISPLAY_ID
+
+ fingerprintPropertyRepository.setProperties(
+ sensorId = 1,
+ strength = SensorStrength.STRONG,
+ sensorType = FingerprintSensorType.POWER_BUTTON,
+ sensorLocations = mapOf(DISPLAY_ID to sensorLocation)
+ )
+
+ displayStateRepository.setIsInRearDisplayMode(isInRearDisplayMode)
+
+ displayStateRepository.setCurrentRotation(rotation)
+
+ displayRepository.emitDisplayChangeEvent(0)
+ runCurrent()
+ }
+
+ companion object {
+ private const val DISPLAY_ID = "displayId"
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index 37a093e..dacf23a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
@@ -37,6 +37,7 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.mockito.any
@@ -342,6 +343,7 @@
assertThat(underTest.willDismissWithAction()).isFalse()
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility() {
updateSideFpsVisibilityParameters(
@@ -355,6 +357,7 @@
verify(repository).setSideFpsShowing(true)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_notVisible() {
updateSideFpsVisibilityParameters(
@@ -368,6 +371,7 @@
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_sfpsNotEnabled() {
updateSideFpsVisibilityParameters(
@@ -381,6 +385,7 @@
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_fpsDetectionNotRunning() {
updateSideFpsVisibilityParameters(
@@ -394,6 +399,7 @@
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_UnlockingWithFpNotAllowed() {
updateSideFpsVisibilityParameters(
@@ -407,6 +413,7 @@
verify(repository).setSideFpsShowing(false)
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Test
fun testSideFpsVisibility_AnimatingAway() {
updateSideFpsVisibilityParameters(
@@ -492,6 +499,7 @@
isUnlockingWithFpAllowed: Boolean,
isAnimatingAway: Boolean
) {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
whenever(repository.primaryBouncerShow.value).thenReturn(isVisible)
resources.addOverride(R.bool.config_show_sidefps_hint_on_bouncer, sfpsEnabled)
whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
index 2207180..07c980b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/complication/DreamHomeControlsComplicationTest.java
@@ -21,14 +21,13 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
-import android.content.Context;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -48,6 +47,7 @@
import com.android.systemui.dreams.DreamOverlayStateController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.shared.condition.Monitor;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -71,9 +71,6 @@
private DreamOverlayStateController mDreamOverlayStateController;
@Mock
- private Context mContext;
-
- @Mock
private Resources mResources;
@Mock
@@ -100,6 +97,9 @@
@Mock
private UiEventLogger mUiEventLogger;
+ @Mock
+ private ConfigurationController mConfigurationController;
+
@Captor
private ArgumentCaptor<DreamOverlayStateController.Callback> mStateCallbackCaptor;
@@ -109,7 +109,8 @@
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mContext.getString(anyInt())).thenReturn("");
+ mContext.ensureTestableResources();
+
when(mControlsComponent.getControlsController()).thenReturn(
Optional.of(mControlsController));
when(mControlsComponent.getControlsListingController()).thenReturn(
@@ -225,6 +226,7 @@
mHomeControlsView,
mActivityStarter,
mContext,
+ mConfigurationController,
mControlsComponent,
mUiEventLogger);
viewController.onViewAttached();
@@ -237,6 +239,24 @@
verify(mUiEventLogger).log(DreamOverlayUiEvent.DREAM_HOME_CONTROLS_TAPPED);
}
+ @Test
+ public void testUnregistersConfigurationCallback() {
+ final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController =
+ new DreamHomeControlsComplication.DreamHomeControlsChipViewController(
+ mHomeControlsView,
+ mActivityStarter,
+ mContext,
+ mConfigurationController,
+ mControlsComponent,
+ mUiEventLogger);
+ viewController.onViewAttached();
+ verify(mConfigurationController).addCallback(any());
+ verify(mConfigurationController, never()).removeCallback(any());
+
+ viewController.onViewDetached();
+ verify(mConfigurationController).removeCallback(any());
+ }
+
private void setHaveFavorites(boolean value) {
final List<StructureInfo> favorites = mock(List.class);
when(favorites.isEmpty()).thenReturn(!value);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index ae5f625..b38c9ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -24,6 +24,7 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER;
import static com.android.systemui.keyguard.KeyguardViewMediator.DELAYED_KEYGUARD_ACTION;
import static com.android.systemui.keyguard.KeyguardViewMediator.KEYGUARD_LOCK_AFTER_DELAY_DEFAULT;
import static com.android.systemui.keyguard.KeyguardViewMediator.REBOOT_MAINLINE_UPDATE;
@@ -93,6 +94,7 @@
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.flags.SystemPropertiesHelper;
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -190,6 +192,7 @@
private @Mock ShadeInteractor mShadeInteractor;
private @Mock ShadeWindowLogger mShadeWindowLogger;
private @Mock SelectedUserInteractor mSelectedUserInteractor;
+ private @Mock KeyguardInteractor mKeyguardInteractor;
private @Captor ArgumentCaptor<KeyguardStateController.Callback>
mKeyguardStateControllerCallback;
private @Captor ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -264,7 +267,7 @@
mSceneContainerFlags);
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false);
- mFeatureFlags.set(Flags.REFACTOR_GETCURRENTUSER, true);
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER);
DejankUtils.setImmediate(true);
@@ -1131,7 +1134,8 @@
() -> mDreamingToLockscreenTransitionViewModel,
mSystemPropertiesHelper,
() -> mock(WindowManagerLockscreenVisibilityManager.class),
- mSelectedUserInteractor);
+ mSelectedUserInteractor,
+ mKeyguardInteractor);
mViewMediator.start();
mViewMediator.registerCentralSurfaces(mCentralSurfaces, null, null, null, null, null);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
new file mode 100644
index 0000000..70d3f81
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2023 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.systemui.keyguard.domain.interactor
+
+import android.os.Handler
+import android.platform.test.annotations.RequiresFlagsEnabled
+import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardSecurityModel
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor
+import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.bouncer.ui.BouncerView
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.DismissCallbackRegistry
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeTrustRepository
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
+import com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.user.domain.interactor.SelectedUserInteractor
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RequiresFlagsEnabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
+@SmallTest
+@RunWith(JUnit4::class)
+class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
+ @JvmField @Rule var mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var faceAuthInteractor: KeyguardFaceAuthInteractor
+ @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
+ @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor
+
+ private val bouncerRepository = FakeKeyguardBouncerRepository()
+ private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+
+ private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
+ private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
+
+ private lateinit var underTest: DeviceEntrySideFpsOverlayInteractor
+
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ @Before
+ fun setup() {
+ primaryBouncerInteractor =
+ PrimaryBouncerInteractor(
+ bouncerRepository,
+ mock(BouncerView::class.java),
+ mock(Handler::class.java),
+ mock(KeyguardStateController::class.java),
+ mock(KeyguardSecurityModel::class.java),
+ mock(PrimaryBouncerCallbackInteractor::class.java),
+ mock(FalsingCollector::class.java),
+ mock(DismissCallbackRegistry::class.java),
+ mContext,
+ keyguardUpdateMonitor,
+ FakeTrustRepository(),
+ testScope.backgroundScope,
+ mSelectedUserInteractor,
+ faceAuthInteractor
+ )
+ alternateBouncerInteractor =
+ AlternateBouncerInteractor(
+ mock(StatusBarStateController::class.java),
+ mock(KeyguardStateController::class.java),
+ bouncerRepository,
+ FakeFingerprintPropertyRepository(),
+ biometricSettingsRepository,
+ FakeSystemClock(),
+ keyguardUpdateMonitor,
+ testScope.backgroundScope,
+ )
+ underTest =
+ DeviceEntrySideFpsOverlayInteractor(
+ mContext,
+ FakeDeviceEntryFingerprintAuthRepository(),
+ primaryBouncerInteractor,
+ alternateBouncerInteractor,
+ keyguardUpdateMonitor
+ )
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerShowing() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerHidden() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = false,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_whenFpsDetectionNotRunning() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = false,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_fromPrimaryBouncer_onUnlockingWithFpDisallowed() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = false
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onPrimaryBouncerAnimatingAway() {
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = true,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+ }
+
+ @Test
+ fun updatesShowIndicatorForDeviceEntry_onAlternateBouncerRequest() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by
+ collectLastValue(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ bouncerRepository.setAlternateVisible(true)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(true)
+
+ bouncerRepository.setAlternateVisible(false)
+ assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
+ }
+
+ private fun updatePrimaryBouncer(
+ isShowing: Boolean,
+ isAnimatingAway: Boolean,
+ fpsDetectionRunning: Boolean,
+ isUnlockingWithFpAllowed: Boolean,
+ ) {
+ bouncerRepository.setPrimaryShow(isShowing)
+ bouncerRepository.setPrimaryStartingToHide(false)
+ val primaryStartDisappearAnimation = if (isAnimatingAway) Runnable {} else null
+ bouncerRepository.setPrimaryStartDisappearAnimation(primaryStartDisappearAnimation)
+
+ whenever(keyguardUpdateMonitor.isFingerprintDetectionRunning)
+ .thenReturn(fpsDetectionRunning)
+ whenever(keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed)
+ .thenReturn(isUnlockingWithFpAllowed)
+ mContext.orCreateTestableResources.addOverride(
+ R.bool.config_show_sidefps_hint_on_bouncer,
+ true
+ )
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 8dea57c..8e81185 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -20,8 +20,6 @@
import androidx.test.filters.SmallTest
import com.android.systemui.coroutines.collectValues
import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -46,11 +44,7 @@
class FromPrimaryBouncerTransitionInteractorTest : KeyguardTransitionInteractorTestCase() {
private lateinit var underTest: FromPrimaryBouncerTransitionInteractor
- private val mSelectedUserInteractor =
- SelectedUserInteractor(
- FakeUserRepository(),
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ private val mSelectedUserInteractor = SelectedUserInteractor(FakeUserRepository())
// Override the fromPrimaryBouncerTransitionInteractor provider from the superclass so our
// underTest interactor is provided to any classes that need it.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
index 119ffd2..ebd34de 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/quickaffordance/NoteTaskQuickAffordanceConfigTest.kt
@@ -28,7 +28,6 @@
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -40,6 +39,7 @@
import com.android.systemui.notetask.NoteTaskController
import com.android.systemui.notetask.NoteTaskEntryPoint
import com.android.systemui.notetask.NoteTaskInfoResolver
+import com.android.systemui.res.R
import com.android.systemui.stylus.StylusManager
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
@@ -134,12 +134,9 @@
// region lockScreenState
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_shouldEmitVisible() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(createLockScreenStateVisible())
@@ -148,10 +145,11 @@
@Test
fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
runTest {
+ val underTest = createUnderTest()
TestConfig()
.setStylusEverUsed(true)
.setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
+ .setConfigSelections(underTest)
whenever(
roleManager.getRoleHoldersAsUser(
eq(RoleManager.ROLE_NOTES),
@@ -160,7 +158,6 @@
)
.thenReturn(emptyList())
- val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -168,12 +165,9 @@
@Test
fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(false)
- .setUserUnlocked(true)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(false).setUserUnlocked(true).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
@@ -181,25 +175,22 @@
@Test
fun lockScreenState_stylusUsed_userLocked_isSelected_shouldEmitHidden() = runTest {
- TestConfig()
- .setStylusEverUsed(true)
- .setUserUnlocked(false)
- .setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
-
val underTest = createUnderTest()
+ TestConfig().setStylusEverUsed(true).setUserUnlocked(false).setConfigSelections(underTest)
+
val actual by collectLastValue(underTest.lockScreenState)
assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_noSelected_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections()
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
@@ -223,13 +214,13 @@
}
@Test
- fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitVisible() = runTest {
+ fun lockScreenState_stylusUsed_userUnlocked_customSelections_shouldEmitHidden() = runTest {
TestConfig().setStylusEverUsed(true).setUserUnlocked(true).setConfigSelections(mock())
val underTest = createUnderTest()
val actual by collectLastValue(underTest.lockScreenState)
- assertThat(actual).isEqualTo(createLockScreenStateVisible())
+ assertThat(actual).isEqualTo(LockScreenState.Hidden)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index b825c08..018fa9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -391,7 +391,7 @@
}
@Test
- public void setTiles_differentTiles_allTilesRemovedAndNewTilesAdded() {
+ public void setTiles_differentTiles_extraTileRemoved() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
@@ -400,8 +400,8 @@
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile));
mController.setTiles();
- verify(mQSPanel, times(2)).removeTile(any());
- verify(mQSPanel).addTile(any());
+ verify(mQSPanel, times(1)).removeTile(any());
+ verify(mQSPanel, never()).addTile(any());
}
@Test
@@ -418,7 +418,7 @@
}
@Test
- public void setTiles_sameTilesDifferentOrder_removesAndReadds() {
+ public void setTiles_sameTilesDifferentOrder_removesAndReads() {
when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
mController.setTiles();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 1123688..b58a41c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.theme;
+import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
@@ -90,6 +91,9 @@
private static final int USER_SYSTEM = UserHandle.USER_SYSTEM;
private static final int USER_SECONDARY = 10;
+ private static final UserHandle MANAGED_USER_HANDLE = UserHandle.of(100);
+ private static final UserHandle PRIVATE_USER_HANDLE = UserHandle.of(101);
+
@Mock
private JavaAdapter mJavaAdapter;
@Mock
@@ -174,6 +178,14 @@
Integer.toHexString(mColorScheme.getSeed() | 0xff000000)));
return overlay;
}
+
+ @VisibleForTesting
+ protected boolean isPrivateProfile(UserHandle userHandle) {
+ if (userHandle.getIdentifier() == PRIVATE_USER_HANDLE.getIdentifier()) {
+ return true;
+ }
+ return false;
+ }
};
mWakefulnessLifecycle.dispatchFinishedWakingUp();
@@ -675,7 +687,8 @@
@Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -684,7 +697,8 @@
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier)
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -694,12 +708,26 @@
reset(mDeviceProvisionedController);
when(mUserManager.isManagedProfile(anyInt())).thenReturn(true);
mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
+ new Intent(Intent.ACTION_PROFILE_ADDED)
+ .putExtra(Intent.EXTRA_USER, MANAGED_USER_HANDLE));
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@Test
+ public void onPrivateProfileAdded_ignoresUntilStartComplete() {
+ mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE);
+ reset(mDeviceProvisionedController);
+ when(mUserManager.isManagedProfile(anyInt())).thenReturn(false);
+ mBroadcastReceiver.getValue().onReceive(null,
+ (new Intent(Intent.ACTION_PROFILE_ADDED))
+ .putExtra(Intent.EXTRA_USER, PRIVATE_USER_HANDLE));
+ verify(mThemeOverlayApplier, never())
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ }
+
+
+ @Test
public void onWallpaperColorsChanged_firstEventBeforeUserSetup_shouldBeAccepted() {
// By default, on setup() we make this controller return that the user finished setup
// wizard. This test on the other hand, is testing the setup flow.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
index 60fe7d2..140e919 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorTest.kt
@@ -2,9 +2,8 @@
import android.content.pm.UserInfo
import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_REFACTOR_GET_CURRENT_USER
import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.user.data.repository.FakeUserRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.runBlocking
@@ -24,15 +23,12 @@
@Before
fun setUp() {
userRepository.setUserInfos(USER_INFOS)
- underTest =
- SelectedUserInteractor(
- userRepository,
- FakeFeatureFlagsClassic().apply { set(Flags.REFACTOR_GETCURRENTUSER, true) }
- )
+ underTest = SelectedUserInteractor(userRepository)
}
@Test
fun getSelectedUserIdReturnsId() {
+ mSetFlagsRule.enableFlags(FLAG_REFACTOR_GET_CURRENT_USER)
runBlocking { userRepository.setSelectedUserInfo(USER_INFOS[0]) }
val actualId = underTest.getSelectedUserId()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
new file mode 100644
index 0000000..607a4f3
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorCorrectionRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 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.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeColorCorrectionRepository : ColorCorrectionRepository {
+ private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+ return getFlow(userHandle.identifier)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean {
+ getFlow(userHandle.identifier).value = isEnabled
+ return true
+ }
+
+ /** initializes the flow if already not */
+ private fun getFlow(userId: Int): MutableStateFlow<Boolean> {
+ return userMap.getOrPut(userId) { MutableStateFlow(false) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
new file mode 100644
index 0000000..1c8bd3b
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeBiometricStatusRepository.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.systemui.biometrics.data.repository
+
+import com.android.systemui.biometrics.shared.model.AuthenticationReason
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeBiometricStatusRepository : BiometricStatusRepository {
+ private val _fingerprintAuthenticationReason =
+ MutableStateFlow<AuthenticationReason>(AuthenticationReason.NotRunning)
+ override val fingerprintAuthenticationReason: StateFlow<AuthenticationReason> =
+ _fingerprintAuthenticationReason.asStateFlow()
+
+ fun setFingerprintAuthenticationReason(reason: AuthenticationReason) {
+ _fingerprintAuthenticationReason.value = reason
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
index f84481c..ff5179a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt
@@ -1,5 +1,6 @@
package com.android.systemui.bouncer.data.repository
+import com.android.systemui.biometrics.shared.SideFpsControllerRefactor
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants
import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel
import com.android.systemui.dagger.SysUISingleton
@@ -113,7 +114,9 @@
_isBackButtonEnabled.value = isBackButtonEnabled
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
override fun setSideFpsShowing(isShowing: Boolean) {
+ SideFpsControllerRefactor.assertInLegacyMode()
_sideFpsShowing.value = isShowing
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
index c9160ef..1d44929 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -54,6 +54,11 @@
private var _authenticationStatus = MutableStateFlow<FingerprintAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = _authenticationStatus.filterNotNull()
+
+ private var _shouldUpdateIndicatorVisibility = MutableStateFlow(false)
+ override val shouldUpdateIndicatorVisibility: Flow<Boolean>
+ get() = _shouldUpdateIndicatorVisibility
+
fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) {
_authenticationStatus.value = status
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index c5d745a..4200f05 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -41,6 +41,10 @@
private val _deferKeyguardDone: MutableSharedFlow<KeyguardDone> = MutableSharedFlow()
override val keyguardDone: Flow<KeyguardDone> = _deferKeyguardDone
+ private val _keyguardDoneAnimationsFinished: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+ override val keyguardDoneAnimationsFinished: Flow<Unit> = _keyguardDoneAnimationsFinished
+
private val _clockShouldBeCentered = MutableStateFlow<Boolean>(true)
override val clockShouldBeCentered: Flow<Boolean> = _clockShouldBeCentered
@@ -176,6 +180,10 @@
_deferKeyguardDone.emit(timing)
}
+ override fun keyguardDoneAnimationsFinished() {
+ _keyguardDoneAnimationsFinished.tryEmit(Unit)
+ }
+
override fun setClockShouldBeCentered(shouldBeCentered: Boolean) {
_clockShouldBeCentered.value = shouldBeCentered
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
index 3d8ae1e..3cabf0c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardDismissInteractorFactory.kt
@@ -27,8 +27,6 @@
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -57,12 +55,6 @@
keyguardRepository: FakeKeyguardRepository = FakeKeyguardRepository(),
bouncerRepository: FakeKeyguardBouncerRepository = FakeKeyguardBouncerRepository(),
keyguardUpdateMonitor: KeyguardUpdateMonitor = mock(KeyguardUpdateMonitor::class.java),
- featureFlags: FakeFeatureFlagsClassic =
- FakeFeatureFlagsClassic().apply {
- set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, true)
- set(Flags.FULL_SCREEN_USER_SWITCHER, false)
- set(Flags.REFACTOR_GETCURRENTUSER, true)
- },
powerRepository: FakePowerRepository = FakePowerRepository(),
userRepository: FakeUserRepository = FakeUserRepository(),
): WithDependencies {
@@ -98,8 +90,7 @@
PowerInteractorFactory.create(
repository = powerRepository,
)
- val selectedUserInteractor =
- SelectedUserInteractor(repository = userRepository, flags = featureFlags)
+ val selectedUserInteractor = SelectedUserInteractor(repository = userRepository)
return WithDependencies(
trustRepository = trustRepository,
keyguardRepository = keyguardRepository,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
index e98f6db..0357036 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsLottieViewWrapper.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/colorcorrection/ColorCorrectionTileKosmos.kt
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.biometrics
-import android.content.Context
-import android.util.AttributeSet
-import com.android.systemui.util.wrapper.LottieViewWrapper
+package com.android.systemui.qs.tiles.impl.colorcorrection
-class SideFpsLottieViewWrapper
-@JvmOverloads
-constructor(context: Context, attrs: AttributeSet? = null) : LottieViewWrapper(context, attrs)
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+
+val Kosmos.qsColorCorrectionTileConfig by
+ Kosmos.Fixture { QSAccessibilityModule.provideColorCorrectionTileConfig(qsEventLogger) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index d78bcb9..0b41926 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -387,7 +387,7 @@
}
fun selectedUserInteractor(): SelectedUserInteractor {
- return SelectedUserInteractor(userRepository, featureFlags)
+ return SelectedUserInteractor(userRepository)
}
fun bouncerActionButtonInteractor(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
index 427f92a..89672f1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/domain/interactor/SelectedUserInteractorKosmos.kt
@@ -16,9 +16,7 @@
package com.android.systemui.user.domain.interactor
-import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.user.data.repository.userRepository
-val Kosmos.selectedUserInteractor by
- Kosmos.Fixture { SelectedUserInteractor(userRepository, featureFlagsClassic) }
+val Kosmos.selectedUserInteractor by Kosmos.Fixture { SelectedUserInteractor(userRepository) }
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index b8cf13b..e2488a5 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -19,6 +19,9 @@
defaults: [
"platform_service_defaults",
],
+ lint: {
+ error_checks: ["MissingPermissionAnnotation"],
+ },
srcs: [
":services.accessibility-sources",
"//frameworks/base/packages/SettingsLib/RestrictedLockUtils:SettingsLibRestrictedLockUtilsSrc",
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 97d36d4..1d73843 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -118,6 +118,7 @@
* This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
* It is responsible for behavior common to both types of clients.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
FingerprintGestureDispatcher.FingerprintGestureClient {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 9ddc35a..abcd8e2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -57,6 +57,7 @@
*
* NOTE: This class has to be created and poked only from the main thread.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityInputFilter extends InputFilter implements EventStreamTransformation {
private static final String TAG = AccessibilityInputFilter.class.getSimpleName();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index edb41639..3d8d7b7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -195,6 +195,7 @@
* event dispatch for {@link AccessibilityEvent}s generated across all processes
* on the device. Events are dispatched to {@link AccessibilityService}s.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class AccessibilityManagerService extends IAccessibilityManager.Stub
implements AbstractAccessibilityServiceConnection.SystemSupport,
AccessibilityUserState.ServiceInfoChangeListener,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 40ca694..5ebe161 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -65,6 +65,7 @@
* passed to the service it represents as soon it is bound. It also serves as the
* connection for the service.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnection {
private static final String LOG_TAG = "AccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index a525e7c..b119d7d 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -34,6 +34,7 @@
* If we are stripping and/or replacing the actions from a window, we need to intercept the
* nodes heading back to the service and swap out the actions.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ActionReplacingCallback extends IAccessibilityInteractionConnectionCallback.Stub {
private static final boolean DEBUG = false;
private static final String LOG_TAG = "ActionReplacingCallback";
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index c9ec16e..e10e87c 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -33,6 +33,7 @@
/**
* Encapsulate fingerprint gesture logic
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub
implements Handler.Callback{
private static final int MSG_REGISTER = 1;
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index ab01fc3..6aa4702 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -64,6 +64,7 @@
*
* TODO(241429275): Initialize this when a proxy is registered.
*/
+@SuppressWarnings("MissingPermissionAnnotation")
public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
private static final String LOG_TAG = "ProxyAccessibilityServiceConnection";
diff --git a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
index 53c629a..f69104d 100644
--- a/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/UiAutomationManager.java
@@ -245,6 +245,7 @@
}
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class UiAutomationService extends AbstractAccessibilityServiceConnection {
private final Handler mMainHandler;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index e6af54b..e11c36a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -922,6 +922,7 @@
disableWindowMagnification(displayId, true);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private class ConnectionCallback extends IMagnificationConnectionCallback.Stub implements
IBinder.DeathRecipient {
private boolean mExpiredDeathRecipient = false;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index c63784a..db5b313 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -246,6 +246,7 @@
return new RemoteAnimationCallback(callback, trace);
}
+ @SuppressWarnings("MissingPermissionAnnotation")
private static class RemoteAnimationCallback extends
IRemoteMagnificationAnimationCallback.Stub {
private final MagnificationAnimationCallback mCallback;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 77a5e3d..a4b2896 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -72,6 +72,7 @@
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -559,10 +560,11 @@
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
} else if (provider.maskedBySuspendedPackage) {
showBadge = mUserManager.hasBadge(appUserId);
- final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
+ final UserPackage suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
appInfo.packageName, appUserId);
// TODO(b/281839596): don't rely on platform always meaning suspended by admin.
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ if (suspendingPackage != null
+ && PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
appUserId, true);
} else {
diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig
index ab678d9..b5130a1 100644
--- a/services/autofill/bugfixes.aconfig
+++ b/services/autofill/bugfixes.aconfig
@@ -27,3 +27,10 @@
description: "Mitigation for view state reset to empty causing no save dialog to show issue"
bug: "297976948"
}
+
+flag {
+ name: "include_invisible_view_group_in_assist_structure"
+ namespace: "autofill"
+ description: "Mitigation for autofill providers miscalculating view visibility"
+ bug: "291795358"
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 23e7ce6..9fdf5c2 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -92,9 +92,10 @@
int userId = getNextIntArgRequired();
String packageName = getNextArgRequired();
String address = getNextArgRequired();
+ String deviceProfile = getNextArg();
final MacAddress macAddress = MacAddress.fromString(address);
mService.createNewAssociation(userId, packageName, macAddress,
- null, null, false);
+ null, deviceProfile, false);
}
break;
@@ -350,7 +351,7 @@
pw.println(" Print this help text.");
pw.println(" list USER_ID");
pw.println(" List all Associations for a user.");
- pw.println(" associate USER_ID PACKAGE MAC_ADDRESS");
+ pw.println(" associate USER_ID PACKAGE MAC_ADDRESS [DEVICE_PROFILE]");
pw.println(" Create a new Association.");
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 8dc6537..0d5cdcb 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -439,6 +439,12 @@
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
}
+ if (!VIRTUAL_DEVICE_COMPANION_DEVICE_PROFILES
+ .contains(associationInfo.getDeviceProfile())
+ && Flags.persistentDeviceIdApi()) {
+ throw new IllegalArgumentException("Unsupported CDM Association device profile "
+ + associationInfo.getDeviceProfile() + " for virtual device creation.");
+ }
Objects.requireNonNull(params);
Objects.requireNonNull(activityListener);
Objects.requireNonNull(soundEffectListener);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a0ccbf3a..f5a80d8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -200,6 +200,7 @@
"notification_flags_lib",
"biometrics_flags_lib",
"am_flags_lib",
+ "com_android_systemui_shared_flags_lib",
"com_android_wm_shell_flags_lib",
"com.android.server.utils_aconfig-java",
"service-jobscheduler-deviceidle.flags-aconfig-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 136692e..cac2efb 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -289,11 +289,11 @@
*
* @param suspendedPackage The package that has been suspended.
* @param userId The user for which to check.
- * @return Name of the package that suspended the given package. Returns {@code null} if the
- * given package is not currently suspended and the platform package name - i.e.
- * {@code "android"} - if the package was suspended by a device admin.
+ * @return User id and package name of the package that suspended the given package. Returns
+ * {@code null} if the given package is not currently suspended and the platform package name
+ * - i.e. {@code "android"} - if the package was suspended by a device admin.
*/
- public abstract String getSuspendingPackage(String suspendedPackage, int userId);
+ public abstract UserPackage getSuspendingPackage(String suspendedPackage, int userId);
/**
* Suspend or unsuspend packages upon admin request.
@@ -312,13 +312,13 @@
* suspended application.
*
* @param suspendedPackage The package that has been suspended.
- * @param suspendingPackage
+ * @param suspendingPackage The package responsible for suspension.
* @param userId The user for which to check.
* @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
*/
@Nullable
public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId);
+ UserPackage suspendingPackage, int userId);
/**
* Gets any distraction flags set via
@@ -1168,14 +1168,14 @@
public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
/**
- * Unsuspends all packages suspended by the given package for the user.
+ * Unsuspends all packages suspended by an admin for the user.
*/
- public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
+ public abstract void unsuspendAdminSuspendedPackages(int userId);
/**
- * Returns {@code true} if the package is suspending any packages for the user.
+ * Returns {@code true} if an admin is suspending any packages for the user.
*/
- public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
+ public abstract boolean isAdminSuspendingAnyPackages(int userId);
/**
* Register to listen for loading progress of an installed package.
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 33726d1..5a44ac8 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -974,6 +974,7 @@
unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw);
} break;
case "get": {
+ final int opts = parseOptions(shell);
final String key = shell.getNextArg();
if (key == null) {
pw.println("No property specified");
@@ -1007,11 +1008,17 @@
break;
case "current_now":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentMicroamps);
}
break;
case "current_average":
if (batteryServiceSupportCurrentAdbCommand()) {
+ if ((opts & OPTION_FORCE_UPDATE) != 0) {
+ updateHealthInfo();
+ }
pw.println(mHealthInfo.batteryCurrentAverageMicroamps);
}
break;
@@ -1125,6 +1132,14 @@
return 0;
}
+ private void updateHealthInfo() {
+ try {
+ mHealthServiceWrapper.scheduleUpdate();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to update health service data.", e);
+ }
+ }
+
private void setChargerAcOnline(boolean online, boolean forceUpdate) {
if (!mUpdatesStopped) {
copyV1Battery(mLastHealthInfo, mHealthInfo);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 21b2d32..2ee39c57 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -421,6 +421,7 @@
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.ArrayUtils;
@@ -468,7 +469,6 @@
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.power.stats.BatteryStatsImpl;
import com.android.server.sdksandbox.SdkSandboxManagerLocal;
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0629e637..dafea9a 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -36,6 +36,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.ComponentInfoInternal;
@@ -385,6 +386,26 @@
}
@Override
+ public void registerAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.registerAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterAuthenticationStateListener(AuthenticationStateListener listener)
+ throws RemoteException {
+ checkInternalPermission();
+ final IFingerprintService fingerprintService = mInjector.getFingerprintService();
+ if (fingerprintService != null) {
+ fingerprintService.unregisterAuthenticationStateListener(listener);
+ }
+ }
+
+ @Override
public void invalidateAuthenticatorIds(int userId, int fromSensorId,
IInvalidationCallback callback) throws RemoteException {
checkInternalPermission();
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index a47135f..f9568ea 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -27,7 +27,7 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.os.IBinder;
import android.os.RemoteException;
import android.security.KeyStore;
@@ -430,19 +430,19 @@
return mLockoutTracker;
}
- protected int getShowOverlayReason() {
+ protected int getRequestReason() {
if (isKeyguard()) {
- return BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
+ return BiometricRequestConstants.REASON_AUTH_KEYGUARD;
} else if (isBiometricPrompt()) {
// BP reason always takes precedent over settings, since callers from within
// settings can always invoke BP.
- return BiometricOverlayConstants.REASON_AUTH_BP;
+ return BiometricRequestConstants.REASON_AUTH_BP;
} else if (isSettings()) {
// This is pretty much only for FingerprintManager#authenticate usage from
// FingerprintSettings.
- return BiometricOverlayConstants.REASON_AUTH_SETTINGS;
+ return BiometricRequestConstants.REASON_AUTH_SETTINGS;
} else {
- return BiometricOverlayConstants.REASON_AUTH_OTHER;
+ return BiometricRequestConstants.REASON_AUTH_OTHER;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
new file mode 100644
index 0000000..5863535
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationStateListeners.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.annotation.NonNull;
+import android.hardware.biometrics.AuthenticationStateListener;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Low-level callback interface between BiometricManager and AuthService. Allows core system
+ * services (e.g. SystemUI) to register and unregister listeners for updates about the current
+ * state of biometric authentication.
+ * @hide */
+public class AuthenticationStateListeners implements IBinder.DeathRecipient {
+
+ private static final String TAG = "AuthenticationStateListeners";
+
+ @NonNull
+ private final CopyOnWriteArrayList<AuthenticationStateListener> mAuthenticationStateListeners =
+ new CopyOnWriteArrayList<>();
+
+ /**
+ * Enables clients to register an AuthenticationStateListener for updates about the current
+ * state of biometric authentication.
+ * @param listener listener to register
+ */
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.add(listener);
+ try {
+ listener.asBinder().linkToDeath(this, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death", e);
+ }
+ }
+
+ /**
+ * Enables clients to unregister an AuthenticationStateListener.
+ * @param listener listener to register
+ */
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ mAuthenticationStateListeners.remove(listener);
+ }
+
+ /**
+ * Defines behavior in response to authentication starting
+ * @param requestReason reason from [BiometricRequestConstants.RequestReason] for requesting
+ * authentication starting
+ */
+ public void onAuthenticationStarted(int requestReason) {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStarted(requestReason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "started", e);
+ }
+ }
+ }
+
+ /**
+ * Defines behavior in response to authentication stopping
+ */
+ public void onAuthenticationStopped() {
+ for (AuthenticationStateListener listener: mAuthenticationStateListeners) {
+ try {
+ listener.onAuthenticationStopped();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in notifying listener that authentication "
+ + "stopped", e);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Do nothing, handled below
+ }
+
+ @Override
+ public void binderDied(IBinder who) {
+ Slog.w(TAG, "Callback binder died: " + who);
+ if (mAuthenticationStateListeners.removeIf(listener -> listener.asBinder().equals(who))) {
+ Slog.w(TAG, "Removed dead listener for " + who);
+ } else {
+ Slog.w(TAG, "No dead listeners found");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 483ce75..2c4d30b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.FingerprintManager;
import android.os.IBinder;
import android.os.RemoteException;
@@ -135,14 +135,14 @@
return true;
}
- protected int getOverlayReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
+ protected int getRequestReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
switch (reason) {
case FingerprintManager.ENROLL_FIND_SENSOR:
- return BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;
+ return BiometricRequestConstants.REASON_ENROLL_FIND_SENSOR;
case FingerprintManager.ENROLL_ENROLL:
- return BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
+ return BiometricRequestConstants.REASON_ENROLL_ENROLLING;
default:
- return BiometricOverlayConstants.REASON_UNKNOWN;
+ return BiometricRequestConstants.REASON_UNKNOWN;
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index aeb6b6e..3d20efc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -16,9 +16,11 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
@@ -42,6 +44,8 @@
private static final String TAG = "SensorOverlays";
@NonNull private final Optional<IUdfpsOverlayController> mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@NonNull private final Optional<ISidefpsController> mSidefpsController;
/**
@@ -58,19 +62,32 @@
}
/**
+ * Create an overlay controller for each modality.
+ *
+ * @param udfpsOverlayController under display fps or null if not present on device
+ */
+ public SensorOverlays(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ mUdfpsOverlayController = Optional.ofNullable(udfpsOverlayController);
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController = Optional.empty();
+ }
+
+ /**
* Show the overlay.
*
* @param sensorId sensor id
* @param reason reason for showing
* @param client client performing operation
*/
- public void show(int sensorId, @BiometricOverlayConstants.ShowReason int reason,
+ public void show(int sensorId, @BiometricRequestConstants.RequestReason int reason,
@NonNull AcquisitionClient<?> client) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().show(sensorId, reason);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().show(sensorId, reason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when showing the side-fps overlay", e);
+ }
}
}
@@ -98,11 +115,13 @@
* @param sensorId sensor id
*/
public void hide(int sensorId) {
- if (mSidefpsController.isPresent()) {
- try {
- mSidefpsController.get().hide(sensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ if (!sidefpsControllerRefactor()) {
+ if (mSidefpsController.isPresent()) {
+ try {
+ mSidefpsController.get().hide(sensorId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when hiding the side-fps overlay", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 7695543..83b306b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -33,6 +33,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -81,6 +82,7 @@
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -128,6 +130,8 @@
private final BiometricStateCallback<ServiceProvider, FingerprintSensorPropertiesInternal>
mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final Handler mHandler;
@NonNull
private final FingerprintServiceRegistry mRegistry;
@@ -891,6 +895,7 @@
return providers;
});
}
+
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void addAuthenticatorsRegisteredCallback(
@@ -902,6 +907,24 @@
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
+ public void registerAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.registerAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.registerAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void unregisterAuthenticationStateListener(
+ @NonNull AuthenticationStateListener listener) {
+ super.unregisterAuthenticationStateListener_enforcePermission();
+
+ mAuthenticationStateListeners.unregisterAuthenticationStateListener(listener);
+ }
+
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
super.registerBiometricStateListener_enforcePermission();
@@ -957,6 +980,7 @@
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
@@ -1014,6 +1038,7 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mBiometricStateCallback = new BiometricStateCallback<>(UserManager.get(context));
+ mAuthenticationStateListeners = new AuthenticationStateListeners();
mFingerprintProvider = fingerprintProvider != null ? fingerprintProvider :
(name) -> {
final String fqName = IFingerprint.DESCRIPTOR + "/" + name;
@@ -1022,9 +1047,9 @@
if (fp != null) {
try {
return new FingerprintProvider(getContext(),
- mBiometricStateCallback, fp.getSensorProps(), name,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
- mBiometricContext);
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ fp.getSensorProps(), name, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher, mBiometricContext);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
}
@@ -1086,13 +1111,13 @@
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
+ mBiometricStateCallback, mAuthenticationStateListeners,
+ hidlSensor, mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
- mBiometricStateCallback, hidlSensor, mHandler,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mBiometricStateCallback, mAuthenticationStateListeners, hidlSensor,
+ mHandler, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
providers.add(fingerprint21);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index a15d1a4..fc37d70 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -135,6 +135,7 @@
void onPowerPressed();
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
/**
* Sets side-fps controller
* @param controller side-fps controller
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 337c3c2..29c5a3d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -48,6 +50,7 @@
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -84,6 +87,7 @@
private final int mSkipWaitForPowerVendorAcquireMessage;
private final long mFingerUpIgnoresPower = 500;
private final AuthSessionCoordinator mAuthSessionCoordinator;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable
private ICancellationSignal mCancellationSignal;
private boolean mIsPointerDown;
@@ -110,7 +114,9 @@
boolean isStrongBiometric,
@Nullable TaskStackListener taskStackListener,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@@ -136,7 +142,12 @@
false /* shouldVibrate */,
biometricStrength);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
mHandler = handler;
@@ -216,6 +227,9 @@
if (authenticated) {
mState = STATE_STOPPED;
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
}
@@ -241,6 +255,9 @@
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -266,11 +283,17 @@
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
mCancellationSignal = doAuthenticate();
@@ -280,6 +303,9 @@
BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -323,6 +349,9 @@
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
@@ -423,6 +452,9 @@
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
@@ -450,6 +482,9 @@
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index e2413ee..e58e5ae 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -16,10 +16,12 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -66,7 +68,12 @@
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController*/);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mOptions = options;
}
@@ -93,7 +100,7 @@
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 06550d8..c0761ed 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,6 +44,7 @@
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -65,6 +68,7 @@
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
@Nullable private ICancellationSignal mCancellationSignal;
private final int mMaxTemplatesPerUser;
private boolean mIsPointerDown;
@@ -80,15 +84,18 @@
}
}
- public FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<AidlSession> lazyDaemon, @NonNull IBinder token, long requestId,
+ public FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<AidlSession> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
int maxTemplatesPerUser, @FingerprintManager.EnrollReason int enrollReason) {
// UDFPS haptics occur when an image is acquired (instead of when the result is known)
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
@@ -96,7 +103,13 @@
logger, biometricContext);
setRequestId(requestId);
mSensorProps = sensorProps;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
+
mMaxTemplatesPerUser = maxTemplatesPerUser;
mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */);
@@ -130,7 +143,11 @@
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
+
}
@Override
@@ -159,8 +176,10 @@
@Override
public void onError(int errorCode, int vendorCode) {
super.onError(errorCode, vendorCode);
-
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
@@ -171,8 +190,12 @@
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -210,6 +233,10 @@
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
+
unsubscribeBiometricContext();
if (mCancellationSignal != null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 9985b06..032ab87 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -64,6 +64,7 @@
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -108,6 +109,8 @@
@NonNull
private final BiometricStateCallback mBiometricStateCallback;
@NonNull
+ private final AuthenticationStateListeners mAuthenticationStateListeners;
+ @NonNull
private final String mHalInstanceName;
@NonNull
private final Handler mHandler;
@@ -122,6 +125,7 @@
@NonNull private final BiometricContext mBiometricContext;
@Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
private AuthSessionCoordinator mAuthSessionCoordinator;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -157,16 +161,19 @@
public FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext, null /* daemon */);
+ this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName,
+ lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext,
+ null /* daemon */);
}
@VisibleForTesting FingerprintProvider(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -174,6 +181,7 @@
IFingerprint daemon) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mHalInstanceName = halInstanceName;
mFingerprintSensors = new SensorList<>(ActivityManager.getService());
mHandler = new Handler(Looper.getMainLooper());
@@ -434,7 +442,7 @@
mBiometricContext,
mFingerprintSensors.get(sensorId).getSensorProperties(),
mUdfpsOverlayController, mSidefpsController,
- maxTemplatesPerUser, enrollReason);
+ mAuthenticationStateListeners, maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(
mBiometricStateCallback, new ClientMonitorCallback() {
@Override
@@ -498,7 +506,7 @@
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
- allowBackgroundAuthentication,
+ mAuthenticationStateListeners, allowBackgroundAuthentication,
mFingerprintSensors.get(sensorId).getSensorProperties(), mHandler,
Utils.getCurrentStrength(sensorId),
SystemClock.elapsedRealtimeClock(),
@@ -732,6 +740,7 @@
}
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 8bfa560..d3cecd0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -68,6 +68,7 @@
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -115,6 +116,7 @@
final Context mContext;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -128,6 +130,8 @@
@Nullable private IBiometricsFingerprint mDaemon;
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
+
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable private ISidefpsController mSidefpsController;
@NonNull private final BiometricContext mBiometricContext;
@Nullable private AuthenticationStatsCollector mAuthenticationStatsCollector;
@@ -330,6 +334,7 @@
@VisibleForTesting
Fingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler,
@NonNull Handler handler,
@@ -338,6 +343,7 @@
@NonNull BiometricContext biometricContext) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
+ mAuthenticationStateListeners = authenticationStateListeners;
mBiometricContext = biometricContext;
mSensorProperties = sensorProps;
@@ -378,6 +384,7 @@
public static Fingerprint21 newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@@ -388,8 +395,9 @@
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler, scheduler);
- return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, BiometricContext.getInstance(context));
+ return new Fingerprint21(context, biometricStateCallback, authenticationStateListeners,
+ sensorProps, scheduler, handler, lockoutResetDispatcher, controller,
+ BiometricContext.getInstance(context));
}
@Override
@@ -719,7 +727,10 @@
mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN, mAuthenticationStatsCollector),
- mBiometricContext, mUdfpsOverlayController, mSidefpsController, enrollReason);
+ mBiometricContext, mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners, enrollReason);
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -761,10 +772,14 @@
BiometricsProtoEnums.CLIENT_UNKNOWN,
mAuthenticationStatsCollector),
mBiometricContext, null /* sensorProps */,
- mUdfpsOverlayController, mSidefpsController,
+ mUdfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
+ mSidefpsController,
+ mAuthenticationStateListeners,
mContext.getResources().getInteger(
com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser),
enrollReason);
+
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
@@ -880,6 +895,7 @@
mBiometricContext, isStrongBiometric,
mTaskStackListener,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties, mHandler,
Utils.getCurrentStrength(mSensorId), null /* clock */, mLockoutTracker);
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -898,6 +914,7 @@
mBiometricContext, isStrongBiometric,
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController,
+ mAuthenticationStateListeners,
allowBackgroundAuthentication, mSensorProperties,
Utils.getCurrentStrength(mSensorId));
mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
@@ -1123,6 +1140,7 @@
mUdfpsOverlayController = controller;
}
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Override
public void setSidefpsController(@NonNull ISidefpsController controller) {
mSidefpsController = controller;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index c1a9370..88dae6f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -41,6 +41,7 @@
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -248,6 +249,7 @@
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -259,8 +261,9 @@
new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, biometricStateCallback, sensorProps, scheduler,
- handler, lockoutResetDispatcher, controller, biometricContext);
+ return new Fingerprint21UdfpsMock(context, biometricStateCallback,
+ authenticationStateListeners, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller, biometricContext);
}
private static abstract class FakeFingerRunnable implements Runnable {
@@ -388,14 +391,15 @@
private Fingerprint21UdfpsMock(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps, scheduler,
+ handler, lockoutResetDispatcher, controller, biometricContext);
mScheduler = scheduler;
mScheduler.init(this);
mHandler = handler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 9966e91..4c1d4d6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
@@ -40,6 +42,7 @@
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +71,7 @@
@NonNull private final SensorOverlays mSensorOverlays;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProps;
@NonNull private final CallbackWithProbe<Probe> mALSProbeCallback;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
@@ -81,7 +85,9 @@
@NonNull TaskStackListener taskStackListener,
@NonNull LockoutFrameworkImpl lockoutTracker,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
boolean allowBackgroundAuthentication,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@Authenticators.Types int sensorStrength) {
@@ -91,7 +97,12 @@
false /* shouldVibrate */, sensorStrength);
setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mSensorProps = sensorProps;
mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
}
@@ -128,6 +139,9 @@
mState = STATE_STOPPED;
resetFailedAttempts(getTargetUserId());
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
} else {
mState = STATE_STARTED_PAUSED_ATTEMPTED;
final @LockoutTracker.LockoutMode int lockoutMode =
@@ -141,6 +155,9 @@
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -156,6 +173,9 @@
}
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
private void resetFailedAttempts(int userId) {
@@ -205,7 +225,10 @@
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getShowOverlayReason(), this);
+ mSensorOverlays.show(getSensorId(), getRequestReason(), this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(getRequestReason());
+ }
try {
// GroupId was never used. In fact, groupId is always the same as userId.
@@ -215,6 +238,9 @@
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -222,6 +248,9 @@
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 0d7f9f2..6e029d2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -16,12 +16,14 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.biometrics.fingerprint.PointerContext;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.FingerprintAuthenticateOptions;
@@ -71,7 +73,12 @@
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
true /* shouldVibrate */, biometricLogger, biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, null /* sideFpsController */);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(
+ udfpsOverlayController, null /* sideFpsController */);
+ }
mIsStrongBiometric = isStrongBiometric;
}
@@ -97,7 +104,7 @@
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), BiometricOverlayConstants.REASON_AUTH_KEYGUARD,
+ mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
try {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 382e7e2..26332ff 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.hidl;
+import static com.android.systemui.shared.Flags.sidefpsControllerRefactor;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -34,6 +36,7 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricNotificationUtils;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
@@ -58,22 +61,31 @@
@NonNull private final SensorOverlays mSensorOverlays;
private final @FingerprintManager.EnrollReason int mEnrollReason;
+ @NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private boolean mIsPointerDown;
- FingerprintEnrollClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
- long requestId, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ FingerprintEnrollClient(
+ @NonNull Context context, @NonNull Supplier<IBiometricsFingerprint> lazyDaemon,
+ @NonNull IBinder token, long requestId,
+ @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int timeoutSec, int sensorId,
@NonNull BiometricLogger biometricLogger, @NonNull BiometricContext biometricContext,
@Nullable IUdfpsOverlayController udfpsOverlayController,
+ // TODO(b/288175061): remove with Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR
@Nullable ISidefpsController sidefpsController,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, sensorId, true /* shouldVibrate */, biometricLogger,
biometricContext);
setRequestId(requestId);
- mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ if (sidefpsControllerRefactor()) {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController);
+ } else {
+ mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
+ }
+ mAuthenticationStateListeners = authenticationStateListeners;
mEnrollReason = enrollReason;
if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
@@ -110,8 +122,12 @@
@Override
protected void startHalOperation() {
- mSensorOverlays.show(getSensorId(), getOverlayReasonFromEnrollReason(mEnrollReason),
+ mSensorOverlays.show(getSensorId(), getRequestReasonFromEnrollReason(mEnrollReason),
this);
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStarted(
+ getRequestReasonFromEnrollReason(mEnrollReason));
+ }
BiometricNotificationUtils.cancelBadCalibrationNotification(getContext());
try {
@@ -122,6 +138,9 @@
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
mCallback.onClientFinished(this, false /* success */);
}
}
@@ -129,6 +148,9 @@
@Override
protected void stopHalOperation() {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
try {
getFreshDaemon().cancel();
@@ -149,6 +171,9 @@
if (remaining == 0) {
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
}
@@ -170,6 +195,9 @@
super.onError(errorCode, vendorCode);
mSensorOverlays.hide(getSensorId());
+ if (sidefpsControllerRefactor()) {
+ mAuthenticationStateListeners.onAuthenticationStopped();
+ }
}
@Override
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index dff14b5..6ec6a12 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -327,7 +327,7 @@
Optional<DeviceState> getOverrideState() {
synchronized (mLock) {
if (mActiveOverride.isPresent()) {
- return getStateLocked(mActiveOverride.get().getRequestedState());
+ return getStateLocked(mActiveOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -342,7 +342,7 @@
Optional<DeviceState> getOverrideBaseState() {
synchronized (mLock) {
if (mActiveBaseStateOverride.isPresent()) {
- return getStateLocked(mActiveBaseStateOverride.get().getRequestedState());
+ return getStateLocked(mActiveBaseStateOverride.get().getRequestedStateIdentifier());
}
return Optional.empty();
}
@@ -499,6 +499,7 @@
* @return {@code true} if the pending state has changed as a result of this call, {@code false}
* otherwise.
*/
+ @GuardedBy("mLock")
private boolean updatePendingStateLocked() {
if (mPendingState.isPresent()) {
// Have pending state, can not configure a new state until the state is committed.
@@ -507,7 +508,8 @@
final DeviceState stateToConfigure;
if (mActiveOverride.isPresent()) {
- stateToConfigure = getStateLocked(mActiveOverride.get().getRequestedState()).get();
+ stateToConfigure = getStateLocked(
+ mActiveOverride.get().getRequestedStateIdentifier()).get();
} else if (mBaseState.isPresent()
&& isSupportedStateLocked(mBaseState.get().getIdentifier())) {
// Base state could have recently become unsupported after a change in supported states.
@@ -599,7 +601,7 @@
// requested state is committed.
OverrideRequest activeRequest = mActiveOverride.orElse(null);
if (activeRequest != null
- && activeRequest.getRequestedState() == newState.getIdentifier()) {
+ && activeRequest.getRequestedStateIdentifier() == newState.getIdentifier()) {
ProcessRecord processRecord = mProcessRecords.get(activeRequest.getPid());
if (processRecord != null) {
processRecord.notifyRequestActiveAsync(activeRequest.getToken());
@@ -666,21 +668,21 @@
case STATUS_ACTIVE:
mActiveOverride = Optional.of(request);
mDeviceStateNotificationController.showStateActiveNotificationIfNeeded(
- request.getRequestedState(), request.getUid());
+ request.getRequestedStateIdentifier(), request.getUid());
break;
case STATUS_CANCELED:
if (mActiveOverride.isPresent() && mActiveOverride.get() == request) {
mActiveOverride = Optional.empty();
mDeviceStateNotificationController.cancelNotification(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
if ((flags & FLAG_THERMAL_CRITICAL) == FLAG_THERMAL_CRITICAL) {
mDeviceStateNotificationController
.showThermalCriticalNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
} else if ((flags & FLAG_POWER_SAVE_ENABLED) == FLAG_POWER_SAVE_ENABLED) {
mDeviceStateNotificationController
.showPowerSaveNotificationIfNeeded(
- request.getRequestedState());
+ request.getRequestedStateIdentifier());
}
}
break;
@@ -723,7 +725,7 @@
*/
@GuardedBy("mLock")
private void enableBaseStateRequestLocked(OverrideRequest request) {
- setBaseState(request.getRequestedState());
+ setBaseState(request.getRequestedStateIdentifier());
mActiveBaseStateOverride = Optional.of(request);
ProcessRecord processRecord = mProcessRecords.get(request.getPid());
processRecord.notifyRequestActiveAsync(request.getToken());
@@ -762,6 +764,11 @@
synchronized (mLock) {
mProcessRecords.remove(processRecord.mPid);
mOverrideRequestController.handleProcessDied(processRecord.mPid);
+
+ if (shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
+ OverrideRequest request = mActiveOverride.get();
+ mOverrideRequestController.cancelRequest(request);
+ }
}
}
@@ -787,7 +794,7 @@
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
// If we don't have the CONTROL_DEVICE_STATE permission, we want to show the overlay
if (!hasControlDeviceStatePermission && mRearDisplayState != null
@@ -848,7 +855,7 @@
}
OverrideRequest request = new OverrideRequest(token, callingPid, callingUid,
- state, flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ deviceState.get(), flags, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mOverrideRequestController.addBaseStateRequest(request);
}
}
@@ -1318,7 +1325,7 @@
if (mActiveOverride.isEmpty()) {
return false;
}
- int identifier = mActiveOverride.get().getRequestedState();
+ int identifier = mActiveOverride.get().getRequestedStateIdentifier();
DeviceState deviceState = mDeviceStates.get(identifier);
return deviceState.hasFlag(DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
}
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequest.java b/services/core/java/com/android/server/devicestate/OverrideRequest.java
index 74cf184..20485c1 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequest.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequest.java
@@ -17,6 +17,7 @@
package com.android.server.devicestate;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.hardware.devicestate.DeviceStateRequest;
import android.os.IBinder;
@@ -32,7 +33,8 @@
private final IBinder mToken;
private final int mPid;
private final int mUid;
- private final int mRequestedState;
+ @NonNull
+ private final DeviceState mRequestedState;
@DeviceStateRequest.RequestFlags
private final int mFlags;
@OverrideRequestType
@@ -69,7 +71,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface OverrideRequestType {}
- OverrideRequest(IBinder token, int pid, int uid, int requestedState,
+ OverrideRequest(IBinder token, int pid, int uid, @NonNull DeviceState requestedState,
@DeviceStateRequest.RequestFlags int flags, @OverrideRequestType int requestType) {
mToken = token;
mPid = pid;
@@ -91,10 +93,15 @@
return mUid;
}
- int getRequestedState() {
+ @NonNull
+ DeviceState getRequestedDeviceState() {
return mRequestedState;
}
+ int getRequestedStateIdentifier() {
+ return mRequestedState.getIdentifier();
+ }
+
@DeviceStateRequest.RequestFlags
int getFlags() {
return mFlags;
diff --git a/services/core/java/com/android/server/devicestate/OverrideRequestController.java b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
index 46f0bc0..f5f2fa8 100644
--- a/services/core/java/com/android/server/devicestate/OverrideRequestController.java
+++ b/services/core/java/com/android/server/devicestate/OverrideRequestController.java
@@ -204,6 +204,12 @@
}
if (mRequest != null && mRequest.getPid() == pid) {
+ if (mRequest.getRequestedDeviceState().hasFlag(
+ DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP)) {
+ cancelCurrentRequestLocked();
+ return;
+ }
+
if (mStickyRequestsAllowed) {
// Do not cancel the requests now because sticky requests are allowed. These
// requests will be cancelled on a call to cancelStickyRequests().
@@ -219,7 +225,7 @@
* listener of all changes to request status as a result of this change.
*/
void handleBaseStateChanged(int state) {
- if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedState()) {
+ if (mBaseStateRequest != null && state != mBaseStateRequest.getRequestedStateIdentifier()) {
cancelBaseStateOverrideRequest();
}
if (mRequest == null) {
@@ -246,11 +252,12 @@
flags |= isThermalCritical ? FLAG_THERMAL_CRITICAL : 0;
flags |= isPowerSaveEnabled ? FLAG_POWER_SAVE_ENABLED : 0;
if (mBaseStateRequest != null && !contains(newSupportedStates,
- mBaseStateRequest.getRequestedState())) {
+ mBaseStateRequest.getRequestedStateIdentifier())) {
cancelCurrentBaseStateRequestLocked(flags);
}
- if (mRequest != null && !contains(newSupportedStates, mRequest.getRequestedState())) {
+ if (mRequest != null && !contains(newSupportedStates,
+ mRequest.getRequestedStateIdentifier())) {
cancelCurrentRequestLocked(flags);
}
}
@@ -262,7 +269,7 @@
pw.println("Override Request active: " + requestActive);
if (requestActive) {
pw.println("Request: mPid=" + overrideRequest.getPid()
- + ", mRequestedState=" + overrideRequest.getRequestedState()
+ + ", mRequestedState=" + overrideRequest.getRequestedStateIdentifier()
+ ", mFlags=" + overrideRequest.getFlags()
+ ", mStatus=" + statusToString(STATUS_ACTIVE));
}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 80c3a27..b542893 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -583,8 +583,8 @@
pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
pw.println(" mAmbientLux=" + mAmbientLux);
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
- pw.println(" mPreThesholdLux=" + mPreThresholdLux);
- pw.println(" mPreThesholdBrightness=" + mPreThresholdBrightness);
+ pw.println(" mPreThresholdLux=" + mPreThresholdLux);
+ pw.println(" mPreThresholdBrightness=" + mPreThresholdBrightness);
pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c440a64..16e043c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -6499,10 +6499,12 @@
nextEnabledImes).getId();
// Reset enabled IMEs.
- settings.putEnabledInputMethodsStr("");
- nextEnabledImes.forEach(
- imi -> settings.appendAndPutEnabledInputMethodLocked(
- imi.getId()));
+ final String[] nextEnabledImeIds = new String[nextEnabledImes.size()];
+ for (int i = 0; i < nextEnabledImeIds.length; ++i) {
+ nextEnabledImeIds[i] = nextEnabledImes.get(i).getId();
+ }
+ settings.putEnabledInputMethodsStr(InputMethodUtils.concatEnabledImeIds(
+ settings.getEnabledInputMethodsStr(), nextEnabledImeIds));
// Reset selected IME.
settings.putSelectedInputMethod(nextIme);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 2128356..773293f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -33,6 +33,7 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -50,6 +51,8 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -952,24 +955,64 @@
final String enabledInputMethodsStr = TextUtils.nullIfEmpty(
SecureSettingsWrapper.getString(Settings.Secure.ENABLED_INPUT_METHODS, null,
userId));
- if (enabledInputMethodsStr == null) {
- return List.of();
+ final ArrayList<String> result = new ArrayList<>();
+ splitEnabledImeStr(enabledInputMethodsStr, result::add);
+ return result;
+ }
+
+ /**
+ * Split enabled IME string ({@link Settings.Secure#ENABLED_INPUT_METHODS}) into IME IDs.
+ *
+ * @param text a text formatted with {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ * @param consumer {@link Consumer} called back when a new IME ID is found.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ static void splitEnabledImeStr(@Nullable String text, @NonNull Consumer<String> consumer) {
+ if (TextUtils.isEmpty(text)) {
+ return;
}
final TextUtils.SimpleStringSplitter inputMethodSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATOR);
final TextUtils.SimpleStringSplitter subtypeSplitter =
new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATOR);
- inputMethodSplitter.setString(enabledInputMethodsStr);
- final ArrayList<String> result = new ArrayList<>();
+ inputMethodSplitter.setString(text);
while (inputMethodSplitter.hasNext()) {
String nextImsStr = inputMethodSplitter.next();
subtypeSplitter.setString(nextImsStr);
if (subtypeSplitter.hasNext()) {
// The first element is ime id.
- result.add(subtypeSplitter.next());
+ consumer.accept(subtypeSplitter.next());
}
}
- return result;
+ }
+
+ /**
+ * Concat given IME IDs with an existing enabled IME
+ * ({@link Settings.Secure#ENABLED_INPUT_METHODS}).
+ *
+ * @param existingEnabledImeId an existing {@link Settings.Secure#ENABLED_INPUT_METHODS} to
+ * which {@code imeIDs} will be added.
+ * @param imeIds an array of IME IDs to be added. For IME IDs that are already seen in
+ * {@code existingEnabledImeId} will be skipped.
+ * @return a new enabled IME ID string that can be stored in
+ * {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+ */
+ @NonNull
+ static String concatEnabledImeIds(@NonNull String existingEnabledImeId,
+ @NonNull String... imeIds) {
+ final ArraySet<String> alreadyEnabledIds = new ArraySet<>();
+ final StringJoiner joiner = new StringJoiner(Character.toString(INPUT_METHOD_SEPARATOR));
+ if (!TextUtils.isEmpty(existingEnabledImeId)) {
+ splitEnabledImeStr(existingEnabledImeId, alreadyEnabledIds::add);
+ joiner.add(existingEnabledImeId);
+ }
+ for (String id : imeIds) {
+ if (!alreadyEnabledIds.contains(id)) {
+ joiner.add(id);
+ alreadyEnabledIds.add(id);
+ }
+ }
+ return joiner.toString();
}
/**
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index ec858ee2..f2dcba4 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -59,6 +59,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
@@ -67,7 +68,6 @@
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index bab3cbe..9c27c22 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.contexthub.HostEndpointInfo;
+import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.NanSessionRequest;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
@@ -467,6 +468,11 @@
// TODO(271471342): Implement
}
+ public void handleMessageDeliveryStatus(char hostEndPointId,
+ MessageDeliveryStatus messageDeliveryStatus) {
+ // TODO(b/312417087): Implement reliable message support
+ }
+
public byte[] getUuid() {
return UUID;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index df9e741..5e18727 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -964,6 +964,7 @@
disposeUserIfNeededLocked(userRecord); // since router removed from user
}
+ @GuardedBy("mLock")
private void setDiscoveryRequestWithRouter2Locked(@NonNull RouterRecord routerRecord,
@NonNull RouteDiscoveryPreference discoveryRequest) {
if (routerRecord.mDiscoveryPreference.equals(discoveryRequest)) {
@@ -1016,6 +1017,7 @@
routeListingPreference));
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull MediaRoute2Info route, int volume) {
final IBinder binder = router.asBinder();
@@ -1035,6 +1037,7 @@
}
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithRouter2Locked(int requestId, long managerRequestId,
@NonNull IMediaRouter2 router, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route, @Nullable Bundle sessionHints) {
@@ -1117,6 +1120,7 @@
sessionHints));
}
+ @GuardedBy("mLock")
private void selectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1138,6 +1142,7 @@
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1159,6 +1164,7 @@
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = router.asBinder();
@@ -1191,6 +1197,7 @@
}
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId, int volume) {
final IBinder binder = router.asBinder();
@@ -1215,6 +1222,7 @@
DUMMY_REQUEST_ID, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithRouter2Locked(@NonNull IMediaRouter2 router,
@NonNull String uniqueSessionId) {
final IBinder binder = router.asBinder();
@@ -1240,6 +1248,7 @@
// Start of locked methods that are used by MediaRouter2Manager.
+ @GuardedBy("mLock")
private List<RoutingSessionInfo> getRemoteSessionsLocked(
@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
@@ -1330,6 +1339,7 @@
UserHandler::notifyInitialRoutesToManager, userRecord.mHandler, manager));
}
+ @GuardedBy("mLock")
private void unregisterManagerLocked(@NonNull IMediaRouter2Manager manager, boolean died) {
ManagerRecord managerRecord = mAllManagerRecords.remove(manager.asBinder());
if (managerRecord == null) {
@@ -1355,6 +1365,7 @@
disposeUserIfNeededLocked(userRecord); // since manager removed from user
}
+ @GuardedBy("mLock")
private void startScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1368,6 +1379,7 @@
managerRecord.startScan();
}
+ @GuardedBy("mLock")
private void stopScanLocked(@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
ManagerRecord managerRecord = mAllManagerRecords.get(binder);
@@ -1381,6 +1393,7 @@
managerRecord.stopScan();
}
+ @GuardedBy("mLock")
private void setRouteVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull MediaRoute2Info route, int volume) {
@@ -1402,6 +1415,7 @@
uniqueRequestId, route, volume));
}
+ @GuardedBy("mLock")
private void requestCreateSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull RoutingSessionInfo oldSession,
@NonNull MediaRoute2Info route) {
@@ -1455,6 +1469,7 @@
uniqueRequestId, routerRecord, managerRecord, oldSession, route));
}
+ @GuardedBy("mLock")
private void selectRouteWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
final IBinder binder = manager.asBinder();
@@ -1479,6 +1494,7 @@
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void deselectRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1504,6 +1520,7 @@
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void transferToRouteWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
@@ -1529,6 +1546,7 @@
uniqueRequestId, routerRecord, uniqueSessionId, route));
}
+ @GuardedBy("mLock")
private void setSessionVolumeWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager,
@NonNull String uniqueSessionId, int volume) {
@@ -1550,6 +1568,7 @@
uniqueRequestId, uniqueSessionId, volume));
}
+ @GuardedBy("mLock")
private void releaseSessionWithManagerLocked(int requestId,
@NonNull IMediaRouter2Manager manager, @NonNull String uniqueSessionId) {
final IBinder binder = manager.asBinder();
@@ -1652,6 +1671,7 @@
// TODO: This assumes that only one router exists in a package.
// Do this in Android S or later.
+ @GuardedBy("mLock")
RouterRecord findRouterRecordLocked(String packageName) {
for (RouterRecord routerRecord : mRouterRecords) {
if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
@@ -1739,6 +1759,7 @@
return mHasModifyAudioRoutingPermission || mHasBluetoothRoutingPermission.get();
}
+ @GuardedBy("mLock")
public void maybeUpdateSystemRoutingPermissionLocked() {
boolean oldSystemRoutingPermissionValue = hasSystemRoutingPermission();
mHasBluetoothRoutingPermission.set(checkCallerHasBluetoothPermissions(mPid, mUid));
@@ -2063,6 +2084,7 @@
this, provider, uniqueRequestId, reason));
}
+ @GuardedBy("mLock")
@Nullable
public RouterRecord findRouterWithSessionLocked(@NonNull String uniqueSessionId) {
return mSessionToRouterMap.get(uniqueSessionId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index b12180b..4b8de4e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -19,6 +19,7 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.service.notification.DeviceEffectsApplier;
import java.util.Set;
@@ -54,4 +55,22 @@
void cleanupHistoryFiles();
void removeBitmaps();
+
+ /**
+ * Sets the {@link DeviceEffectsApplier} that will be used to apply the different
+ * {@link android.service.notification.ZenDeviceEffects} that are relevant for the platform
+ * when {@link android.service.notification.ZenModeConfig.ZenRule} instances are activated and
+ * deactivated.
+ *
+ * <p>This method is optional and needs only be called if the platform supports non-standard
+ * effects (i.e. any that are not <em>public APIs</em> in
+ * {@link android.service.notification.ZenDeviceEffects}, or if they must be applied in a
+ * non-standard fashion. If not used, a {@link DefaultDeviceEffectsApplier} will be invoked,
+ * which should be sufficient for most devices.
+ *
+ * <p>If this method is called, it <em>must</em> be during system startup and <em>before</em>
+ * the {@link com.android.server.SystemService#PHASE_THIRD_PARTY_APPS_CAN_START} boot phase.
+ * Otherwise an {@link IllegalStateException} will be thrown.
+ */
+ void setDeviceEffectsApplier(DeviceEffectsApplier applier);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a62d8b8..e7ae610 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -251,6 +251,7 @@
import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
@@ -5406,6 +5407,7 @@
private void validateAutomaticZenRule(AutomaticZenRule rule) {
Objects.requireNonNull(rule, "automaticZenRule is null");
Objects.requireNonNull(rule.getName(), "Name is null");
+ rule.validate();
if (rule.getOwner() == null
&& rule.getConfigurationActivity() == null) {
throw new NullPointerException(
@@ -5463,6 +5465,7 @@
public void setAutomaticZenRuleState(String id, Condition condition) {
Objects.requireNonNull(id, "id is null");
Objects.requireNonNull(condition, "Condition is null");
+ condition.validate();
enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
@@ -6962,6 +6965,18 @@
}
}
}
+
+ @Override
+ public void setDeviceEffectsApplier(DeviceEffectsApplier applier) {
+ if (!android.app.Flags.modesApi()) {
+ return;
+ }
+ if (mZenModeHelper == null) {
+ throw new IllegalStateException("ZenModeHelper is not yet ready!");
+ }
+ // This can also throw IllegalStateException if called too late.
+ mZenModeHelper.setDeviceEffectsApplier(applier);
+ }
};
private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 7b35589..7f58e75e 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -837,13 +837,11 @@
}
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final SparseArray<int[]> broadcastAllowList = packageRemovedInfo.mBroadcastAllowList;
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_REPLACING, true);
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_ADDED, removedPackage, extras,
0, null /*targetPackage*/, null, null, null, broadcastAllowList, null);
@@ -888,8 +886,6 @@
boolean removedBySystem,
boolean isArchived) {
final String removedPackage = packageRemovedInfo.mRemovedPackage;
- final int removedAppId = packageRemovedInfo.mRemovedAppId;
- final int uid = packageRemovedInfo.mUid;
final String installerPackageName = packageRemovedInfo.mInstallerPackageName;
final int[] broadcastUserIds = packageRemovedInfo.mBroadcastUsers;
final int[] instantUserIds = packageRemovedInfo.mInstantUserIds;
@@ -902,8 +898,7 @@
final boolean isStaticSharedLib = packageRemovedInfo.mIsStaticSharedLib;
Bundle extras = new Bundle();
- final int removedUid = removedAppId >= 0 ? removedAppId : uid;
- extras.putInt(Intent.EXTRA_UID, removedUid);
+ extras.putInt(Intent.EXTRA_UID, packageRemovedInfo.mUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, isRemovedPackageSystemUpdate);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
@@ -940,10 +935,10 @@
sendPackageBroadcastAndNotify(Intent.ACTION_PACKAGE_FULLY_REMOVED,
removedPackage, extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, null,
null, broadcastUserIds, instantUserIds, broadcastAllowList, null);
- packageSender.notifyPackageRemoved(removedPackage, removedUid);
+ packageSender.notifyPackageRemoved(removedPackage, packageRemovedInfo.mUid);
}
}
- if (removedAppId >= 0) {
+ if (packageRemovedInfo.mIsAppIdRemoved) {
// If a system app's updates are uninstalled the UID is not actually removed. Some
// services need to know the package name affected.
if (isReplace) {
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 27f4e11..482807c 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -518,7 +518,9 @@
boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
throws PackageManager.NameNotFoundException;
- boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
+ /** Check if the package is suspending any package. */
+ boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
+ @UserIdInt int suspendingUserId, int targetUserId);
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index abfd571..3cb2420 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -96,6 +96,7 @@
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VersionedPackage;
import android.os.Binder;
import android.os.Build;
@@ -3864,19 +3865,15 @@
} finally {
Binder.restoreCallingIdentity(identity);
}
-
- var usingSharedLibraryPair =
- getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getAllCodePaths(),
libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), declaringPackage,
- usingSharedLibraryPair.first,
(libInfo.getDependencies() == null
? null
: new ArrayList<>(libInfo.getDependencies())),
- libInfo.isNative());
-
+ libInfo.isNative(),
+ getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId));
if (result == null) {
result = new ArrayList<>();
}
@@ -5012,11 +5009,13 @@
@Override
public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId, int targetUserId) {
+ final UserPackage suspender = UserPackage.of(suspendingUserId, suspendingPackage);
for (final PackageStateInternal packageState : getPackageStates().values()) {
- final PackageUserStateInternal state = packageState.getUserStateOrDefault(userId);
+ final PackageUserStateInternal state =
+ packageState.getUserStateOrDefault(targetUserId);
if (state.getSuspendParams() != null
- && state.getSuspendParams().containsKey(suspendingPackage)) {
+ && state.getSuspendParams().containsKey(suspender)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index dcf921c..aa7f0d3 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -510,7 +510,10 @@
}
if (clearPackageStateAndReturn) {
mRemovePackageHelper.clearPackageStateForUserLIF(ps, userId, flags);
- outInfo.mRemovedAppId = ps.getAppId();
+ // Legacy behavior to report appId as UID here.
+ // The final broadcasts will contain a per-user UID.
+ outInfo.mUid = ps.getAppId();
+ outInfo.mIsAppIdRemoved = true;
mPm.scheduleWritePackageRestrictions(user);
return;
}
@@ -555,6 +558,7 @@
boolean deleteCodeAndResources, int flags, @NonNull int[] allUserHandles,
@NonNull PackageRemovedInfo outInfo, boolean writeSettings) {
synchronized (mPm.mLock) {
+ // Since the package is being deleted in all users, report appId as the uid
outInfo.mUid = ps.getAppId();
outInfo.mBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
mPm.snapshotComputer(), ps, allUserHandles,
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 5c4447e..3b9f9c8 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -18,6 +18,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME;
import static com.android.server.pm.PackageManagerService.SCAN_AS_APK_IN_APEX;
@@ -30,7 +31,6 @@
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_APK_IN_APEX;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,12 +46,12 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfig;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 9b8ee74..0fa7aa5 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -154,12 +154,16 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.F2fsUtils;
+import com.android.internal.pm.parsing.PackageParserException;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,8 +185,6 @@
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedLibraryWrapper;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.FileIntegrityService;
import com.android.server.utils.WatchedArrayMap;
@@ -1165,7 +1167,7 @@
parseFlags);
archivedPackage = request.getPackageLite().getArchivedPackage();
}
- } catch (PackageManagerException e) {
+ } catch (PackageManagerException | PackageParserException e) {
throw new PrepareFailure("Failed parse during installPackageLI", e);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -2910,7 +2912,8 @@
info.mInstallerPackageName = request.getInstallerPackageName();
info.mRemovedUsers = firstUserIds;
info.mBroadcastUsers = firstUserIds;
- info.mRemovedAppId = request.getAppId();
+ info.mUid = request.getAppId();
+ info.mIsAppIdRemoved = true;
info.mRemovedPackageVersionCode = request.getPkg().getLongVersionCode();
info.mRemovedForAllUsers = true;
@@ -3856,7 +3859,7 @@
synchronized (mPm.mLock) {
platformPackage = mPm.getPlatformPackage();
- var isSystemApp = AndroidPackageUtils.isSystem(parsedPackage);
+ var isSystemApp = AndroidPackageLegacyUtils.isSystem(parsedPackage);
final String renamedPkgName = mPm.mSettings.getRenamedPackageLPr(
AndroidPackageUtils.getRealPackageOrNull(parsedPackage, isSystemApp));
realPkgName = ScanPackageUtils.getRealPackageName(parsedPackage, renamedPkgName,
@@ -4574,7 +4577,7 @@
private void assertPackageWithSharedUserIdIsPrivileged(AndroidPackage pkg)
throws PackageManagerException {
- if (!AndroidPackageUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
+ if (!AndroidPackageLegacyUtils.isPrivileged(pkg) && (pkg.getSharedUserId() != null)) {
SharedUserSetting sharedUserSetting = null;
try {
synchronized (mPm.mLock) {
@@ -4612,7 +4615,7 @@
final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0)
&& ScanPackageUtils.getVendorPartitionVersion() < 28;
if (((scanFlags & SCAN_AS_PRIVILEGED) == 0)
- && !AndroidPackageUtils.isPrivileged(pkg)
+ && !AndroidPackageLegacyUtils.isPrivileged(pkg)
&& (pkg.getSharedUserId() != null)
&& !skipVendorPrivilegeScan) {
SharedUserSetting sharedUserSetting = null;
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 5494bd9..ee780d9 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -51,12 +51,12 @@
import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.art.model.DexoptResult;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.util.ArrayList;
@@ -818,7 +818,8 @@
public void setRemovedAppId(int appId) {
if (mRemovedInfo != null) {
- mRemovedInfo.mRemovedAppId = appId;
+ mRemovedInfo.mUid = appId;
+ mRemovedInfo.mIsAppIdRemoved = true;
}
}
diff --git a/services/core/java/com/android/server/pm/KnownPackages.java b/services/core/java/com/android/server/pm/KnownPackages.java
index 154709a..83831ca 100644
--- a/services/core/java/com/android/server/pm/KnownPackages.java
+++ b/services/core/java/com/android/server/pm/KnownPackages.java
@@ -77,6 +77,8 @@
// Please note the numbers should be continuous.
public static final int LAST_KNOWN_PACKAGE = PACKAGE_WEARABLE_SENSING;
+ static final String SYSTEM_PACKAGE_NAME = "android";
+
private final DefaultAppProvider mDefaultAppProvider;
private final String mRequiredInstallerPackage;
private final String mRequiredUninstallerPackage;
@@ -186,7 +188,7 @@
case PACKAGE_SETUP_WIZARD:
return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
case PACKAGE_SYSTEM:
- return new String[]{"android"};
+ return new String[]{SYSTEM_PACKAGE_NAME};
case PACKAGE_VERIFIER:
return snapshot.filterOnlySystemPackages(mRequiredVerifierPackages);
case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ba66377..127bf49 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -822,7 +822,7 @@
return new LauncherActivityInfoInternal(
activityInfo,
new IncrementalStatesInfo(
- false /* isLoading */, 1 /* progress */, 0 /* loadingCompletedTime */),
+ false /* isLoading */, 0 /* progress */, 0 /* loadingCompletedTime */),
user);
}
@@ -1599,6 +1599,33 @@
}
@Override
+ public @Nullable IntentSender getAppMarketActivityIntent(@NonNull String callingPackage,
+ @Nullable String packageName, @NonNull UserHandle user) {
+ // Only system launchers, which have access to recents should have access to this API.
+ // TODO(b/303803157): Update access control for this API to default Launcher app.
+ if (!mActivityTaskManagerInternal.isCallerRecents(Binder.getCallingUid())) {
+ throw new SecurityException("Caller is not the recents app");
+ }
+ if (!canAccessProfile(user.getIdentifier(),
+ "Can't access AppMarketActivity for another user")) {
+ return null;
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // TODO(b/316118005): Add code to launch the app installer for the packageName.
+ Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
+ appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET);
+ final PendingIntent pi = PendingIntent.getActivityAsUser(
+ mContext, /* requestCode */ 0, appMarketIntent, PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+ /* options */ null, user);
+ return pi == null ? null : pi.getIntentSender();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, ComponentName component, Rect sourceBounds,
Bundle opts, UserHandle user) throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index 6b05edf..2864a8b 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -165,7 +165,7 @@
Computer snapshot = mPm.snapshotComputer();
int userId = userHandle.getIdentifier();
int binderUid = Binder.getCallingUid();
- if (!PackageManagerServiceUtils.isRootOrShell(binderUid)) {
+ if (!PackageManagerServiceUtils.isSystemOrRootOrShell(binderUid)) {
verifyCaller(snapshot.getPackageUid(callerPackageName, 0, userId), binderUid);
}
snapshot.enforceCrossUserPermission(binderUid, userId, true, true,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 7d6dd62..2942bbb 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -821,6 +821,18 @@
params.installFlags &= ~PackageManager.INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;
}
+ params.installFlags &= ~PackageManager.INSTALL_UNARCHIVE;
+ if (Flags.archiving() && params.appPackageName != null) {
+ PackageStateInternal ps = mPm.snapshotComputer().getPackageStateInternal(
+ params.appPackageName, SYSTEM_UID);
+ if (ps != null
+ && PackageArchiver.isArchived(ps.getUserStateOrDefault(userId))
+ && PackageArchiver.getResponsibleInstallerPackage(ps)
+ .equals(requestedInstallerPackageName)) {
+ params.installFlags |= PackageManager.INSTALL_UNARCHIVE;
+ }
+ }
+
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
&& !PackageManagerServiceUtils.isSystemOrRootOrShell(callingUid)
&& (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 47d1df5..4adb60c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -168,6 +168,7 @@
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.os.SomeArgs;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -181,7 +182,6 @@
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index c737b45..8da1683 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -19,6 +19,8 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -37,6 +39,7 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -250,7 +253,7 @@
getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
new String[]{packageName},
(suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
- suspendingPackage),
+ suspendingPackage.packageName),
userId);
}
@@ -269,7 +272,7 @@
@Override
@Deprecated
- public final String getSuspendingPackage(String suspendedPackage, int userId) {
+ public final UserPackage getSuspendingPackage(String suspendedPackage, int userId) {
return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
Binder.getCallingUid());
}
@@ -277,7 +280,7 @@
@Override
@Deprecated
public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId) {
+ UserPackage suspendingPackage, int userId) {
return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
suspendingPackage, userId, Binder.getCallingUid());
}
@@ -683,14 +686,16 @@
@Override
@Deprecated
- public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
- mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+ public final void unsuspendAdminSuspendedPackages(int affectedUser) {
+ final int suspendingUserId = affectedUser;
+ mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
}
@Override
@Deprecated
- public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+ public final boolean isAdminSuspendingAnyPackages(int userId) {
+ final int suspendingUserId = userId;
+ return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d369658..bc441b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -185,6 +185,7 @@
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
@@ -238,7 +239,6 @@
import com.android.server.pm.pkg.mutate.PackageStateMutator;
import com.android.server.pm.pkg.mutate.PackageStateWrite;
import com.android.server.pm.pkg.mutate.PackageUserStateWrite;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.resolution.ComponentResolver;
import com.android.server.pm.resolution.ComponentResolverApi;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
@@ -292,6 +292,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
+import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
@@ -2013,6 +2014,16 @@
public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
};
// CHECKSTYLE:ON IndentationCheck
@@ -3127,7 +3138,7 @@
}
private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
- boolean quarantined, String callingPackage, int callingUid, int userId,
+ boolean quarantined, UserPackage suspender, int callingUid, int targetUserId,
String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
@@ -3135,9 +3146,10 @@
return;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, targetUserId);
if (ownerUid == callingUid) {
return;
}
@@ -3158,25 +3170,27 @@
callingMethod);
}
- final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
+ final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
final boolean allowedPackageUid = packageUid == callingUid;
// TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
final boolean allowedShell = callingUid == SHELL_UID
&& UserHandle.isSameApp(packageUid, callingUid);
if (!allowedShell && !allowedPackageUid) {
- throw new SecurityException("Calling package " + callingPackage + " in user "
- + userId + " does not belong to calling uid " + callingUid);
+ throw new SecurityException("Suspending package " + suspender.packageName
+ + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
}
}
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
- @UserIdInt int userId) {
+ @UserIdInt int suspendingUserId) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
// this weird pre-collect of all packages.
final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
+ final Predicate<UserPackage> suspenderPredicate =
+ UserPackage.of(suspendingUserId, suspendingPackage)::equals;
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
- allPackages, suspendingPackage::equals, userId);
+ allPackages, suspenderPredicate, suspendingUserId);
}
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -5249,8 +5263,9 @@
if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
return null;
}
- return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
- callingUid);
+ final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage(
+ snapshot, packageName, userId, callingUid);
+ return suspender != null ? suspender.packageName : null;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -6188,7 +6203,8 @@
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
- SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId) {
+ SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
+ int suspendingUserId, int targetUserId) {
final int callingUid = Binder.getCallingUid();
boolean quarantined = false;
if (Flags.quarantinedEnabled()) {
@@ -6197,14 +6213,15 @@
} else if (FeatureFlagUtils.isEnabled(mContext,
SETTINGS_TREAT_PAUSE_AS_QUARANTINE)) {
final String wellbeingPkg = mContext.getString(R.string.config_systemWellbeing);
- quarantined = callingPackage.equals(wellbeingPkg);
+ quarantined = suspendingPackage.equals(wellbeingPkg);
}
}
final Computer snapshot = snapshotComputer();
- enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, callingPackage, callingUid,
- userId, "setPackagesSuspendedAsUser");
+ final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
+ enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
+ targetUserId, "setPackagesSuspendedAsUser");
return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
- appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid,
+ appExtras, launcherExtras, dialogInfo, suspender, targetUserId, callingUid,
quarantined);
}
@@ -6643,7 +6660,7 @@
final Computer computer = snapshotComputer();
final String[] allPackages = computer.getAllAvailablePackageNames();
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+ (suspender) -> !PLATFORM_PACKAGE_NAME.equals(suspender.packageName),
userId);
}
@@ -6657,8 +6674,13 @@
@Override
public String[] setPackagesSuspendedByAdmin(
@UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
- return mSuspendPackageHelper.setPackagesSuspendedByAdmin(
- snapshotComputer(), userId, packageNames, suspended);
+ final int suspendingUserId = userId;
+ final UserPackage suspender = UserPackage.of(
+ suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
+ return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
+ suspended, null /* appExtras */, null /* launcherExtras */,
+ null /* dialogInfo */, suspender, userId, Process.SYSTEM_UID,
+ false /* quarantined */);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 215e952..243fb16 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2827,7 +2827,7 @@
mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
suspendedState, ((appExtras.size() > 0) ? appExtras : null),
((launcherExtras.size() > 0) ? launcherExtras : null),
- info, flags, callingPackage, translatedUserId);
+ info, flags, callingPackage, UserHandle.USER_SYSTEM, translatedUserId);
for (int i = 0; i < packageNames.size(); i++) {
final String packageName = packageNames.get(i);
pw.println("Package " + packageName + " new suspended state: "
@@ -2872,16 +2872,16 @@
UserHandle.USER_NULL, "runGrantRevokePermission"));
List<PackageInfo> packageInfos;
+ PackageManager pm = mContext.createContextAsUser(translatedUser, 0).getPackageManager();
if (pkg == null) {
- packageInfos = mContext.getPackageManager().getInstalledPackages(
- PackageManager.GET_PERMISSIONS);
+ packageInfos = pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
} else {
try {
- packageInfos = Collections.singletonList(
- mContext.getPackageManager().getPackageInfo(pkg,
- PackageManager.GET_PERMISSIONS));
+ packageInfos = Collections.singletonList(pm.getPackageInfo(pkg,
+ PackageManager.GET_PERMISSIONS));
} catch (NameNotFoundException e) {
getErrPrintWriter().println("Error: package not found");
+ getOutPrintWriter().println("Failure [package not found]");
return 1;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index 7ee1772..881b0b3 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -25,7 +25,7 @@
String mRemovedPackage;
String mInstallerPackageName;
int mUid = -1;
- int mRemovedAppId = -1;
+ boolean mIsAppIdRemoved = false;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 7d0a1f6..28a90f3 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,6 +32,7 @@
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
@@ -952,7 +953,7 @@
void setUserState(int userId, long ceDataInode, long deDataInode, int enabled,
boolean installed, boolean stopped, boolean notLaunched, boolean hidden,
- int distractionFlags, ArrayMap<String, SuspendParams> suspendParams,
+ int distractionFlags, ArrayMap<UserPackage, SuspendParams> suspendParams,
boolean instantApp, boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason,
@@ -1182,7 +1183,7 @@
if (state.isSuspended()) {
for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
- state.getSuspendParams().keyAt(j));
+ state.getSuspendParams().keyAt(j).packageName);
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index bb0017c..b6de0e5 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -20,19 +20,23 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
+import static com.android.server.pm.PackageManagerService.SCAN_AS_APEX;
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
+import static com.android.server.pm.PackageManagerService.TAG;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
+import android.os.Build;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedLongSparseArray;
import java.util.ArrayList;
@@ -49,6 +53,8 @@
* as install) led to the request.
*/
final class ReconcilePackageUtils {
+ private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
+
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
Map<String, AndroidPackage> allPackages,
@@ -90,6 +96,8 @@
}
}
+ final AndroidPackage systemPackage = allPackages.get(KnownPackages.SYSTEM_PACKAGE_NAME);
+
for (InstallRequest installRequest : installRequests) {
final String installPackageName = installRequest.getParsedPackage().getPackageName();
final List<SharedLibraryInfo> allowedSharedLibInfos =
@@ -133,6 +141,9 @@
if (parsedPackage != null) {
signingDetails = parsedPackage.getSigningDetails();
}
+ final boolean isSystemPackage =
+ ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0);
+ final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0;
SharedUserSetting sharedUserSetting = settings.getSharedUserSettingLPr(
signatureCheckPs);
if (ksms.shouldCheckUpgradeKeySetLocked(
@@ -141,7 +152,7 @@
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
} else {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Package " + parsedPackage.getPackageName()
+ " upgrade keys do not match the previously installed"
@@ -168,9 +179,23 @@
removeAppKeySetData = true;
}
+ if (!isSystemPackage && !isApex && signingDetails != null
+ && systemPackage != null && systemPackage.getSigningDetails() != null
+ && systemPackage.getSigningDetails().checkCapability(
+ signingDetails,
+ SigningDetails.CertCapabilities.PERMISSION)) {
+ Slog.d(TAG, "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ if (!ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE) {
+ throw new ReconcileFailure(
+ INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ "Non-preload app associated with system signature: "
+ + signatureCheckPs.getPackageName());
+ }
+ }
+
// if this is is a sharedUser, check to see if the new package is signed by a
- // newer
- // signing certificate than the existing one, and if so, copy over the new
+ // newer signing certificate than the existing one, and if so, copy over the new
// details
if (sharedUserSetting != null) {
// Attempt to merge the existing lineage for the shared SigningDetails with
@@ -203,7 +228,7 @@
}
}
} catch (PackageManagerException e) {
- if ((parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) == 0) {
+ if (!isSystemPackage) {
throw new ReconcileFailure(e);
}
signingDetails = parsedPackage.getSigningDetails();
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 109d7ba..fefab3b 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -44,12 +44,12 @@
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.Installer.LegacyDexoptDisabledException;
import com.android.server.pm.parsing.PackageCacher;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -167,7 +167,7 @@
if (removedPackage != null) {
// TODO: Use PackageState for isSystem
cleanPackageDataStructuresLILPw(removedPackage,
- AndroidPackageUtils.isSystem(removedPackage), chatty);
+ AndroidPackageLegacyUtils.isSystem(removedPackage), chatty);
}
}
}
@@ -347,8 +347,7 @@
mPm.mAppsFilter.removePackage(snapshot,
snapshot.getPackageStateInternal(packageName));
removedAppId = mPm.mSettings.removePackageLPw(packageName);
- outInfo.mRemovedAppId = removedAppId;
-
+ outInfo.mIsAppIdRemoved = true;
if (!mPm.mSettings.isDisabledSystemPackageLPr(packageName)) {
// If we don't have a disabled system package to reinstall, the package is
// really gone and its permission state should be removed.
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 31a63e0..5c6d61e 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -74,11 +74,13 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProcess;
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -86,8 +88,6 @@
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateUtils;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArraySet;
import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 37cf30b..41e2a3f 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -22,8 +22,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
/** A package to be scanned */
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 75d88da..d6952262 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -51,6 +51,7 @@
import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
import android.net.Uri;
@@ -89,6 +90,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
@@ -106,7 +108,6 @@
import com.android.server.backup.PreferredActivityBackupHelper;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
@@ -1956,7 +1957,7 @@
ArchiveState archiveState = null;
int packageDepth = parser.getDepth();
- ArrayMap<String, SuspendParams> suspendParamsMap = null;
+ ArrayMap<UserPackage, SuspendParams> suspendParamsMap = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > packageDepth)) {
@@ -1983,18 +1984,15 @@
parser);
break;
case TAG_SUSPEND_PARAMS:
- final String suspendingPackage = parser.getAttributeValue(null,
- ATTR_SUSPENDING_PACKAGE);
- if (suspendingPackage == null) {
- Slog.wtf(TAG, "No suspendingPackage found inside tag "
- + TAG_SUSPEND_PARAMS);
+ Map.Entry<UserPackage, SuspendParams> entry =
+ readSuspensionParamsLPr(userId, parser);
+ if (entry == null) {
continue;
}
if (suspendParamsMap == null) {
suspendParamsMap = new ArrayMap<>();
}
- suspendParamsMap.put(suspendingPackage,
- SuspendParams.restoreFromXml(parser));
+ suspendParamsMap.put(entry.getKey(), entry.getValue());
break;
case TAG_ARCHIVE_STATE:
archiveState = parseArchiveState(parser);
@@ -2016,7 +2014,8 @@
oldSuspendedLauncherExtras,
false /* quarantined */);
suspendParamsMap = new ArrayMap<>();
- suspendParamsMap.put(oldSuspendingPackage, suspendParams);
+ suspendParamsMap.put(
+ UserPackage.of(userId, oldSuspendingPackage), suspendParams);
}
if (blockUninstall) {
@@ -2058,6 +2057,20 @@
}
}
+ @Nullable
+ private static Map.Entry<UserPackage, SuspendParams> readSuspensionParamsLPr(
+ int userId, TypedXmlPullParser parser) throws IOException {
+ final String suspendingPackage = parser.getAttributeValue(null, ATTR_SUSPENDING_PACKAGE);
+ if (suspendingPackage == null) {
+ Slog.wtf(TAG, "No suspendingPackage found inside tag " + TAG_SUSPEND_PARAMS);
+ return null;
+ }
+ final int suspendingUserId = userId;
+ return Map.entry(
+ UserPackage.of(suspendingUserId, suspendingPackage),
+ SuspendParams.restoreFromXml(parser));
+ }
+
private static ArchiveState parseArchiveState(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
String installerTitle = parser.getAttributeValue(null,
@@ -2414,10 +2427,11 @@
}
if (ustate.isSuspended()) {
for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
- final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
+ final UserPackage suspendingPackage =
+ ustate.getSuspendParams().keyAt(i);
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
- suspendingPackage);
+ suspendingPackage.packageName);
final SuspendParams params =
ustate.getSuspendParams().valueAt(i);
if (params != null) {
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index dddc6b0..5c0a15a 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -25,14 +25,14 @@
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedProcess;
+import com.android.internal.pm.pkg.component.ParsedProcessImpl;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProcessImpl;
import com.android.server.utils.SnapshotCache;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchedArraySet;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index b607502..7d87d1b 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -47,11 +47,11 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index c2a960a..4e70cc5 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -27,10 +27,10 @@
import android.app.AppOpsManager;
import android.content.Intent;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Bundle;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -88,8 +88,8 @@
* @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
* should be shown to the user when they try to launch a suspended app.
* Ignored if {@code suspended} is false.
- * @param callingPackage The caller's package name.
- * @param userId The user where packages reside.
+ * @param suspendingPackage The caller's package name.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of failed packages.
*/
@@ -97,14 +97,14 @@
String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
boolean suspended, @Nullable PersistableBundle appExtras,
@Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
- @NonNull String callingPackage, @UserIdInt int userId, int callingUid,
+ @NonNull UserPackage suspendingPackage, @UserIdInt int targetUserId, int callingUid,
boolean quarantined) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !quarantined && !isSuspendAllowedForUser(snapshot, userId,
- callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ if (suspended && !quarantined
+ && !isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
@@ -119,19 +119,21 @@
final IntArray changedUids = new IntArray(packageNames.length);
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid)
+ ? canSuspendPackageForUser(snapshot, packageNames, targetUserId, callingUid)
: null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
- if (callingPackage.equals(packageName)) {
- Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ if (suspendingPackage.packageName.equals(packageName)
+ && suspendingPackage.userId == targetUserId) {
+ Slog.w(TAG, "Suspending package: " + suspendingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unmodifiablePackages.add(packageName);
continue;
}
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
- if (packageState == null || !packageState.getUserStateOrDefault(userId).isInstalled()
- || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
+ if (packageState == null
+ || !packageState.getUserStateOrDefault(targetUserId).isInstalled()
+ || snapshot.shouldFilterApplication(packageState, callingUid, targetUserId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -142,34 +144,34 @@
continue;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
- packageState.getUserStateOrDefault(userId).getSuspendParams();
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
+ packageState.getUserStateOrDefault(targetUserId).getSuspendParams();
final SuspendParams oldSuspendParams = suspendParamsMap == null
- ? null : suspendParamsMap.get(callingPackage);
+ ? null : suspendParamsMap.get(suspendingPackage);
boolean changed = !Objects.equals(oldSuspendParams, newSuspendParams);
if (suspended && !changed) {
// Carried over API behavior, must notify change even if no change
notifyPackagesList.add(packageName);
notifyUids.add(
- UserHandle.getUid(userId, packageState.getAppId()));
+ UserHandle.getUid(targetUserId, packageState.getAppId()));
continue;
}
- // If only the callingPackage is suspending this package,
+ // If only the suspendingPackage is suspending this package,
// it will be unsuspended when this change is committed
boolean packageUnsuspended = !suspended
&& CollectionUtils.size(suspendParamsMap) == 1
- && suspendParamsMap.containsKey(callingPackage);
+ && suspendParamsMap.containsKey(suspendingPackage);
if (suspended || packageUnsuspended) {
// Always notify of a suspend call + notify when fully unsuspended
notifyPackagesList.add(packageName);
- notifyUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ notifyUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
if (changed) {
changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ changedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
} else {
Slog.w(TAG, "No change is needed for package: " + packageName
+ ". Skipping suspending/un-suspending.");
@@ -181,11 +183,11 @@
for (int index = 0; index < size; index++) {
final String packageName = changedPackagesList.valueAt(index);
final PackageUserStateWrite userState = mutator.forPackage(packageName)
- .userState(userId);
+ .userState(targetUserId);
if (suspended) {
- userState.putSuspendParams(callingPackage, newSuspendParams);
+ userState.putSuspendParams(suspendingPackage, newSuspendParams);
} else {
- userState.removeSuspension(callingPackage);
+ userState.removeSuspension(suspendingPackage);
}
}
});
@@ -197,17 +199,17 @@
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
- changedPackages, notifyUids.toArray(), quarantined, userId);
+ changedPackages, notifyUids.toArray(), quarantined, targetUserId);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages,
- suspended, userId);
- mPm.scheduleWritePackageRestrictions(userId);
+ suspended, targetUserId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!changedPackagesList.isEmpty()) {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined,
- userId);
+ targetUserId);
}
return unmodifiablePackages.toArray(new String[0]);
}
@@ -216,19 +218,19 @@
* Returns the names in the {@code packageNames} which can not be suspended by the caller.
*
* @param packageNames The names of packages to check.
- * @param userId The user where packages reside.
+ * @param targetUserId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of packages which are Unsuspendable.
*/
@NonNull
String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
- @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
- if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
+ @NonNull String[] packageNames, @UserIdInt int targetUserId, int callingUid) {
+ if (!isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, targetUserId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -237,7 +239,7 @@
}
final PackageStateInternal packageState =
snapshot.getPackageStateForInstalledAndFiltered(
- packageNames[i], callingUid, userId);
+ packageNames[i], callingUid, targetUserId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -285,30 +287,31 @@
* @param packagesToChange The packages on which the suspension are to be removed.
* @param suspendingPackagePredicate A predicate identifying the suspending packages whose
* suspensions will be removed.
- * @param userId The user for which the changes are taking place.
+ * @param targetUserId The user for which the changes are taking place.
*/
void removeSuspensionsBySuspendingPackage(@NonNull Computer snapshot,
@NonNull String[] packagesToChange,
- @NonNull Predicate<String> suspendingPackagePredicate, int userId) {
+ @NonNull Predicate<UserPackage> suspendingPackagePredicate, int targetUserId) {
final List<String> unsuspendedPackages = new ArrayList<>();
final IntArray unsuspendedUids = new IntArray();
- final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>();
+ final ArrayMap<String, ArraySet<UserPackage>> pkgToSuspendingPkgsToCommit =
+ new ArrayMap<>();
for (String packageName : packagesToChange) {
final PackageStateInternal packageState =
snapshot.getPackageStateInternal(packageName);
final PackageUserStateInternal packageUserState = packageState == null
- ? null : packageState.getUserStateOrDefault(userId);
+ ? null : packageState.getUserStateOrDefault(targetUserId);
if (packageUserState == null || !packageUserState.isSuspended()) {
continue;
}
- WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
packageUserState.getSuspendParams();
int countRemoved = 0;
for (int index = 0; index < suspendParamsMap.size(); index++) {
- String suspendingPackage = suspendParamsMap.keyAt(index);
+ UserPackage suspendingPackage = suspendParamsMap.keyAt(index);
if (suspendingPackagePredicate.test(suspendingPackage)) {
- ArraySet<String> suspendingPkgsToCommit =
+ ArraySet<UserPackage> suspendingPkgsToCommit =
pkgToSuspendingPkgsToCommit.get(packageName);
if (suspendingPkgsToCommit == null) {
suspendingPkgsToCommit = new ArraySet<>();
@@ -322,31 +325,33 @@
// Everything would be removed and package unsuspended
if (countRemoved == suspendParamsMap.size()) {
unsuspendedPackages.add(packageState.getPackageName());
- unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
+ unsuspendedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
}
}
mPm.commitPackageStateMutation(null, mutator -> {
for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) {
String packageName = pkgToSuspendingPkgsToCommit.keyAt(mapIndex);
- ArraySet<String> packagesToRemove = pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
- PackageUserStateWrite userState = mutator.forPackage(packageName).userState(userId);
+ ArraySet<UserPackage> packagesToRemove =
+ pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
+ PackageUserStateWrite userState =
+ mutator.forPackage(packageName).userState(targetUserId);
for (int setIndex = 0; setIndex < packagesToRemove.size(); setIndex++) {
userState.removeSuspension(packagesToRemove.valueAt(setIndex));
}
}
});
- mPm.scheduleWritePackageRestrictions(userId);
+ mPm.scheduleWritePackageRestrictions(targetUserId);
final Computer newSnapshot = mPm.snapshotComputer();
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray,
- false, userId);
+ false, targetUserId);
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_UNSUSPENDED,
- packageArray, unsuspendedUids.toArray(), false, userId);
+ packageArray, unsuspendedUids.toArray(), false, targetUserId);
}
}
@@ -404,7 +409,7 @@
* @return The name of suspending package.
*/
@Nullable
- String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ UserPackage getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
int userId, int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -417,13 +422,13 @@
return null;
}
- String suspendingPackage = null;
- String suspendedBySystem = null;
- String qasPackage = null;
+ UserPackage suspendingPackage = null;
+ UserPackage suspendedBySystem = null;
+ UserPackage qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
var suspendParams = userState.getSuspendParams().valueAt(i);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
suspendedBySystem = suspendingPackage;
}
if (suspendParams.isQuarantined() && qasPackage == null) {
@@ -451,7 +456,7 @@
*/
@Nullable
SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
- @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+ @NonNull String suspendedPackage, @NonNull UserPackage suspendingPackage, int userId,
int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -464,7 +469,7 @@
return null;
}
- final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
userState.getSuspendParams();
if (suspendParamsMap == null) {
return null;
@@ -493,34 +498,36 @@
* be suspended or not.
*
* @param packageNames The package names to check suspendability for.
- * @param userId The user to check in
+ * @param targetUserId The user to check in
* @param callingUid The caller's uid.
* @return An array containing results of the checks
*/
@NonNull
boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
- int userId, int callingUid) {
+ int targetUserId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
+ final boolean isCallerOwner =
+ isCallerDeviceOrProfileOwner(snapshot, targetUserId, callingUid);
final long token = Binder.clearCallingIdentity();
try {
final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
- final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
- final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
+ final String activeLauncherPackageName =
+ defaultAppProvider.getDefaultHome(targetUserId);
+ final String dialerPackageName = defaultAppProvider.getDefaultDialer(targetUserId);
final String requiredInstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, targetUserId);
final String requiredUninstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, targetUserId);
final String requiredVerifierPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, targetUserId);
final String requiredPermissionControllerPackage =
getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
- userId);
+ targetUserId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
- if (mPm.isPackageDeviceAdmin(packageName, userId)) {
+ if (mPm.isPackageDeviceAdmin(packageName, targetUserId)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": has an active device admin");
continue;
@@ -555,12 +562,12 @@
+ "\": required for permissions management");
continue;
}
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ if (mProtectedPackages.isPackageStateProtected(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": protected package");
continue;
}
- if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(targetUserId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -572,7 +579,7 @@
PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
- final int uid = UserHandle.getUid(userId, packageState.getAppId());
+ final int uid = UserHandle.getUid(targetUserId, packageState.getAppId());
// Cannot suspend SDK libs as they are controlled by SDK manager.
if (pkg.isSdkLibrary()) {
Slog.w(TAG, "Cannot suspend package: " + packageName
@@ -614,20 +621,6 @@
== AppOpsManager.MODE_ALLOWED;
}
- /**
- * Suspends packages on behalf of an admin.
- *
- * @return array of packages that are unsuspendable, either because admin is not allowed to
- * suspend them (e.g. current dialer) or there was other problem (e.g. package not found).
- */
- public String[] setPackagesSuspendedByAdmin(
- Computer snapshot, int userId, String[] packageNames, boolean suspend) {
- return setPackagesSuspended(snapshot, packageNames, suspend,
- null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
- PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
- false /* quarantined */);
- }
-
private String getKnownPackageName(@NonNull Computer snapshot,
@KnownPackages.KnownPackage int knownPackage, int userId) {
final String[] knownPackages =
@@ -635,14 +628,15 @@
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int targetUserId,
int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
- final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
+ final String ownerPackage =
+ mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
if (ownerPackage != null) {
- return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, targetUserId,
callingUid);
}
return false;
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 7386301..14db70e 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -306,7 +306,6 @@
.setDarkThemeBadgeColors(
R.color.white)
.setDefaultRestrictions(getDefaultProfileRestrictions())
- .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
.setDefaultUserProperties(new UserProperties.Builder()
.setStartWithParent(true)
.setCredentialShareableWithParent(true)
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 459e2cf..79c9c8e 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -28,9 +28,9 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.ApexManager;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import libcore.io.IoUtils;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index b23dbee..d0fe964 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -28,6 +28,7 @@
import android.content.pm.FallbackCategoryProvider;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
@@ -52,6 +53,9 @@
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedAttribution;
import com.android.internal.pm.pkg.component.ParsedComponent;
@@ -63,11 +67,12 @@
import com.android.internal.pm.pkg.component.ParsedProvider;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
import com.android.server.pm.PackageArchiver;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUnserialized;
@@ -75,9 +80,6 @@
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SELinuxUtil;
-import com.android.server.pm.pkg.component.ComponentParseUtils;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.ArrayList;
@@ -273,8 +275,8 @@
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final ParsedActivity a = pkg.getActivities().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- aflags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), aflags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
a.getName())) {
continue;
@@ -293,8 +295,8 @@
final ActivityInfo[] res = new ActivityInfo[size];
for (int i = 0; i < size; i++) {
final ParsedActivity a = pkg.getReceivers().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), a,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ a.isEnabled(), a.isDirectBootAware(), a.getName(), flags)) {
res[num++] = generateActivityInfo(pkg, a, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -309,8 +311,8 @@
final ServiceInfo[] res = new ServiceInfo[size];
for (int i = 0; i < size; i++) {
final ParsedService s = pkg.getServices().get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), s,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ s.isEnabled(), s.isDirectBootAware(), s.getName(), flags)) {
res[num++] = generateServiceInfo(pkg, s, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -326,8 +328,8 @@
for (int i = 0; i < size; i++) {
final ParsedProvider pr = pkg.getProviders()
.get(i);
- if (ComponentParseUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(), pr,
- flags)) {
+ if (PackageUserStateUtils.isMatch(state, pkgSetting.isSystem(), pkg.isEnabled(),
+ pr.isEnabled(), pr.isDirectBootAware(), pr.getName(), flags)) {
res[num++] = generateProviderInfo(pkg, pr, flags, state, applicationInfo,
userId, pkgSetting);
}
@@ -473,7 +475,34 @@
}
info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
? null : usesLibraryFiles.toArray(new String[0]);
- info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+
+
+ if (!Flags.sdkLibIndependence()) {
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ info.optionalSharedLibraryInfos = null;
+ } else {
+ // sharedLibraryInfos contains all shared libraries that the app depends on (including
+ // the optional sdk libraries)
+ info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
+ String[] libsNames = pkgSetting.getUsesSdkLibraries();
+ boolean[] libsOptional = pkgSetting.getUsesSdkLibrariesOptional();
+ List<SharedLibraryInfo> optionalSdkLibraries = null;
+ if (!ArrayUtils.isEmpty(libsOptional) && !ArrayUtils.isEmpty(libsNames)
+ && libsNames.length == libsOptional.length) {
+ for (SharedLibraryInfo info1 : usesLibraryInfos) {
+ if (info1.getType() == SharedLibraryInfo.TYPE_SDK_PACKAGE) {
+ int index = ArrayUtils.indexOf(libsNames, info1.getName());
+ if (index >= 0 && libsOptional[index]) {
+ if (optionalSdkLibraries == null) {
+ optionalSdkLibraries = new ArrayList<>();
+ }
+ optionalSdkLibraries.add(info1);
+ }
+ }
+ }
+ }
+ info.optionalSharedLibraryInfos = optionalSdkLibraries;
+ }
if (info.category == ApplicationInfo.CATEGORY_UNDEFINED) {
info.category = pkgSetting.getCategoryOverride();
}
@@ -923,7 +952,7 @@
| flag(pkg.isExtraLargeScreensSupported(), ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS)
| flag(pkg.isResizeable(), ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS)
| flag(pkg.isAnyDensity(), ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
- | flag(AndroidPackageUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
+ | flag(AndroidPackageLegacyUtils.isSystem(pkg), ApplicationInfo.FLAG_SYSTEM)
| flag(pkg.isFactoryTest(), ApplicationInfo.FLAG_FACTORY_TEST);
return appInfoFlags(pkgWithoutStateFlags, pkgSetting);
@@ -964,12 +993,12 @@
| flag(pkg.isSaveStateDisallowed(), ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
| flag(pkg.isResizeableActivityViaSdkVersion(), ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
| flag(pkg.isAllowNativeHeapPointerTagging(), ApplicationInfo.PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING)
- | flag(AndroidPackageUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
- | flag(AndroidPackageUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
- | flag(AndroidPackageUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
- | flag(AndroidPackageUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
- | flag(AndroidPackageUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
- | flag(AndroidPackageUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
+ | flag(AndroidPackageLegacyUtils.isSystemExt(pkg), ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT)
+ | flag(AndroidPackageLegacyUtils.isPrivileged(pkg), ApplicationInfo.PRIVATE_FLAG_PRIVILEGED)
+ | flag(AndroidPackageLegacyUtils.isOem(pkg), ApplicationInfo.PRIVATE_FLAG_OEM)
+ | flag(AndroidPackageLegacyUtils.isVendor(pkg), ApplicationInfo.PRIVATE_FLAG_VENDOR)
+ | flag(AndroidPackageLegacyUtils.isProduct(pkg), ApplicationInfo.PRIVATE_FLAG_PRODUCT)
+ | flag(AndroidPackageLegacyUtils.isOdm(pkg), ApplicationInfo.PRIVATE_FLAG_ODM)
| flag(pkg.isSignedWithPlatformKey(), ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY);
Boolean resizeableActivity = pkg.getResizeableActivity();
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 1c751e0..b6a08a5 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -35,17 +35,19 @@
import android.util.Slog;
import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
import com.android.internal.util.ArrayUtils;
+import com.android.server.SystemConfig;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.io.File;
import java.util.List;
+import java.util.Set;
/**
* The v2 of package parsing for use when parsing is initiated in the server and must
@@ -88,6 +90,16 @@
// behavior.
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
});
}
@@ -221,7 +233,7 @@
@NonNull String baseCodePath, @NonNull String codePath,
@NonNull TypedArray manifestArray, boolean isCoreApp) {
return PackageImpl.forParsing(packageName, baseCodePath, codePath, manifestArray,
- isCoreApp);
+ isCoreApp, Callback.this);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 61be6e1..1b7c7ad 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -29,7 +29,9 @@
import android.os.incremental.IncrementalManager;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.pm.parsing.PackageParserException;
import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
import com.android.internal.pm.pkg.component.ParsedProvider;
@@ -37,7 +39,6 @@
import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemConfig;
-import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
@@ -134,10 +135,10 @@
/**
* Validate the dex metadata files installed for the given package.
*
- * @throws PackageManagerException in case of errors.
+ * @throws PackageParserException in case of errors.
*/
public static void validatePackageDexMetadata(AndroidPackage pkg)
- throws PackageManagerException {
+ throws PackageParserException {
Collection<String> apkToDexMetadataList = getPackageDexMetadata(pkg).values();
String packageName = pkg.getPackageName();
long versionCode = pkg.getLongVersionCode();
@@ -146,7 +147,7 @@
final ParseResult result = DexMetadataHelper.validateDexMetadataFile(
input.reset(), dexMetadata, packageName, versionCode);
if (result.isError()) {
- throw new PackageManagerException(
+ throw new PackageParserException(
result.getErrorCode(), result.getErrorMessage(), result.getException());
}
}
@@ -314,60 +315,4 @@
info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
}
-
- /**
- * @deprecated Use {@link PackageState#isSystem}
- */
- @Deprecated
- public static boolean isSystem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isSystemExt}
- */
- @Deprecated
- public static boolean isSystemExt(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isSystemExt();
- }
-
- /**
- * @deprecated Use {@link PackageState#isPrivileged}
- */
- @Deprecated
- public static boolean isPrivileged(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isPrivileged();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOem}
- */
- @Deprecated
- public static boolean isOem(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOem();
- }
-
- /**
- * @deprecated Use {@link PackageState#isVendor}
- */
- @Deprecated
- public static boolean isVendor(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isVendor();
- }
-
- /**
- * @deprecated Use {@link PackageState#isProduct}
- */
- @Deprecated
- public static boolean isProduct(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isProduct();
- }
-
- /**
- * @deprecated Use {@link PackageState#isOdm}
- */
- @Deprecated
- public static boolean isOdm(@NonNull AndroidPackage pkg) {
- return ((AndroidPackageHidden) pkg).isOdm();
- }
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 8bd2d94..671e031 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -120,8 +120,11 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.RoSystemProperties;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.IntPair;
@@ -144,8 +147,6 @@
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.SoftRestrictedPermissionPolicy;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 2f4ad2d8..15b693c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
import android.util.Pair;
@@ -173,7 +174,7 @@
@Nullable
@Override
- public WatchedArrayMap<String, SuspendParams> getSuspendParams() {
+ public WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams() {
return null;
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index c5ef525..7a5a14d 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -121,7 +122,7 @@
* Suspending package to suspend params
*/
@Nullable
- private WatchedArrayMap<String, SuspendParams> mSuspendParams;
+ private WatchedArrayMap<UserPackage, SuspendParams> mSuspendParams;
@Nullable
private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
@@ -369,7 +370,10 @@
return !CollectionUtils.isEmpty(mSuspendParams);
}
- public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
+ /**
+ * Adds or updates suspension params by the given package.
+ */
+ public PackageUserStateImpl putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mSuspendParams == null) {
mSuspendParams = new WatchedArrayMap<>();
@@ -384,7 +388,10 @@
return this;
}
- public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
+ /**
+ * Removes suspension by the given package.
+ */
+ public PackageUserStateImpl removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mSuspendParams != null) {
mSuspendParams.remove(suspendingPackage);
onChanged();
@@ -565,7 +572,7 @@
* Suspending package to suspend params
*/
public @NonNull PackageUserStateImpl setSuspendParams(
- @NonNull ArrayMap<String, SuspendParams> value) {
+ @NonNull ArrayMap<UserPackage, SuspendParams> value) {
if (value == null) {
return this;
}
@@ -778,7 +785,7 @@
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @Nullable WatchedArrayMap<String,SuspendParams> getSuspendParams() {
+ public @Nullable WatchedArrayMap<UserPackage,SuspendParams> getSuspendParams() {
return mSuspendParams;
}
@@ -830,7 +837,7 @@
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<String,SuspendParams> value) {
+ public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<UserPackage,SuspendParams> value) {
mSuspendParams = value;
return this;
}
@@ -909,10 +916,10 @@
}
@DataClass.Generated(
- time = 1701470095849L,
+ time = 1701864813354L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(android.content.pm.UserPackage)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index 46cc830..f8d745c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.pm.UserPackage;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.util.Pair;
@@ -38,7 +39,7 @@
// TODO: Make non-null with emptyMap()
@Nullable
- WatchedArrayMap<String, SuspendParams> getSuspendParams();
+ WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams();
@Nullable
WatchedArraySet<String> getDisabledComponentsNoCopy();
diff --git a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
index 6cbc1de..6a15641 100644
--- a/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
+++ b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
@@ -16,6 +16,8 @@
package com.android.server.pm.pkg;
+import com.android.internal.pm.pkg.SEInfoUtil;
+
/**
* Utility methods that need to be used in application space.
* @hide
@@ -23,10 +25,10 @@
public final class SELinuxUtil {
/** Append to existing seinfo label for instant apps @hide */
- private static final String INSTANT_APP_STR = ":ephemeralapp";
+ private static final String INSTANT_APP_STR = SEInfoUtil.INSTANT_APP_STR;
/** Append to existing seinfo when modifications are complete @hide */
- public static final String COMPLETE_STR = ":complete";
+ public static final String COMPLETE_STR = SEInfoUtil.COMPLETE_STR;
/** @hide */
public static String getSeinfoUser(PackageUserState userState) {
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 8430cf7..253eb40 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -21,6 +21,7 @@
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
@@ -349,7 +350,7 @@
@NonNull
@Override
- public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ public PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mUserState != null) {
mUserState.putSuspendParams(suspendingPackage, suspendParams);
@@ -359,7 +360,7 @@
@NonNull
@Override
- public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
+ public PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage) {
if (mUserState != null) {
mUserState.removeSuspension(suspendingPackage);
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
index 0c6c672..f6b2104 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -38,11 +39,11 @@
@PackageManager.DistractionRestriction int restrictionFlags);
@NonNull
- PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
+ PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
@Nullable SuspendParams suspendParams);
@NonNull
- PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
+ PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage);
@NonNull
PackageUserStateWrite setHidden(boolean hidden);
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 532a7f8..c9da99d 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -45,11 +45,13 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.pm.pkg.component.ComponentMutateUtils;
import com.android.internal.pm.pkg.component.ParsedActivity;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
import com.android.internal.util.ArrayUtils;
import com.android.server.IntentResolver;
@@ -62,8 +64,6 @@
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ComponentMutateUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
import com.android.server.pm.snapshot.PackageDataSnapshot;
import com.android.server.utils.Snappable;
import com.android.server.utils.SnapshotCache;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 6f27507..d903ad4 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -41,7 +41,6 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -2081,6 +2080,45 @@
}
@Override
+ public void stopPlayback(IBinder sessionToken, int mode, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).stopPlayback(
+ mode);
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in stopPlayback(mode)", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void startPlayback(IBinder sessionToken, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+ userId, "stopPlayback");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ try {
+ getSessionLocked(sessionToken, callingUid, resolvedUserId).startPlayback();
+ } catch (RemoteException | SessionNotFoundException e) {
+ Slog.e(TAG, "error in startPlayback()", e);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void timeShiftPlay(IBinder sessionToken, final Uri recordedProgramUri, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index f9d344b..1b45c1b 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -48,6 +48,7 @@
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -335,19 +336,19 @@
return false;
}
final String suspendedPackage = mAInfo.applicationInfo.packageName;
- final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+ final UserPackage suspender = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+ if (suspender != null && PLATFORM_PACKAGE_NAME.equals(suspender.packageName)) {
return interceptSuspendedByAdminPackage();
}
final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
- suspendingPackage, mUserId);
+ suspender, mUserId);
final Bundle crossProfileOptions = hasCrossProfileAnimation()
? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
: null;
final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_IMMUTABLE);
mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
- suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
+ suspender, dialogInfo, crossProfileOptions, target, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 4a3d0c1..32d60c5 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static com.android.input.flags.Flags.enablePointerChoreographer;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -23,6 +24,7 @@
import android.annotation.NonNull;
import android.content.ClipData;
import android.content.Context;
+import android.hardware.input.InputManagerGlobal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -31,6 +33,8 @@
import android.util.Slog;
import android.view.Display;
import android.view.IWindow;
+import android.view.InputDevice;
+import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
@@ -97,8 +101,8 @@
}
IBinder performDrag(int callerPid, int callerUid, IWindow window, int flags,
- SurfaceControl surface, int touchSource, float touchX, float touchY,
- float thumbCenterX, float thumbCenterY, ClipData data) {
+ SurfaceControl surface, int touchSource, int touchDeviceId, int touchPointerId,
+ float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
if (DEBUG_DRAG) {
Slog.d(TAG_WM, "perform drag: win=" + window + " surface=" + surface + " flags=" +
Integer.toHexString(flags) + " data=" + data + " touch(" + touchX + ","
@@ -208,7 +212,17 @@
final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
mDragState.broadcastDragStartedLocked(touchX, touchY);
- mDragState.overridePointerIconLocked(touchSource);
+ if (enablePointerChoreographer()) {
+ if ((touchSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
+ InputManagerGlobal.getInstance().setPointerIcon(
+ PointerIcon.getSystemIcon(
+ mService.mContext, PointerIcon.TYPE_GRABBING),
+ mDragState.mDisplayContent.getDisplayId(), touchDeviceId,
+ touchPointerId, mDragState.getInputToken());
+ }
+ } else {
+ mDragState.overridePointerIconLocked(touchSource);
+ }
// remember the thumb offsets for later
mDragState.mThumbOffsetX = thumbCenterX;
mDragState.mThumbOffsetY = thumbCenterY;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index a888f84..adbe3bc 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -416,6 +416,13 @@
return mInputInterceptor == null ? null : mInputInterceptor.mDragWindowHandle;
}
+ IBinder getInputToken() {
+ if (mInputInterceptor == null || mInputInterceptor.mClientChannel == null) {
+ return null;
+ }
+ return mInputInterceptor.mClientChannel.getToken();
+ }
+
/**
* @param display The Display that the window being dragged is on.
*/
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 0d15fc9..2b841fd 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH;
import static com.android.internal.R.bool.config_unfoldTransitionEnabled;
import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
@@ -110,15 +111,6 @@
return;
}
- final TransitionRequestInfo.DisplayChange displayChange =
- new TransitionRequestInfo.DisplayChange(displayId);
-
- final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
- displayChange.setStartAbsBounds(startAbsBounds);
- final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
- displayChange.setEndAbsBounds(endAbsBounds);
- displayChange.setPhysicalDisplayChanged(true);
-
mTransition = null;
if (mTransitionController.isCollecting()) {
@@ -128,10 +120,20 @@
// Make sure that transition is not ready until we finish the remote display change
mTransition.setReady(mDisplayContent, false);
+ mTransition.addFlag(TRANSIT_FLAG_PHYSICAL_DISPLAY_SWITCH);
ProtoLog.d(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Adding display switch to existing collecting transition");
} else {
+ final TransitionRequestInfo.DisplayChange displayChange =
+ new TransitionRequestInfo.DisplayChange(displayId);
+
+ final Rect startAbsBounds = new Rect(0, 0, oldDisplayWidth, oldDisplayHeight);
+ displayChange.setStartAbsBounds(startAbsBounds);
+ final Rect endAbsBounds = new Rect(0, 0, newDisplayWidth, newDisplayHeight);
+ displayChange.setEndAbsBounds(endAbsBounds);
+ displayChange.setPhysicalDisplayChanged(true);
+
mTransition = mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE,
0 /* flags */,
mDisplayContent, mDisplayContent, null /* remoteTransition */,
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 56f9aa4..57939bc 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -340,7 +340,8 @@
@Override
public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
- float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
+ int touchDeviceId, int touchPointerId, float touchX, float touchY, float thumbCenterX,
+ float thumbCenterY, ClipData data) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
// Validate and resolve ClipDescription data before clearing the calling identity
@@ -349,7 +350,8 @@
final long ident = Binder.clearCallingIdentity();
try {
return mDragDropController.performDrag(mPid, mUid, window, flags, surface, touchSource,
- touchX, touchY, thumbCenterX, thumbCenterY, data);
+ touchDeviceId, touchPointerId, touchX, touchY, thumbCenterX, thumbCenterY,
+ data);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index d66b9b9..2a0f1e2 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -468,7 +468,6 @@
borrowed_fd incomingFd, bool waitOnEof, std::vector<char>* buffer,
std::vector<IncFsDataBlock>* blocks) {
IncFsSize remaining = size;
- IncFsSize totalSize = 0;
IncFsBlockIndex blockIdx = 0;
while (remaining > 0) {
constexpr auto capacity = BUFFER_SIZE;
@@ -502,7 +501,6 @@
buffer->resize(size + read);
remaining -= read;
- totalSize += read;
}
if (!buffer->empty() && !flashToIncFs(incfsFd, kind, true, &blockIdx, buffer, blocks)) {
return false;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e0a2f30..a490013 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2469,7 +2469,7 @@
private void migratePersonalAppSuspensionLocked(
int doUserId, int poUserId, ActiveAdmin poAdmin) {
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
- if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
+ if (!pmi.isAdminSuspendingAnyPackages(doUserId)) {
Slogf.i(LOG_TAG, "DO is not suspending any apps.");
return;
}
@@ -2480,7 +2480,7 @@
poAdmin.mSuspendPersonalApps = true;
} else {
Slogf.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
- pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
+ pmi.unsuspendAdminSuspendedPackages(doUserId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 6570ce1..506dbe8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -16,8 +16,6 @@
package com.android.server.devicepolicy;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
@@ -287,7 +285,7 @@
suspendPersonalAppsInPackageManager(context, userId);
} else {
LocalServices.getService(PackageManagerInternal.class)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId);
+ .unsuspendAdminSuspendedPackages(userId);
}
});
return true;
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index 02032c7..f69f628 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -24,6 +24,7 @@
import android.os.Build
import android.util.Slog
import com.android.internal.os.RoSystemProperties
+import com.android.internal.pm.permission.CompatibilityPermissionInfo
import com.android.modules.utils.BinaryXmlPullParser
import com.android.modules.utils.BinaryXmlSerializer
import com.android.server.permission.access.AccessState
@@ -42,7 +43,6 @@
import com.android.server.permission.access.util.isInternal
import com.android.server.pm.KnownPackages
import com.android.server.pm.parsing.PackageInfoUtils
-import com.android.server.pm.permission.CompatibilityPermissionInfo
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index d62da1a..5b222c0 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -57,11 +57,11 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowUserManager;
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 3011fa1..5c4716d 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -25,6 +25,7 @@
import android.os.UserHandle
import android.util.ArrayMap
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.component.ParsedActivity
import com.android.server.pm.AppsFilterImpl
@@ -38,7 +39,6 @@
import com.android.server.pm.SharedLibrariesImpl
import com.android.server.pm.UserManagerInternal
import com.android.server.pm.UserManagerService
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
@@ -49,6 +49,8 @@
import com.android.server.testutils.whenever
import com.android.server.wm.ActivityTaskManagerInternal
import com.google.common.truth.Truth.assertThat
+import java.io.File
+import java.util.UUID
import org.junit.After
import org.junit.Before
import org.junit.BeforeClass
@@ -61,8 +63,6 @@
import org.mockito.Mockito.intThat
import org.mockito.Mockito.same
import org.testng.Assert.assertThrows
-import java.io.File
-import java.util.UUID
@RunWith(Parameterized::class)
class PackageManagerComponentLabelIconOverrideTest {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
index 3461bb6..7277fd7 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/AppsFilterImplTest.java
@@ -49,20 +49,20 @@
import androidx.annotation.NonNull;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
+import com.android.internal.pm.pkg.component.ParsedComponentImpl;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.om.OverlayReferenceMapper;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedComponentImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.utils.WatchableTester;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
index f0d389b..b1c3e94 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/CompatibilityModeTest.java
@@ -32,11 +32,11 @@
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageStateUnserialized;
import com.android.server.pm.pkg.PackageUserStateImpl;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.After;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index f07e820..40d3d5c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -45,15 +45,19 @@
import android.app.PropertyInvalidatedCache;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.BaseBundle;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -63,10 +67,11 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
-import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.ArchiveState;
@@ -85,6 +90,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -109,6 +115,9 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PackageManagerSettingsTests {
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String PACKAGE_NAME_1 = "com.android.app1";
private static final String PACKAGE_NAME_2 = "com.android.app2";
private static final String PACKAGE_NAME_3 = "com.android.app3";
@@ -140,6 +149,7 @@
public void setup() {
// Disable binder caches in this process.
PropertyInvalidatedCache.disableForTestMode();
+
}
@Before
@@ -161,6 +171,107 @@
deleteFolder(InstrumentationRegistry.getContext().getFilesDir());
}
+ @Test
+ public void testApplicationInfoForUseSdkOptionalEnabled() throws Exception {
+ mSetFlagsRule.enableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path11",
+ "packageName11",
+ Collections.emptyList(),
+ "com.example.sdk.oneone",
+ 1212 /*version*/,
+ SharedLibraryInfo.TYPE_STATIC,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, notNullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ assertEquals(appInfo1.optionalSharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+
+ final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+ ps2.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_2).hideAsParsed())
+ .setUid(ps2.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps2.setUsesSdkLibraries(new String[] { "com.example.sdk.two" });
+ ps2.setUsesSdkLibrariesVersionsMajor(new long[] { 34 });
+ ps2.setUsesSdkLibrariesOptional(new boolean[] {false});
+ ps2.addUsesLibraryInfo(new SharedLibraryInfo("path2",
+ "packageName2",
+ Collections.emptyList(),
+ "com.example.sdk.two",
+ 34 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo2 = PackageInfoUtils.generateApplicationInfo(ps2.getAndroidPackage(),
+ 0 /*flags*/, ps2.getUserStateOrDefault(0), 0 /*userId*/,
+ ps2);
+ assertThat(appInfo2, notNullValue());
+ assertThat(appInfo2.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo2.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo2.sharedLibraryInfos.get(0).getName(), "com.example.sdk.two");
+ }
+
+ @Test
+ public void testApplicationInfoForUseSdkOptionalDisabled() throws Exception {
+ mSetFlagsRule.disableFlags(Flags.FLAG_SDK_LIB_INDEPENDENCE);
+
+ // Create basic information for SDK lib
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ ps1.setPkg(((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
+ .setUid(ps1.getAppId())
+ .setSystem(true)
+ .hideAsFinal());
+ ps1.setUsesSdkLibraries(new String[] { "com.example.sdk.one" });
+ ps1.setUsesSdkLibrariesVersionsMajor(new long[] { 12 });
+ ps1.setUsesSdkLibrariesOptional(new boolean[] {true});
+ ps1.addUsesLibraryInfo(new SharedLibraryInfo("path1",
+ "packageName1",
+ Collections.emptyList(),
+ "com.example.sdk.one",
+ 12 /*version*/,
+ SharedLibraryInfo.TYPE_SDK_PACKAGE,
+ null /*declaringPackage*/,
+ null /*dependentPackages*/,
+ null /*dependencies*/,
+ false /*isNative*/));
+ ApplicationInfo appInfo1 = PackageInfoUtils.generateApplicationInfo(ps1.getAndroidPackage(),
+ 0 /*flags*/, ps1.getUserStateOrDefault(0), 0 /*userId*/,
+ ps1);
+ assertThat(appInfo1, notNullValue());
+ assertThat(appInfo1.sharedLibraryInfos, notNullValue());
+ assertThat(appInfo1.optionalSharedLibraryInfos, nullValue());
+ assertEquals(appInfo1.sharedLibraryInfos.get(0).getName(), "com.example.sdk.one");
+ }
+
/** make sure our initialized KeySetManagerService metadata matches packages.xml */
@Test
public void testReadKeySetSettings() throws Exception {
@@ -315,7 +426,7 @@
PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -327,7 +438,7 @@
packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -362,7 +473,8 @@
watcher.verifyNoChangeReported("readUserState");
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is(PACKAGE_NAME_3));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0),
+ is(UserPackage.of(0, PACKAGE_NAME_3)));
final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
@@ -413,19 +525,24 @@
.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND)
.build();
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ UserPackage suspender1 = UserPackage.of(0, "suspendingPackage1");
+ UserPackage suspender2 = UserPackage.of(0, "suspendingPackage2");
+ UserPackage suspender3 = UserPackage.of(0, "suspendingPackage3");
+ UserPackage irrelevantSuspender = UserPackage.of(0, "irrelevant");
+
+ ps1.modifyUserState(0).putSuspendParams(suspender1,
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- ps1.modifyUserState(0).putSuspendParams("suspendingPackage2",
+ ps1.modifyUserState(0).putSuspendParams(suspender2,
new SuspendParams(dialogInfo2, appExtras2, launcherExtras2));
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
watcher.verifyChangeReported("put package 1");
- ps2.modifyUserState(0).putSuspendParams("suspendingPackage3",
+ ps2.modifyUserState(0).putSuspendParams(suspender3,
new SuspendParams(null, appExtras1, null));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
watcher.verifyChangeReported("put package 2");
- ps3.modifyUserState(0).removeSuspension("irrelevant");
+ ps3.modifyUserState(0).removeSuspension(irrelevantSuspender);
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
watcher.verifyChangeReported("put package 3");
@@ -450,7 +567,7 @@
assertThat(readPus1.getSuspendParams().size(), is(2));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(0), is("suspendingPackage1"));
+ assertThat(readPus1.getSuspendParams().keyAt(0), is(suspender1));
final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
@@ -460,7 +577,7 @@
is(true));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
+ assertThat(readPus1.getSuspendParams().keyAt(1), is(suspender2));
final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
assertThat(params12.getDialogInfo(), is(dialogInfo2));
@@ -473,7 +590,7 @@
.readUserState(0);
assertThat(readPus2.isSuspended(), is(true));
assertThat(readPus2.getSuspendParams().size(), is(1));
- assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
+ assertThat(readPus2.getSuspendParams().keyAt(0), is(suspender3));
final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
assertThat(params21.getDialogInfo(), is(nullValue()));
@@ -1024,7 +1141,8 @@
.setNeutralButtonText(0x11220003)
.setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS)
.build();
- origPkgSetting01.modifyUserState(0).putSuspendParams("suspendingPackage1",
+ origPkgSetting01.modifyUserState(0).putSuspendParams(
+ UserPackage.of(0, "suspendingPackage1"),
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
origPkgSetting01.setPkg(mockAndroidPackage(origPkgSetting01));
final PackageSetting testPkgSetting01 = new PackageSetting(
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index 9c48af8..285c059 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -73,7 +73,7 @@
import com.android.compatibility.common.util.CddTest;
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.parsing.ParsingUtils;
import com.android.server.pm.test.service.server.R;
import dalvik.system.VMRuntime;
@@ -346,7 +346,7 @@
private ParsedPackage parsePackage(Uri packageURI) {
final String archiveFilePath = packageURI.getPath();
- ParseResult<ParsedPackage> result = ParsingPackageUtils.parseDefaultOneTime(
+ ParseResult<ParsedPackage> result = ParsingUtils.parseDefaultOneTime(
new File(archiveFilePath), 0 /*flags*/, Collections.emptyList(),
false /*collectCertificates*/);
if (result.isError()) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index a62cd4f..03e45a2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.pm;
-import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
+import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -58,17 +58,28 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.permission.CompatibilityPermissionInfo;
import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedActivityImpl;
import com.android.internal.pm.pkg.component.ParsedApexSystemService;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl;
import com.android.internal.pm.pkg.component.ParsedPermission;
import com.android.internal.pm.pkg.component.ParsedPermissionGroup;
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedProviderImpl;
import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedServiceImpl;
import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.parsing.PackageCacher;
@@ -76,19 +87,8 @@
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
-import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.component.ParsedActivityImpl;
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionImpl;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
-import com.android.server.pm.pkg.component.ParsedProviderImpl;
-import com.android.server.pm.pkg.component.ParsedServiceImpl;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import org.junit.Before;
import org.junit.Rule;
@@ -725,6 +725,16 @@
public boolean hasFeature(String feature) {
return false;
}
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
if (cacheDir != null) {
setCacheDir(cacheDir);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
index c0c7032..9780440 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
@@ -27,6 +27,7 @@
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
+import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
@@ -89,7 +90,7 @@
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
- oldUserState.putSuspendParams("suspendingPackage",
+ oldUserState.putSuspendParams(UserPackage.of(0, "suspendingPackage"),
new SuspendParams(null, new PersistableBundle(), null));
assertThat(testUserState.equals(oldUserState), is(false));
@@ -220,6 +221,8 @@
final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
"launcherExtras2", null, 0);
+ final int suspendingUser1 = 0;
+ final int suspendingUser2 = 10;
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
@@ -230,12 +233,12 @@
.setMessage("dialogMessage2")
.build();
- final ArrayMap<String, SuspendParams> paramsMap1 = new ArrayMap<>();
- paramsMap1.put(suspendingPackage1, createSuspendParams(dialogInfo1, appExtras1,
- launcherExtras1));
- final ArrayMap<String, SuspendParams> paramsMap2 = new ArrayMap<>();
- paramsMap2.put(suspendingPackage2, createSuspendParams(dialogInfo2,
- appExtras2, launcherExtras2));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap1 = new ArrayMap<>();
+ paramsMap1.put(UserPackage.of(suspendingUser1, suspendingPackage1),
+ createSuspendParams(dialogInfo1, appExtras1, launcherExtras1));
+ final ArrayMap<UserPackage, SuspendParams> paramsMap2 = new ArrayMap<>();
+ paramsMap2.put(UserPackage.of(suspendingUser2, suspendingPackage2),
+ createSuspendParams(dialogInfo2, appExtras2, launcherExtras2));
final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
index 6202908..c1271bb 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
@@ -50,13 +50,13 @@
import android.platform.test.annotations.Presubmit;
import android.util.Pair;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import org.hamcrest.BaseMatcher;
@@ -376,7 +376,7 @@
// Create the ParsedPackage for the apex
final ParsedPackage basicPackage =
((ParsedPackage) new PackageImpl(DUMMY_PACKAGE_NAME, codePath, codePath,
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.hideAsParsed())
.setVersionCodeMajor(1)
@@ -595,7 +595,7 @@
// TODO(b/135203078): Make this use PackageImpl.forParsing and separate the steps
return (ParsingPackage) ((ParsedPackage) new PackageImpl(packageName,
"/data/tmp/randompath/base.apk", createCodePath(packageName),
- mock(TypedArray.class), false)
+ mock(TypedArray.class), false, null)
.setVolumeUuid(UUID_ONE.toString())
.addUsesStaticLibrary("some.static.library", 234L, new String[]{"testCert1"})
.addUsesStaticLibrary("some.other.static.library", 456L, new String[]{"testCert2"})
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index b102ab4..b63950c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -39,14 +39,14 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.component.ParsedActivityUtils;
import com.android.internal.pm.pkg.component.ParsedComponent;
import com.android.internal.pm.pkg.component.ParsedIntentInfo;
import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedPermissionUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedActivityUtils;
-import com.android.server.pm.pkg.component.ParsedPermissionUtils;
import com.android.server.pm.test.service.server.R;
import com.google.common.truth.Expect;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index 67b91d2..c435b94 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -22,7 +22,6 @@
import android.platform.test.annotations.Presubmit
import androidx.test.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.ParsedPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.test.service.server.R
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -121,7 +120,7 @@
input.copyTo(output)
}
}
- return ParsingPackageUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
+ return ParsingUtils.parseDefaultOneTime(file, 0 /*flags*/, emptyList(),
false /*collectCertificates*/)
}
}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
new file mode 100644
index 0000000..a9eac95
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/ParsingUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.parsing;
+
+import android.annotation.NonNull;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.res.TypedArray;
+import android.permission.PermissionManager;
+
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackage;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.SystemConfig;
+
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+
+/** @hide **/
+public class ParsingUtils {
+
+ /**
+ * @see ParsingPackageUtils#parseDefault(ParseInput, File, int, List, boolean,
+ * ParsingPackageUtils.Callback)
+ */
+ @NonNull
+ public static ParseResult<ParsedPackage> parseDefaultOneTime(File file,
+ @ParsingPackageUtils.ParseFlags int parseFlags,
+ @NonNull List<PermissionManager.SplitPermissionInfo> splitPermissions,
+ boolean collectCertificates) {
+ ParseInput input = ParseTypeImpl.forDefaultParsing().reset();
+ return ParsingPackageUtils.parseDefault(input, file, parseFlags, splitPermissions, collectCertificates,
+ new ParsingPackageUtils.Callback() {
+ @Override
+ public boolean hasFeature(String feature) {
+ // Assume the device doesn't support anything. This will affect permission
+ // parsing and will force <uses-permission/> declarations to include all
+ // requiredNotFeature permissions and exclude all requiredFeature
+ // permissions. This mirrors the old behavior.
+ return false;
+ }
+
+ @Override
+ public ParsingPackage startParsingPackage(
+ @NonNull String packageName,
+ @NonNull String baseApkPath,
+ @NonNull String path,
+ @NonNull TypedArray manifestArray, boolean isCoreApp) {
+ return PackageImpl.forParsing(packageName, baseApkPath, path, manifestArray,
+ isCoreApp, this);
+ }
+
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return SystemConfig.getInstance().getHiddenApiWhitelistedApps();
+ }
+
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return SystemConfig.getInstance().getInstallConstraintsAllowlist();
+ }
+ });
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
index 1f57b6c..98af63c 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
@@ -17,15 +17,15 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.platform.test.annotations.Postsubmit
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerException
import com.android.server.pm.PackageManagerService
import com.android.server.pm.PackageManagerServiceUtils
+import java.io.File
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
-import java.io.File
/**
* This test parses all the system APKs on the device image to ensure that they succeed.
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
index 6cd7123..9517e49 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidHidlUpdaterTest.java
@@ -24,8 +24,8 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
index 27fd781..01fad8f 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -21,8 +21,8 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
index b13d6de..b1f26c2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestBaseUpdaterTest.java
@@ -23,8 +23,8 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
index fa69f84..349763a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/AndroidTestRunnerSplitUpdaterTest.java
@@ -24,9 +24,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.AndroidTestRunnerSplitUpdater;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
index 856013a..71bdacb 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java
@@ -22,9 +22,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Before;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
index ae5ea21..6aa0c2d 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/ComGoogleAndroidMapsUpdaterTest.java
@@ -21,8 +21,8 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
index e126ffc..44098d0 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/OrgApacheHttpLegacyUpdaterTest.java
@@ -23,8 +23,8 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index d0b0cf8..9d5ce8a 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -28,10 +28,10 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Assume;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
index c141c03..bffeb72 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryAndroidTestBaseLibraryTest.java
@@ -23,9 +23,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryAndroidTestBaseLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
index a58604b..b114cd3 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/parsing/library/RemoveUnnecessaryOrgApacheHttpLegacyLibraryTest.java
@@ -23,9 +23,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.parsing.library.PackageBackwardCompatibility.RemoveUnnecessaryOrgApacheHttpLegacyLibrary;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.Test;
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 09b66c1..ef9c62f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -30,21 +30,21 @@
import android.util.SparseArray
import android.util.SparseIntArray
import com.android.internal.R
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils
-import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedApexSystemServiceImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
-import com.android.server.pm.pkg.component.ParsedServiceImpl
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import java.security.KeyPairGenerator
@@ -534,34 +534,34 @@
}
),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
- getSetByValue({ AndroidPackageUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
- getSetByValue({ AndroidPackageUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOdm(it) }, "isOdm", PackageImpl::setOdm, true),
+ getSetByValue({ AndroidPackageLegacyUtils.isOem(it) }, "isOem", PackageImpl::setOem, true),
getSetByValue(
- { AndroidPackageUtils.isPrivileged(it) },
+ { AndroidPackageLegacyUtils.isPrivileged(it) },
"isPrivileged",
PackageImpl::setPrivileged,
true
),
getSetByValue(
- { AndroidPackageUtils.isProduct(it) },
+ { AndroidPackageLegacyUtils.isProduct(it) },
"isProduct",
PackageImpl::setProduct,
true
),
getSetByValue(
- { AndroidPackageUtils.isVendor(it) },
+ { AndroidPackageLegacyUtils.isVendor(it) },
"isVendor",
PackageImpl::setVendor,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystem(it) },
+ { AndroidPackageLegacyUtils.isSystem(it) },
"isSystem",
PackageImpl::setSystem,
true
),
getSetByValue(
- { AndroidPackageUtils.isSystemExt(it) },
+ { AndroidPackageLegacyUtils.isSystemExt(it) },
"isSystemExt",
PackageImpl::setSystemExt,
true
@@ -593,7 +593,7 @@
)
) { "" }
},
- true
+ true, null
)
.asSplit(
arrayOf("testSplitNameZero", "testSplitNameOne"),
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index 2646854..2c8b1cd 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -18,7 +18,7 @@
import android.content.pm.ActivityInfo
import com.android.internal.pm.pkg.component.ParsedActivity
-import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
index 52d5b3b..ad53746 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedAttribution
-import com.android.server.pm.pkg.component.ParsedAttributionImpl
+import com.android.internal.pm.pkg.component.ParsedAttributionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
index af0c0de2..3ac4853 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
@@ -18,8 +18,8 @@
import android.content.pm.PackageManager
import com.android.internal.pm.pkg.component.ParsedComponent
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Bundle
import android.os.Parcelable
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
index dc0f194..2bd4f61 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedInstrumentation
-import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.internal.pm.pkg.component.ParsedInstrumentationImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
index 5224f23..af385e2 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedIntentInfo
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Parcelable
import android.os.PatternMatcher
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
index dfff602..061e39d 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedMainComponent
-import com.android.server.pm.pkg.component.ParsedMainComponentImpl
+import com.android.internal.pm.pkg.component.ParsedMainComponentImpl
import android.os.Parcelable
import java.util.Arrays
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
index ccbf558..3a64188 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
index 2814783..551f16d 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
@@ -18,8 +18,8 @@
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
-import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
index 2e96046..93bdeae 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
@@ -16,9 +16,9 @@
package com.android.server.pm.test.parsing.parcelling
-import com.android.internal.pm.pkg.component.ParsedProcess
-import com.android.server.pm.pkg.component.ParsedProcessImpl
import android.util.ArrayMap
+import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
index 290dbd6..1e84470 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
@@ -17,9 +17,9 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PathPermission
-import com.android.internal.pm.pkg.component.ParsedProvider
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import android.os.PatternMatcher
+import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
index 3ae7e92..79d5a4f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedService
-import com.android.server.pm.pkg.component.ParsedServiceImpl
+import com.android.internal.pm.pkg.component.ParsedServiceImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
index 67dfc6d..d0ad09b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.test.parsing.parcelling
import com.android.internal.pm.pkg.component.ParsedUsesPermission
-import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
+import com.android.internal.pm.pkg.component.ParsedUsesPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
index 1da3a22..b21c349 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/pkg/PackageStateTest.kt
@@ -17,37 +17,34 @@
package com.android.server.pm.test.pkg
import android.content.Intent
-import android.content.pm.overlay.OverlayPaths
import android.content.pm.PackageManager
import android.content.pm.PathPermission
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
+import android.content.pm.overlay.OverlayPaths
import android.os.PatternMatcher
import android.util.ArraySet
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.pkg.component.ParsedActivity
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedComponentImpl
import com.android.internal.pm.pkg.component.ParsedInstrumentation
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.internal.pm.pkg.component.ParsedPermission
import com.android.internal.pm.pkg.component.ParsedPermissionGroup
+import com.android.internal.pm.pkg.component.ParsedPermissionImpl
import com.android.internal.pm.pkg.component.ParsedProcess
+import com.android.internal.pm.pkg.component.ParsedProcessImpl
import com.android.internal.pm.pkg.component.ParsedProvider
+import com.android.internal.pm.pkg.component.ParsedProviderImpl
import com.android.internal.pm.pkg.component.ParsedService
import com.android.server.pm.PackageSetting
import com.android.server.pm.PackageSettingBuilder
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
import com.android.server.pm.pkg.PackageUserState
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedComponentImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
-import com.android.server.pm.pkg.component.ParsedPermissionImpl
-import com.android.server.pm.pkg.component.ParsedProcessImpl
-import com.android.server.pm.pkg.component.ParsedProviderImpl
import com.android.server.pm.test.parsing.parcelling.AndroidPackageTest
import com.google.common.truth.Expect
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.TemporaryFolder
import kotlin.contracts.ExperimentalContracts
import kotlin.reflect.KClass
import kotlin.reflect.KFunction
@@ -55,6 +52,9 @@
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.full.memberFunctions
import kotlin.reflect.full.starProjectedType
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
class PackageStateTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 9341e9d..5e73d19 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -22,11 +22,11 @@
import android.os.PatternMatcher
import android.util.ArraySet
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.SystemConfig
import com.android.server.compat.PlatformCompat
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationCollector
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index a737b90..d307608 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -29,17 +29,22 @@
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationEnforcer
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicInteger
+import kotlin.test.assertFailsWith
+import kotlin.test.fail
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -51,11 +56,6 @@
import org.mockito.Mockito.eq
import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoMoreInteractions
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.atomic.AtomicInteger
-import kotlin.test.assertFailsWith
-import kotlin.test.fail
@RunWith(Parameterized::class)
class DomainVerificationEnforcerTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index f38df22..5edf30a3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -30,24 +30,24 @@
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerStub
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.test.assertFailsWith
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-import java.util.concurrent.atomic.AtomicBoolean
-import kotlin.test.assertFailsWith
class DomainVerificationManagerApiTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index 874e0d2..85f0125 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -37,27 +37,27 @@
import android.util.SparseArray
import android.util.Xml
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.Computer
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.spy
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.security.PublicKey
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.io.ByteArrayInputStream
-import java.io.ByteArrayOutputStream
-import java.security.PublicKey
-import java.util.UUID
class DomainVerificationPackageTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index 3207e6c..a5c4f6c 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -25,15 +25,16 @@
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
+import java.util.UUID
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -44,7 +45,6 @@
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.eq
import org.mockito.Mockito.verify
-import java.util.UUID
@RunWith(Parameterized::class)
class DomainVerificationSettingsMutationTest {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index a90b7d5..ae570a3 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -27,14 +27,15 @@
import android.util.ArraySet
import android.util.SparseArray
import com.android.internal.pm.parsing.pkg.AndroidPackageInternal
+import com.android.internal.pm.pkg.component.ParsedActivityImpl
+import com.android.internal.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageStateInternal
import com.android.server.pm.pkg.PackageUserStateInternal
-import com.android.server.pm.pkg.component.ParsedActivityImpl
-import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.verify.domain.DomainVerificationService
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
+import java.util.UUID
import org.junit.Test
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
@@ -42,8 +43,6 @@
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.doReturn
-import java.util.UUID
-
class DomainVerificationUserStateOverrideTest {
companion object {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index de8b308..c2b52b4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -45,14 +45,15 @@
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.Before;
import org.junit.Rule;
@@ -67,6 +68,7 @@
import java.io.OutputStream;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
@SmallTest
@Presubmit
@@ -106,6 +108,18 @@
public boolean hasFeature(String feature) {
return true;
}
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getHiddenApiWhitelistedApps() {
+ return new ArraySet<>();
+ }
+
+ @androidx.annotation.NonNull
+ @Override
+ public Set<String> getInstallConstraintsAllowlist() {
+ return new ArraySet<>();
+ }
});
mMockSystem.system().stageNominalSystemState();
@@ -385,7 +399,7 @@
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
@@ -416,7 +430,7 @@
findFactory(results, "test.apex.rebootless").apexInfo);
assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
- assertThat(AndroidPackageUtils.isSystem(factoryPkg)).isTrue();
+ assertThat(AndroidPackageLegacyUtils.isSystem(factoryPkg)).isTrue();
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 28bd987..7b29e2a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -56,8 +56,10 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder
import com.android.internal.R
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.internal.pm.pkg.parsing.ParsingPackage
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.LockGuard
@@ -68,10 +70,8 @@
import com.android.server.pm.dex.DexManager
import com.android.server.pm.dex.DynamicCodeLogger
import com.android.server.pm.parsing.PackageParser2
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.resolution.ComponentResolver
import com.android.server.pm.snapshot.PackageDataSnapshot
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
@@ -81,14 +81,6 @@
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.android.server.utils.WatchedArrayMap
-import libcore.util.HexEncoding
-import org.junit.Assert
-import org.junit.rules.TestRule
-import org.junit.runner.Description
-import org.junit.runners.model.Statement
-import org.mockito.AdditionalMatchers.or
-import org.mockito.Mockito
-import org.mockito.quality.Strictness
import java.io.File
import java.io.IOException
import java.nio.file.Files
@@ -97,6 +89,14 @@
import java.util.Arrays
import java.util.Random
import java.util.concurrent.FutureTask
+import libcore.util.HexEncoding
+import org.junit.Assert
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.mockito.AdditionalMatchers.or
+import org.mockito.Mockito
+import org.mockito.quality.Strictness
/**
* A utility for mocking behavior of the system and dependencies when testing PackageManagerService
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
index e685c3f..944b1aa 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -21,17 +21,17 @@
import android.content.pm.SharedLibraryInfo
import android.content.pm.VersionedPackage
import android.os.Build
-import android.os.storage.StorageManager
import android.os.UserHandle
+import android.os.storage.StorageManager
import android.util.ArrayMap
import android.util.PackageUtils
+import com.android.internal.pm.parsing.pkg.PackageImpl
import com.android.internal.pm.parsing.pkg.ParsedPackage
import com.android.server.SystemConfig.SharedLibraryEntry
import com.android.server.compat.PlatformCompat
import com.android.server.extendedtestutils.wheneverStatic
import com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME
import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.testutils.any
import com.android.server.testutils.eq
import com.android.server.testutils.mock
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index ae53e70..7444403 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -19,6 +19,7 @@
import android.app.AppOpsManager
import android.content.Intent
import android.content.pm.SuspendDialogInfo
+import android.content.pm.UserPackage
import android.os.Binder
import android.os.PersistableBundle
import com.android.server.testutils.any
@@ -41,12 +42,18 @@
.thenReturn(AppOpsManager.MODE_DEFAULT)
}
+ companion object {
+ val doUserPackage = UserPackage.of(TEST_USER_ID, DEVICE_OWNER_PACKAGE)
+ val platformUserPackage = UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME)
+ val testUserPackage1 = UserPackage.of(TEST_USER_ID, TEST_PACKAGE_1)
+ }
+
@Test
fun setPackagesSuspended() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -63,14 +70,14 @@
fun setPackagesSuspended_emptyPackageName() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
null /* packageNames */, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isNull()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOfNulls(0), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isEmpty()
@@ -80,7 +87,8 @@
fun setPackagesSuspended_callerIsNotAllowed() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
+ null /* launcherExtras */, null /* dialogInfo */,
+ testUserPackage1, TEST_USER_ID,
Binder.getCallingUid(), false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -91,7 +99,7 @@
fun setPackagesSuspended_callerSuspendItself() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -102,7 +110,7 @@
fun setPackagesSuspended_nonexistentPackage() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -115,7 +123,7 @@
INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
knownPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)!!
assertThat(failedNames.size).isEqualTo(knownPackages.size)
@@ -129,14 +137,14 @@
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, false /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -184,7 +192,7 @@
appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -202,22 +210,22 @@
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspender -> suspender.packageName == DEVICE_OWNER_PACKAGE },
TEST_USER_ID)
testHandler.flush()
@@ -243,7 +251,7 @@
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -258,7 +266,7 @@
fun isPackageSuspended() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
+ null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -273,13 +281,13 @@
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
}
@Test
@@ -290,57 +298,57 @@
// Suspend.
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
// Suspend by system.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, PLATFORM_PACKAGE_NAME, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, platformUserPackage, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
// QAS by package1.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, testUserPackage1, TEST_USER_ID, deviceOwnerUid,
true /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(TEST_PACKAGE_1)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(testUserPackage1)
// Un-QAS by package1.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == TEST_PACKAGE_1 },
+ targetPackages, { suspendingPackage -> suspendingPackage == testUserPackage1 },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
// Un-suspend by system.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == PLATFORM_PACKAGE_NAME },
+ targetPackages, { suspender -> suspender.packageName == PLATFORM_PACKAGE_NAME },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
// Unsuspend.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspendingPackage -> suspendingPackage == doUserPackage },
TEST_USER_ID)
testHandler.flush()
@@ -354,13 +362,13 @@
.setTitle(TEST_PACKAGE_1).build()
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
+ null /* launcherExtras */, dialogInfo, doUserPackage, TEST_USER_ID,
deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
- TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
+ TEST_PACKAGE_1, doUserPackage, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index a78f2dc..3b5cae3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -23,6 +23,8 @@
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
@@ -41,6 +43,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.hardware.biometrics.AuthenticationStateListener;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -108,6 +111,7 @@
@Mock
IFaceService mFaceService;
@Mock
+
AppOpsManager mAppOpsManager;
@Mock
private VirtualDeviceManagerInternal mVdmInternal;
@@ -404,6 +408,23 @@
eq(TEST_OP_PACKAGE_NAME));
}
+ @Test
+ public void testRegisterAuthenticationStateListener_callsFingerprintService()
+ throws Exception {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
+
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final AuthenticationStateListener listener = mock(AuthenticationStateListener.class);
+
+ mAuthService.mImpl.registerAuthenticationStateListener(listener);
+
+ waitForIdle();
+ verify(mFingerprintService).registerAuthenticationStateListener(
+ eq(listener));
+ }
@Test
public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
index 5012335..94cb860 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/SensorOverlaysTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -23,10 +25,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.biometrics.BiometricOverlayConstants;
+import android.hardware.biometrics.BiometricRequestConstants;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import androidx.test.filters.SmallTest;
@@ -40,6 +43,7 @@
import java.util.ArrayList;
import java.util.List;
+@RequiresFlagsDisabled(FLAG_SIDEFPS_CONTROLLER_REFACTOR)
@Presubmit
@SmallTest
public class SensorOverlaysTest {
@@ -97,7 +101,7 @@
private void testShow(IUdfpsOverlayController udfps, ISidefpsController sidefps)
throws Exception {
final SensorOverlays sensorOverlays = new SensorOverlays(udfps, sidefps);
- final int reason = BiometricOverlayConstants.REASON_UNKNOWN;
+ final int reason = BiometricRequestConstants.REASON_UNKNOWN;
sensorOverlays.show(SENSOR_ID, reason, mAcquisitionClient);
if (udfps != null) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 79a528c..c24227f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -18,6 +18,8 @@
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -56,6 +58,7 @@
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -68,6 +71,7 @@
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -91,6 +95,8 @@
@SmallTest
public class FingerprintAuthenticationClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final int SENSOR_ID = 4;
private static final int USER_ID = 8;
private static final long OP_ID = 7;
@@ -128,6 +134,8 @@
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -384,6 +392,7 @@
private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
@@ -398,6 +407,49 @@
}
@Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_lockout_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutTimed(5000));
+ }
+
+ @Test
+ public void showHideOverlay_lockoutPerm_sidefpsControllerRemovalRefactor()
+ throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onLockoutPermanent());
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintAuthenticationClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintAuthenticationClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
+ @Test
public void cancelsAuthWhenNotInForeground() throws Exception {
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
topTask.topActivity = new ComponentName("other", "thing");
@@ -502,7 +554,8 @@
mBiometricLogger, mBiometricContext,
true /* isStrongBiometric */,
null /* taskStackListener */,
- mUdfpsOverlayController, mSideFpsController, allowBackgroundAuthentication,
+ mUdfpsOverlayController, mSideFpsController, mAuthenticationStateListeners,
+ allowBackgroundAuthentication,
mSensorProps,
new Handler(mLooper.getLooper()), 0 /* biometricStrength */, mClock,
lockoutTracker) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index c7eb1db..e7d4a2e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
+import static com.android.systemui.shared.Flags.FLAG_SIDEFPS_CONTROLLER_REFACTOR;
+
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -38,6 +40,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
@@ -48,6 +51,7 @@
import com.android.server.biometrics.log.CallbackWithProbe;
import com.android.server.biometrics.log.OperationContextExt;
import com.android.server.biometrics.log.Probe;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
@@ -68,6 +72,8 @@
@SmallTest
public class FingerprintEnrollClientTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
private static final long REQUEST_ID = 9;
@@ -98,6 +104,8 @@
@Mock
private ISidefpsController mSideFpsController;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private FingerprintSensorPropertiesInternal mSensorProps;
@Mock
private ClientMonitorCallback mCallback;
@@ -271,6 +279,7 @@
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
throws RemoteException {
+ mSetFlagsRule.disableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
final FingerprintEnrollClient client = createClient();
client.start(mCallback);
@@ -284,6 +293,44 @@
verify(mSideFpsController).hide(anyInt());
}
+ @Test
+ public void showHideOverlay_cancel_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.cancel());
+ }
+
+ @Test
+ public void showHideOverlay_stop_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.stopHalOperation());
+ }
+
+ @Test
+ public void showHideOverlay_error_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(c -> c.onError(0, 0));
+ verify(mCallback).onClientFinished(any(), eq(false));
+ }
+
+ @Test
+ public void showHideOverlay_result_sidefpsControllerRemovalRefactor() throws RemoteException {
+ showHideOverlay_sidefpsControllerRemovalRefactor(
+ c -> c.onEnrollResult(new Fingerprint("", 1, 1), 0));
+ }
+
+ private void showHideOverlay_sidefpsControllerRemovalRefactor(
+ Consumer<FingerprintEnrollClient> block) throws RemoteException {
+ mSetFlagsRule.enableFlags(FLAG_SIDEFPS_CONTROLLER_REFACTOR);
+ final FingerprintEnrollClient client = createClient();
+
+ client.start(mCallback);
+
+ verify(mUdfpsOverlayController).showUdfpsOverlay(eq(REQUEST_ID), anyInt(), anyInt(), any());
+ verify(mAuthenticationStateListeners).onAuthenticationStarted(anyInt());
+
+ block.accept(client);
+
+ verify(mUdfpsOverlayController).hideUdfpsOverlay(anyInt());
+ verify(mAuthenticationStateListeners).onAuthenticationStopped();
+ }
+
private FingerprintEnrollClient createClient() throws RemoteException {
return createClient(500);
}
@@ -296,6 +343,7 @@
mClientMonitorCallbackConverter, 0 /* userId */,
HAT, "owner", mBiometricUtils, 8 /* sensorId */,
mBiometricLogger, mBiometricContext, mSensorProps, mUdfpsOverlayController,
- mSideFpsController, 6 /* maxTemplatesPerUser */, FingerprintManager.ENROLL_ENROLL);
+ mSideFpsController, mAuthenticationStateListeners, 6 /* maxTemplatesPerUser */,
+ FingerprintManager.ENROLL_ENROLL);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 8f6efff..4cfb83f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -43,6 +43,7 @@
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
@@ -74,6 +75,8 @@
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -110,8 +113,9 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new FingerprintProvider(mContext,
- mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext, mDaemon);
+ mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG,
+ mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext,
+ mDaemon);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index b32b89a..0d3f192 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -40,6 +40,7 @@
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -70,6 +71,8 @@
@Mock
private BiometricScheduler mScheduler;
@Mock
+ private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -102,9 +105,10 @@
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken);
- mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback, sensorProps,
- mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
- mHalResultController, mBiometricContext);
+ mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback,
+ mAuthenticationStateListeners, sensorProps, mScheduler,
+ new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController,
+ mBiometricContext);
}
@Test
@@ -126,13 +130,14 @@
TestableFingerprint21(@NonNull Context context,
@NonNull BiometricStateCallback biometricStateCallback,
+ @NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, biometricStateCallback, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller, biometricContext);
+ super(context, biometricStateCallback, authenticationStateListeners, sensorProps,
+ scheduler, handler, lockoutResetDispatcher, controller, biometricContext);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 943a9c47..1dd64ff 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,7 +18,6 @@
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -222,21 +221,21 @@
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
// Verify that actual package suspension state is not modified after user start
verify(getServices().packageManagerInternal, never())
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
@@ -255,14 +254,14 @@
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isSuspendingAnyPackages(
- PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
+ USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// Verify that apps get unsuspended.
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(USER_SYSTEM);
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
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 f4dac2c..2470403 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -63,7 +63,6 @@
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
@@ -5080,7 +5079,7 @@
verify(getServices().iwindowManager).refreshScreenCaptureDisabled();
// Unsuspend personal apps
verify(getServices().packageManagerInternal)
- .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
+ .unsuspendAdminSuspendedPackages(UserHandle.USER_SYSTEM);
verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
@@ -7535,7 +7534,7 @@
.cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
// Verify that the apps are NOT unsuspeded.
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt());
+ any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
// Verify that DPC is invoked to check policy compliance.
verify(mContext.spiedContext).startActivityAsUser(
MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
index fe37f42..b3d25f2 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/OverrideRequestControllerTest.java
@@ -47,6 +47,10 @@
@Presubmit
@RunWith(AndroidJUnit4.class)
public final class OverrideRequestControllerTest {
+
+ private static final DeviceState TEST_DEVICE_STATE_ZERO = new DeviceState(0, "TEST_STATE", 0);
+ private static final DeviceState TEST_DEVICE_STATE_ONE = new DeviceState(1, "TEST_STATE", 0);
+
private TestStatusChangeListener mStatusListener;
private OverrideRequestController mController;
@@ -59,7 +63,7 @@
@Test
public void addRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addRequest(request);
@@ -69,14 +73,14 @@
@Test
public void addRequest_cancelExistingRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addRequest(secondRequest);
@@ -87,7 +91,7 @@
@Test
public void addRequest_cancelActiveRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
@@ -101,7 +105,7 @@
@Test
public void addBaseStateRequest() {
OverrideRequest request = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(request));
mController.addBaseStateRequest(request);
@@ -111,14 +115,14 @@
@Test
public void addBaseStateRequest_cancelExistingBaseStateRequestThroughNewRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(firstRequest));
mController.addBaseStateRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
OverrideRequest secondRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
assertNull(mStatusListener.getLastStatus(secondRequest));
mController.addBaseStateRequest(secondRequest);
@@ -129,7 +133,7 @@
@Test
public void addBaseStateRequest_cancelActiveBaseStateRequest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addBaseStateRequest(firstRequest);
@@ -143,13 +147,13 @@
@Test
public void handleBaseStateChanged() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES /* flags */,
OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 0 /* requestedState */,
+ TEST_DEVICE_STATE_ZERO,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -169,11 +173,11 @@
@Test
public void handleProcessDied() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -192,11 +196,11 @@
mController.setStickyRequestsAllowed(true);
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 0 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ZERO, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
@@ -215,11 +219,11 @@
@Test
public void handleNewSupportedStates() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
OverrideRequest baseStateRequest = new OverrideRequest(new Binder(), 0 /* pid */,
0 /* uid */,
- 1 /* requestedState */,
+ TEST_DEVICE_STATE_ONE,
0 /* flags */, OVERRIDE_REQUEST_TYPE_BASE_STATE);
mController.addRequest(firstRequest);
@@ -242,7 +246,7 @@
@Test
public void cancelOverrideRequestsTest() {
OverrideRequest firstRequest = new OverrideRequest(new Binder(), 0 /* pid */, 0 /* uid */,
- 1 /* requestedState */, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
+ TEST_DEVICE_STATE_ONE, 0 /* flags */, OVERRIDE_REQUEST_TYPE_EMULATED_STATE);
mController.addRequest(firstRequest);
assertEquals(mStatusListener.getLastStatus(firstRequest).intValue(), STATUS_ACTIVE);
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index fb78574..0d25faf 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -60,6 +60,8 @@
import com.android.internal.inputmethod.StartInputFlags;
+import com.google.common.truth.Truth;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -1336,6 +1338,54 @@
}
}
+ private static void verifySplitEnabledImeStr(@NonNull String enabledImeStr,
+ @NonNull String... expected) {
+ final ArrayList<String> actual = new ArrayList<>();
+ InputMethodUtils.splitEnabledImeStr(enabledImeStr, actual::add);
+ if (expected.length == 0) {
+ Truth.assertThat(actual).isEmpty();
+ } else {
+ Truth.assertThat(actual).containsExactlyElementsIn(expected);
+ }
+ }
+
+ @Test
+ public void testSplitEnabledImeStr() {
+ verifySplitEnabledImeStr("");
+ verifySplitEnabledImeStr("com.android/.ime1", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3", "com.android/.ime1");
+ verifySplitEnabledImeStr("com.android/.ime1;1;2;3:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2",
+ "com.android/.ime1", "com.android/.ime2");
+ verifySplitEnabledImeStr("com.android/.ime1:com.android/.ime2:com.android/.ime3",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ verifySplitEnabledImeStr("com.android/.ime1;1:com.android/.ime2;1:com.android/.ime3;1",
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3");
+ }
+
+ @Test
+ public void testConcatEnabledImeIds() {
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("")).isEmpty();
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds("", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1", "com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime1"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2");
+ Truth.assertThat(InputMethodUtils.concatEnabledImeIds(
+ "com.android/.ime1:com.android/.ime2", "com.android/.ime3"))
+ .isEqualTo("com.android/.ime1:com.android/.ime2:com.android/.ime3");
+ }
+
@Test
public void updateEnabledImeStringTest() {
// No change cases
diff --git a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
index dd687fd4..86a1358 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SELinuxMMACTest.java
@@ -27,9 +27,9 @@
import android.os.Build;
import android.platform.test.annotations.Presubmit;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.compat.PlatformCompat;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.PackageState;
import org.junit.Test;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index 8464969..ee93bc1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -53,10 +53,10 @@
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import org.junit.After;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 0f87202..587f5fa 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -29,9 +29,9 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.internal.pm.parsing.pkg.ParsedPackage;
import com.android.internal.pm.pkg.parsing.ParsingPackage;
-import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.pkg.AndroidPackage;
import dalvik.system.DelegateLastClassLoader;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index ee23a00..9b4ca2a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -21,17 +21,17 @@
import android.os.SystemProperties.PROP_VALUE_MAX
import android.platform.test.annotations.Postsubmit
import com.android.internal.R
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.PackageManagerService
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.google.common.truth.Truth.assertThat
+import java.io.ByteArrayInputStream
+import java.io.File
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Assert.fail
import org.junit.Test
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
-import java.io.ByteArrayInputStream
-import java.io.File
@Postsubmit
class AndroidPackageParsingValidationTest {
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
index 2332817..c44f583 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/TestPackageParser2.kt
@@ -17,6 +17,7 @@
package com.android.server.pm.parsing
import android.content.pm.ApplicationInfo
+import android.util.ArraySet
import java.io.File
class TestPackageParser2(var cacheDir: File? = null) : PackageParser2(
@@ -33,4 +34,7 @@
// behavior.
return false
}
+
+ override fun getHiddenApiWhitelistedApps() = ArraySet<String>()
+ override fun getInstallConstraintsAllowlist() = ArraySet<String>()
})
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 5ba4851..759b204 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -32,8 +32,9 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.PackageList;
-import com.android.server.pm.parsing.pkg.PackageImpl;
+
import com.google.common.collect.Range;
import org.junit.Before;
@@ -415,7 +416,7 @@
private void addPkgWithMinExtVersions(String pkg, int[][] minExtVersions) {
mPackages.add(pkg);
- PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false);
+ PackageImpl pkgImpl = new PackageImpl(pkg, "baseCodePath", "codePath", null, false, null);
pkgImpl.setMinExtensionVersions(sparseArrayFrom(minExtVersions));
when(mMockPmi.getPackage(pkg)).thenReturn(pkgImpl);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 14b551a..776189e 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -219,6 +219,7 @@
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.ConversationChannelWrapper;
+import android.service.notification.DeviceEffectsApplier;
import android.service.notification.NotificationListenerFilter;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
@@ -635,6 +636,10 @@
}
private void initNMS() throws Exception {
+ initNMS(SystemService.PHASE_BOOT_COMPLETED);
+ }
+
+ private void initNMS(int upToBootPhase) throws Exception {
mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
mNotificationInstanceIdSequence);
@@ -662,13 +667,21 @@
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
mPowerManager, mPostNotificationTrackerFactory);
+
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
- mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+
+ if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
+ }
+
Mockito.reset(mHistoryManager);
verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
- mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
- verify(mHistoryManager).onBootPhaseAppsCanStart();
+
+ if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper);
+ verify(mHistoryManager).onBootPhaseAppsCanStart();
+ }
// TODO b/291907312: remove feature flag
if (Flags.refactorAttentionHelper()) {
@@ -914,7 +927,9 @@
mTestNotificationChannel.setAllowBubbles(channelEnabled);
}
- private void setUpPrefsForHistory(int uid, boolean globalEnabled) {
+ private void setUpPrefsForHistory(int uid, boolean globalEnabled) throws Exception {
+ initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
// Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, uid);
@@ -10090,7 +10105,7 @@
}
@Test
- public void testHandleOnPackageRemoved_ClearsHistory() throws RemoteException {
+ public void testHandleOnPackageRemoved_ClearsHistory() throws Exception {
// Enables Notification History setting
setUpPrefsForHistory(mUid, true /* =enabled */);
@@ -13209,6 +13224,34 @@
}
@Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_succeeds() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ // No exception!
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_tooLate_throws() throws Exception {
+ initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
+ @EnableFlags(android.app.Flags.FLAG_MODES_API)
+ public void setDeviceEffectsApplier_calledTwice_throws() throws Exception {
+ initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY);
+
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class));
+ assertThrows(IllegalStateException.class, () ->
+ mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)));
+ }
+
+ @Test
@EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES)
public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
diff --git a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
index 656957c..159c760 100644
--- a/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
+++ b/services/tests/voiceinteractiontests/src/com/android/server/voiceinteraction/SetSandboxedTrainingDataAllowedTest.java
@@ -120,12 +120,12 @@
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_currentAndPreinstalledAssistant_setsOp() {
+ public void setShouldReceiveSandboxedTrainingData_currentAndPreinstalledAssistant_setsOp() {
// Set application info so current app is the current and preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
- mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true);
verify(mAppOpsManager).setUidMode(mOpIdCaptor.capture(), mUidCaptor.capture(),
@@ -137,7 +137,7 @@
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_missingPermission_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_missingPermission_doesNotSetOp() {
// Set application info so current app is the current and preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
@@ -146,33 +146,33 @@
mPermissionEnforcer.revoke(Manifest.permission.MANAGE_HOTWORD_DETECTION);
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_notPreinstalledAssistant_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_notPreinstalledAssistant_doesNotSetOp() {
// Set application info so current app is not preinstalled assistant.
mApplicationInfo.uid = Process.myUid();
mApplicationInfo.flags = ApplicationInfo.FLAG_INSTALLED; // Does not contain FLAG_SYSTEM.
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
}
@Test
- public void setIsReceiveSandboxedTrainingDataAllowed_notCurrentAssistant_doesNotSetOp() {
+ public void setShouldReceiveSandboxedTrainingData_notCurrentAssistant_doesNotSetOp() {
// Set application info so current app is not current assistant.
mApplicationInfo.uid = Process.SHELL_UID; // Set current assistant uid to shell UID.
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
assertThrows(SecurityException.class,
- () -> mVoiceInteractionManagerServiceStub.setIsReceiveSandboxedTrainingDataAllowed(
+ () -> mVoiceInteractionManagerServiceStub.setShouldReceiveSandboxedTrainingData(
/* allowed= */ true));
verify(mAppOpsManager, never()).setUidMode(anyInt(), anyInt(), anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 526201f..670f9f6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -49,6 +49,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.UserPackage;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -195,7 +196,7 @@
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(PLATFORM_PACKAGE_NAME);
+ .thenReturn(UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME));
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
@@ -227,9 +228,10 @@
.setMessage("Test Message")
.setIcon(0x11110001)
.build();
+ UserPackage suspender = UserPackage.of(TEST_USER_ID, suspendingPackage);
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(suspendingPackage);
- when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
+ .thenReturn(suspender);
+ when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspender,
TEST_USER_ID)).thenReturn(dialogInfo);
return dialogInfo;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 98055fa..8a9c05d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,6 +117,7 @@
import com.android.compatibility.common.util.DeviceConfigStateHelper;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.pm.PackageArchiver;
import com.android.server.pm.pkg.AndroidPackage;
import com.android.server.wm.BackgroundActivityStartController.BalVerdict;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
@@ -421,6 +422,7 @@
doNothing().when(mMockPackageManager).grantImplicitAccess(
anyInt(), any(), anyInt(), anyInt(), anyBoolean());
doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
+ doReturn(mock(PackageArchiver.class)).when(mMockPackageManager).getPackageArchiver();
final Intent intent = new Intent();
intent.addFlags(launchFlags);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 50fe042..1fb7cd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -553,7 +553,7 @@
assertTrue(mWm.mInputManager.transferTouchFocus(new InputChannel(),
new InputChannel(), true /* isDragDrop */));
mToken = mTarget.performDrag(TEST_PID, 0, mWindow.mClient,
- flag, surface, 0, 0, 0, 0, 0, data);
+ flag, surface, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
@@ -575,7 +575,7 @@
private void startA11yDrag(int flags, ClipData data, Runnable r) {
mToken = mTarget.performDrag(0, 0, mWindow.mClient,
- flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, data);
+ flags | View.DRAG_FLAG_ACCESSIBILITY_ACTION, null, 0, 0, 0, 0, 0, 0, 0, data);
assertNotNull(mToken);
r.run();
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 6e4f13a..c902d459 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1569,13 +1569,13 @@
@Override
@EnforcePermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION)
- public void setIsReceiveSandboxedTrainingDataAllowed(boolean allowed) {
- super.setIsReceiveSandboxedTrainingDataAllowed_enforcePermission();
+ public void setShouldReceiveSandboxedTrainingData(boolean allowed) {
+ super.setShouldReceiveSandboxedTrainingData_enforcePermission();
synchronized (this) {
if (mImpl == null) {
throw new IllegalStateException(
- "setIsReceiveSandboxedTrainingDataAllowed without running voice "
+ "setShouldReceiveSandboxedTrainingData without running voice "
+ "interaction service");
}
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index eac4d16..cc768bc 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -16,12 +16,16 @@
package android.telephony;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.TelephonyManager.CarrierRestrictionStatus;
+
+import com.android.internal.telephony.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -104,7 +108,7 @@
private int mCarrierRestrictionDefault;
@MultiSimPolicy
private int mMultiSimPolicy;
- @TelephonyManager.CarrierRestrictionStatus
+ @CarrierRestrictionStatus
private int mCarrierRestrictionStatus;
private CarrierRestrictionRules() {
@@ -293,8 +297,22 @@
return true;
}
- /** @hide */
- public int getCarrierRestrictionStatus() {
+ /**
+ * Get the carrier restriction status of the device.
+ * The return value of the API is as follows.
+ * <ul>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED_TO_CALLER}
+ * if the caller and the device locked by the network are same</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_RESTRICTED} if the
+ * caller and the device locked by the network are different</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_NOT_RESTRICTED} if the
+ * device is not locked</li>
+ * <li>return {@link TelephonyManager#CARRIER_RESTRICTION_STATUS_UNKNOWN} if the device
+ * locking state is unavailable or radio does not supports the feature</li>
+ * </ul>
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_RESTRICTION_STATUS)
+ public @CarrierRestrictionStatus int getCarrierRestrictionStatus() {
return mCarrierRestrictionStatus;
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 3e87872..8679bd4 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1866,7 +1866,7 @@
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
private int mSkip464Xlat = Carriers.SKIP_464XLAT_DEFAULT;
private boolean mAlwaysOn;
- private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR;
+ private int mInfrastructureBitmask = INFRASTRUCTURE_CELLULAR | INFRASTRUCTURE_SATELLITE;
private boolean mEsimBootstrapProvisioning;
/**
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index 12a57d5..c8cac8f 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -25,6 +25,7 @@
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.LegacyFlickerTest
import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
@@ -142,7 +143,7 @@
}
/** During the transition Secondary Activity shrinks to the bottom right corner. */
- @Presubmit
+ @FlakyTest(bugId = 315605409)
@Test
fun secondaryLayerShrinks() {
flicker.assertLayers {