Merge "Add hotword detection metrics." into tm-dev
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 66767e2..da429af 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -210,6 +210,8 @@
* on how frequently it can be scheduled. Only available (and automatically applied) to
* system alarms.
*
+ * <p>Note that alarms set with a {@link WorkSource} <b>do not</b> get this flag.
+ *
* @hide
*/
@UnsupportedAppUsage
diff --git a/core/api/current.txt b/core/api/current.txt
index 542221c..c80c4cb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -113,8 +113,9 @@
field public static final String MANAGE_MEDIA = "android.permission.MANAGE_MEDIA";
field public static final String MANAGE_ONGOING_CALLS = "android.permission.MANAGE_ONGOING_CALLS";
field public static final String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS";
- field public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
+ field @Deprecated public static final String MANAGE_WIFI_AUTO_JOIN = "android.permission.MANAGE_WIFI_AUTO_JOIN";
field public static final String MANAGE_WIFI_INTERFACES = "android.permission.MANAGE_WIFI_INTERFACES";
+ field public static final String MANAGE_WIFI_NETWORK_SELECTION = "android.permission.MANAGE_WIFI_NETWORK_SELECTION";
field public static final String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
field public static final String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL";
field public static final String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
@@ -3335,7 +3336,7 @@
}
public class InputMethod {
- ctor protected InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
+ ctor public InputMethod(@NonNull android.accessibilityservice.AccessibilityService);
method @Nullable public final android.accessibilityservice.InputMethod.AccessibilityInputConnection getCurrentInputConnection();
method @Nullable public final android.view.inputmethod.EditorInfo getCurrentInputEditorInfo();
method public final boolean getCurrentInputStarted();
@@ -4275,7 +4276,6 @@
method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
method public final void setMediaController(android.media.session.MediaController);
method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
- method public void setPreferDockBigOverlays(boolean);
method @Deprecated public final void setProgress(int);
method @Deprecated public final void setProgressBarIndeterminate(boolean);
method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
@@ -4285,6 +4285,7 @@
method public final void setResult(int);
method public final void setResult(int, android.content.Intent);
method @Deprecated public final void setSecondaryProgress(int);
+ method public void setShouldDockBigOverlays(boolean);
method public void setShowWhenLocked(boolean);
method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
method public void setTitle(CharSequence);
@@ -4295,6 +4296,7 @@
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
method public void setVrModeEnabled(boolean, @NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public boolean shouldDockBigOverlays();
method public boolean shouldShowRequestPermissionRationale(@NonNull String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -7437,7 +7439,7 @@
method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
method @Nullable public java.util.List<java.lang.String> getPermittedInputMethods(@NonNull android.content.ComponentName);
method public int getPersonalAppsSuspendedReasons(@NonNull android.content.ComponentName);
- method @NonNull public android.app.admin.PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
+ method @NonNull public java.util.List<android.app.admin.PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
method public int getRequiredPasswordComplexity();
method public long getRequiredStrongAuthTimeout(@Nullable android.content.ComponentName);
method public boolean getScreenCaptureDisabled(@Nullable android.content.ComponentName);
@@ -7582,7 +7584,7 @@
method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
method public boolean setPermittedInputMethods(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
method public void setPersonalAppsSuspended(@NonNull android.content.ComponentName, boolean);
- method public void setPreferentialNetworkServiceConfig(@NonNull android.app.admin.PreferentialNetworkServiceConfig);
+ method public void setPreferentialNetworkServiceConfigs(@NonNull java.util.List<android.app.admin.PreferentialNetworkServiceConfig>);
method public void setPreferentialNetworkServiceEnabled(boolean);
method public void setProfileEnabled(@NonNull android.content.ComponentName);
method public void setProfileName(@NonNull android.content.ComponentName, String);
@@ -26063,11 +26065,9 @@
public static final class AppLinkInfo.Builder {
ctor public AppLinkInfo.Builder(@NonNull String, @NonNull String);
method @NonNull public android.media.tv.interactive.AppLinkInfo build();
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setClassName(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setPackageName(@NonNull String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriHost(@Nullable String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriPrefix(@Nullable String);
- method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@Nullable String);
+ method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriHost(@NonNull String);
+ method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriPrefix(@NonNull String);
+ method @NonNull public android.media.tv.interactive.AppLinkInfo.Builder setUriScheme(@NonNull String);
}
public final class TvInteractiveAppInfo implements android.os.Parcelable {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 27ca6a2..7aef9a6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -102,6 +102,7 @@
public abstract class PackageManager {
method @NonNull public String getPermissionControllerPackageName();
method @NonNull public String getSdkSandboxPackageName();
+ field public static final String EXTRA_VERIFICATION_ROOT_HASH = "android.content.pm.extra.VERIFICATION_ROOT_HASH";
field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
}
@@ -359,8 +360,8 @@
}
public class Process {
+ method public static final int getAppUidForSdkSandboxUid(int);
method public static final boolean isSdkSandboxUid(int);
- method public static final int sdkSandboxToAppUid(int);
method public static final int toSdkSandboxUid(int);
field public static final int NFC_UID = 1027; // 0x403
field public static final int VPN_UID = 1016; // 0x3f8
@@ -454,6 +455,14 @@
}
+package android.telecom {
+
+ public abstract class ConnectionService extends android.app.Service {
+ method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.Connection onCreateUnknownConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
+ }
+
+}
+
package android.telephony {
public abstract class CellSignalStrength {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5a6e8ee..5f2dcb3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -469,7 +469,6 @@
method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
method @Deprecated public boolean isBackgroundVisibleBehind();
method @Deprecated public void onBackgroundVisibleBehindChanged(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityAsUser(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public void startActivityForResultAsUser(@NonNull android.content.Intent, @NonNull String, int, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
@@ -1650,13 +1649,13 @@
public final class SearchRequest implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public String getCallerPackageName();
method public float getMaxLatencyMillis();
method @NonNull public String getQuery();
method @NonNull public String getRequestId();
method public int getResultNumber();
method public int getResultOffset();
method @NonNull public android.os.Bundle getSearchConstraints();
- method @NonNull public String getSource();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
@@ -1704,6 +1703,7 @@
field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_TEXT";
field public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
+ field public static final String EXTRAINFO_APP_CARD_ACTION = "android.app.cloudsearch.APP_CARD_ACTION";
field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
field public static final String EXTRAINFO_APP_DEVELOPER_NAME = "android.app.cloudsearch.APP_DEVELOPER_NAME";
@@ -1713,6 +1713,7 @@
field public static final String EXTRAINFO_APP_REVIEW_COUNT = "android.app.cloudsearch.APP_REVIEW_COUNT";
field public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
field public static final String EXTRAINFO_APP_STAR_RATING = "android.app.cloudsearch.APP_STAR_RATING";
+ field public static final String EXTRAINFO_INSTALL_BUTTON_ACTION = "android.app.cloudsearch.INSTALL_BUTTON_ACTION";
field public static final String EXTRAINFO_LONG_DESCRIPTION = "android.app.cloudsearch.LONG_DESCRIPTION";
field public static final String EXTRAINFO_SCREENSHOTS = "android.app.cloudsearch.SCREENSHOTS";
field public static final String EXTRAINFO_SHORT_DESCRIPTION = "android.app.cloudsearch.SHORT_DESCRIPTION";
@@ -2948,6 +2949,7 @@
method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[], @Nullable android.app.BroadcastOptions);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle, @NonNull android.os.UserHandle);
field public static final String AMBIENT_CONTEXT_SERVICE = "ambient_context";
field public static final String APP_HIBERNATION_SERVICE = "app_hibernation";
field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
@@ -6946,7 +6948,7 @@
}
public class Lnb implements java.lang.AutoCloseable {
- method public void addCallback(@NonNull android.media.tv.tuner.LnbCallback, @NonNull java.util.concurrent.Executor);
+ method public void addCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.LnbCallback);
method public void close();
method public boolean removeCallback(@NonNull android.media.tv.tuner.LnbCallback);
method public int sendDiseqcMessage(@NonNull byte[]);
@@ -8547,7 +8549,7 @@
public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.net.IpConfiguration getIpConfiguration();
- method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method @Nullable public android.net.NetworkCapabilities getNetworkCapabilities();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
}
@@ -8557,7 +8559,7 @@
ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest);
method @NonNull public android.net.EthernetNetworkUpdateRequest build();
method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration);
- method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
+ method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
}
public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
@@ -9030,6 +9032,7 @@
method public void enableVerboseLogging(boolean);
method @NonNull public int[] getChannelsMhzForBand(int);
method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String);
+ method public int getMaxNumScanSsids(@NonNull String);
method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int);
method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String);
method public void notifyCountryCodeChanged(@Nullable String);
@@ -9819,7 +9822,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
method public boolean isCloneProfile();
- method public boolean isCredentialSharedWithParent();
+ method public boolean isCredentialSharableWithParent();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isGuestUser();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isManagedProfile(int);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isMediaSharedWithParent();
@@ -10580,7 +10583,6 @@
field public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled";
field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
field public static final String DOZE_ALWAYS_ON = "doze_always_on";
- field public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
field public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled";
field public static final String LAST_SETUP_SHOWN = "last_setup_shown";
@@ -11405,7 +11407,7 @@
public static interface GameSession.ScreenshotCallback {
method public void onFailure(int);
- method public void onSuccess(@NonNull android.graphics.Bitmap);
+ method public void onSuccess();
field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
}
@@ -12217,7 +12219,6 @@
public abstract class ConnectionService extends android.app.Service {
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telecom.Connection onCreateUnknownConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.ConnectionRequest);
}
public abstract class InCallService extends android.app.Service {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index c5cce35..2eb0f19 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -422,9 +422,9 @@
method @NonNull public android.content.res.Configuration getConfiguration();
method public int getParentTaskId();
method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams();
- method public boolean getPreferDockBigOverlays();
method @NonNull public android.window.WindowContainerToken getToken();
method public boolean hasParentTask();
+ method public boolean shouldDockBigOverlays();
}
public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
@@ -622,7 +622,7 @@
package android.app.cloudsearch {
public static final class SearchRequest.Builder {
- method @NonNull public android.app.cloudsearch.SearchRequest.Builder setSource(@NonNull String);
+ method @NonNull public android.app.cloudsearch.SearchRequest.Builder setCallerPackageName(@NonNull String);
}
}
@@ -1791,9 +1791,9 @@
}
public class Process {
+ method public static final int getAppUidForSdkSandboxUid(int);
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
method public static final boolean isSdkSandboxUid(int);
- method public static final int sdkSandboxToAppUid(int);
method public static final int toSdkSandboxUid(int);
field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
@@ -1801,6 +1801,7 @@
field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
field public static final int NFC_UID = 1027; // 0x403
field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
+ field public static final int SDK_SANDBOX_VIRTUAL_UID = 1090; // 0x442
}
public final class StrictMode {
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index c82f5f6..3cb04e7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -825,17 +825,7 @@
for (int i = 0; i < mMagnificationControllers.size(); i++) {
mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
}
- AccessibilityServiceInfo info = getServiceInfo();
- if (info != null) {
- boolean requestIme = (info.flags
- & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
- if (requestIme && !mInputMethodInitialized) {
- mInputMethod = onCreateInputMethod();
- mInputMethodInitialized = true;
- }
- } else {
- Log.e(LOG_TAG, "AccessibilityServiceInfo is null in dispatchServiceConnected");
- }
+ updateInputMethod(getServiceInfo());
}
if (mSoftKeyboardController != null) {
mSoftKeyboardController.onServiceConnected();
@@ -846,6 +836,20 @@
onServiceConnected();
}
+ private void updateInputMethod(AccessibilityServiceInfo info) {
+ if (info != null) {
+ boolean requestIme = (info.flags
+ & AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
+ if (requestIme && !mInputMethodInitialized) {
+ mInputMethod = onCreateInputMethod();
+ mInputMethodInitialized = true;
+ } else if (!requestIme & mInputMethodInitialized) {
+ mInputMethod = null;
+ mInputMethodInitialized = false;
+ }
+ }
+ }
+
/**
* This method is a part of the {@link AccessibilityService} lifecycle and is
* called after the system has successfully bound to the service. If is
@@ -2521,6 +2525,7 @@
*/
public final void setServiceInfo(AccessibilityServiceInfo info) {
mInfo = info;
+ updateInputMethod(info);
sendServiceInfo();
}
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index 001d804..36cfd0e 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -67,7 +67,7 @@
private InputConnection mStartedInputConnection;
private EditorInfo mInputEditorInfo;
- protected InputMethod(@NonNull AccessibilityService service) {
+ public InputMethod(@NonNull AccessibilityService service) {
mService = service;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8f348a4..ec9bb26 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -984,6 +984,8 @@
private boolean mIsInMultiWindowMode;
private boolean mIsInPictureInPictureMode;
+ private boolean mShouldDockBigOverlays;
+
private UiTranslationController mUiTranslationController;
private SplashScreen mSplashScreen;
@@ -2977,13 +2979,28 @@
* <p> If specified, the system will try to respect the preference, but it may be
* overridden by a user preference.
*
- * @param preferDockBigOverlays indicates that the activity prefers big overlays to be
- * docked next to it instead of overlaying its content
+ * @param shouldDockBigOverlays indicates that big overlays should be docked next to the
+ * activity instead of overlay its content
*
* @see PictureInPictureParams.Builder#setExpandedAspectRatio
+ * @see #shouldDockBigOverlays
*/
- public void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
- ActivityClient.getInstance().setPreferDockBigOverlays(mToken, preferDockBigOverlays);
+ public void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+ ActivityClient.getInstance().setShouldDockBigOverlays(mToken, shouldDockBigOverlays);
+ mShouldDockBigOverlays = shouldDockBigOverlays;
+ }
+
+ /**
+ * Returns whether big overlays should be docked next to the activity as set by
+ * {@link #setShouldDockBigOverlays}.
+ *
+ * @return {@code true} if big overlays should be docked next to the activity instead
+ * of overlay its content
+ *
+ * @see #setShouldDockBigOverlays
+ */
+ public boolean shouldDockBigOverlays() {
+ return mShouldDockBigOverlays;
}
void dispatchMovedToDisplay(int displayId, Configuration config) {
@@ -5663,7 +5680,6 @@
* @throws ActivityNotFoundException
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {INTERACT_ACROSS_USERS, INTERACT_ACROSS_USERS_FULL})
public void startActivityAsUser(@NonNull Intent intent,
@Nullable Bundle options, @NonNull UserHandle user) {
@@ -8249,6 +8265,7 @@
.getWindowingMode();
mIsInMultiWindowMode = inMultiWindowMode(windowingMode);
mIsInPictureInPictureMode = windowingMode == WINDOWING_MODE_PINNED;
+ mShouldDockBigOverlays = getResources().getBoolean(R.bool.config_dockBigOverlayWindows);
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index cf8480c..7b7b1ef 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -324,9 +324,9 @@
}
}
- void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
try {
- getActivityClientController().setPreferDockBigOverlays(token, preferDockBigOverlays);
+ getActivityClientController().setShouldDockBigOverlays(token, shouldDockBigOverlays);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 64f0301..b1a4e41 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3587,7 +3587,7 @@
}
try {
- Application app = r.packageInfo.makeApplication(false, mInstrumentation);
+ Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
@@ -4286,7 +4286,7 @@
BroadcastReceiver receiver;
ContextImpl context;
try {
- app = packageInfo.makeApplication(false, mInstrumentation);
+ app = packageInfo.makeApplicationInner(false, mInstrumentation);
context = (ContextImpl) app.getBaseContext();
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
@@ -4475,7 +4475,7 @@
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
- Application app = packageInfo.makeApplication(false, mInstrumentation);
+ Application app = packageInfo.makeApplicationInner(false, mInstrumentation);
final java.lang.ClassLoader cl;
if (data.info.splitName != null) {
@@ -6695,7 +6695,7 @@
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
- app = data.info.makeApplication(data.restrictedBackupMode, null);
+ app = data.info.makeApplicationInner(data.restrictedBackupMode, null);
// Propagate autofill compat state
app.setAutofillOptions(data.autofillOptions);
@@ -7565,7 +7565,7 @@
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
- mInitialApplication = context.mPackageInfo.makeApplication(true, null);
+ mInitialApplication = context.mPackageInfo.makeApplicationInner(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 60e22f4..9bdddd0 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -360,6 +360,53 @@
*/
public static final int SUBREASON_FREEZER_BINDER_TRANSACTION = 20;
+ /**
+ * The process was killed because of force-stop, it could be due to that
+ * the user clicked the "Force stop" button of the application in the Settings;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_FORCE_STOP = 21;
+
+ /**
+ * The process was killed because the user removed the application away from Recents;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_REMOVE_TASK = 22;
+
+ /**
+ * The process was killed because the user stopped the application from the task manager;
+ * this would be set only when the reason is {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_STOP_APP = 23;
+
+ /**
+ * The process was killed because the user stopped the application from developer options,
+ * or via the adb shell commmand interface; this would be set only when the reason is
+ * {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_KILL_BACKGROUND = 24;
+
+ /**
+ * The process was killed because of package update; this would be set only when the reason is
+ * {@link #REASON_USER_REQUESTED}.
+ *
+ * For internal use only.
+ * @hide
+ */
+ public static final int SUBREASON_PACKAGE_UPDATE = 25;
+
// If there is any OEM code which involves additional app kill reasons, it should
// be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000.
@@ -520,6 +567,11 @@
SUBREASON_ISOLATED_NOT_NEEDED,
SUBREASON_FREEZER_BINDER_IOCTL,
SUBREASON_FREEZER_BINDER_TRANSACTION,
+ SUBREASON_FORCE_STOP,
+ SUBREASON_REMOVE_TASK,
+ SUBREASON_STOP_APP,
+ SUBREASON_KILL_BACKGROUND,
+ SUBREASON_PACKAGE_UPDATE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface SubReason {}
@@ -1193,6 +1245,16 @@
return "FREEZER BINDER IOCTL";
case SUBREASON_FREEZER_BINDER_TRANSACTION:
return "FREEZER BINDER TRANSACTION";
+ case SUBREASON_FORCE_STOP:
+ return "FORCE STOP";
+ case SUBREASON_REMOVE_TASK:
+ return "REMOVE TASK";
+ case SUBREASON_STOP_APP:
+ return "STOP APP";
+ case SUBREASON_KILL_BACKGROUND:
+ return "KILL BACKGROUND";
+ case SUBREASON_PACKAGE_UPDATE:
+ return "PACKAGE UPDATE";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index caf1c41b7..1307161 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -88,7 +88,7 @@
boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
- oneway void setPreferDockBigOverlays(in IBinder token, in boolean preferDockBigOverlays);
+ oneway void setShouldDockBigOverlays(in IBinder token, in boolean shouldDockBigOverlays);
void toggleFreeformWindowingMode(in IBinder token);
oneway void startLockTaskModeByToken(in IBinder token);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index cf259e57..d35c5be 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1352,9 +1352,28 @@
return mResources;
}
+ /**
+ * This is for 3p apps accessing this hidden API directly... in which case, we don't return
+ * the cached Application instance.
+ */
@UnsupportedAppUsage
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
+ return makeApplicationInner(forceDefaultAppClass, instrumentation,
+ /* allowDuplicateInstances= */ true);
+ }
+
+ /**
+ * This is for all the (internal) callers, for which we do return the cached instance.
+ */
+ public Application makeApplicationInner(boolean forceDefaultAppClass,
+ Instrumentation instrumentation) {
+ return makeApplicationInner(forceDefaultAppClass, instrumentation,
+ /* allowDuplicateInstances= */ false);
+ }
+
+ private Application makeApplicationInner(boolean forceDefaultAppClass,
+ Instrumentation instrumentation, boolean allowDuplicateInstances) {
if (mApplication != null) {
return mApplication;
}
@@ -1366,11 +1385,15 @@
// Looks like this is always happening for the system server, because
// the LoadedApk created in systemMain() -> attach() isn't cached properly?
if (!"android".equals(mPackageName)) {
- Slog.wtf(TAG, "App instance already created for package=" + mPackageName
+ Slog.wtfStack(TAG, "App instance already created for package=" + mPackageName
+ " instance=" + cached);
}
- mApplication = cached;
- return cached;
+ if (!allowDuplicateInstances) {
+ mApplication = cached;
+ return cached;
+ }
+ // Some apps intentionally call makeApplication() to create a new Application
+ // instance... Sigh...
}
}
@@ -1421,8 +1444,10 @@
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
- synchronized (sApplications) {
- sApplications.put(mPackageName, app);
+ if (!allowDuplicateInstances) {
+ synchronized (sApplications) {
+ sApplications.put(mPackageName, app);
+ }
}
if (instrumentation != null) {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 5c7c73c..1a38fcf 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -188,7 +188,7 @@
/**
* @hide
*/
- public boolean preferDockBigOverlays;
+ public boolean shouldDockBigOverlays;
/**
* The task id of the host Task of the launch-into-pip Activity, i.e., it points to the Task
@@ -392,8 +392,8 @@
/** @hide */
@TestApi
- public boolean getPreferDockBigOverlays() {
- return preferDockBigOverlays;
+ public boolean shouldDockBigOverlays() {
+ return shouldDockBigOverlays;
}
/** @hide */
@@ -465,7 +465,7 @@
&& displayAreaFeatureId == that.displayAreaFeatureId
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
- && Objects.equals(preferDockBigOverlays, that.preferDockBigOverlays)
+ && Objects.equals(shouldDockBigOverlays, that.shouldDockBigOverlays)
&& Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
@@ -522,7 +522,7 @@
token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
- preferDockBigOverlays = source.readBoolean();
+ shouldDockBigOverlays = source.readBoolean();
launchIntoPipHostTaskId = source.readInt();
displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
@@ -569,7 +569,7 @@
token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
dest.writeTypedObject(pictureInPictureParams, flags);
- dest.writeBoolean(preferDockBigOverlays);
+ dest.writeBoolean(shouldDockBigOverlays);
dest.writeInt(launchIntoPipHostTaskId);
dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
@@ -610,7 +610,7 @@
+ " token=" + token
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
- + " preferDockBigOverlays=" + preferDockBigOverlays
+ + " shouldDockBigOverlays=" + shouldDockBigOverlays
+ " launchIntoPipHostTaskId=" + launchIntoPipHostTaskId
+ " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 8d4e0d6..4c7b910 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,8 @@
package android.app.admin;
+import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
@@ -11031,7 +11033,7 @@
}
/**
- * Sets whether preferential network service is enabled on the work profile.
+ * Sets whether preferential network service is enabled.
* For example, an organization can have a deal/agreement with a carrier that all of
* the work data from its employees’ devices will be sent via a network service dedicated
* for enterprise use.
@@ -11039,75 +11041,72 @@
* An example of a supported preferential network service is the Enterprise
* slice on 5G networks.
*
- * By default, preferential network service is disabled on the work profile on supported
- * carriers and devices. Admins can explicitly enable it with this API.
- * On fully-managed devices this method is unsupported because all traffic is considered
- * work traffic.
+ * By default, preferential network service is disabled on the work profile and
+ * fully managed devices, on supported carriers and devices.
+ * Admins can explicitly enable it with this API.
*
* <p> This method enables preferential network service with a default configuration.
- * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfig) instead.
+ * To fine-tune the configuration, use {@link #setPreferentialNetworkServiceConfigs) instead.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * this method can be called by the profile owner of a managed profile.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile
+ * or device owner.
*
- * <p>This method can only be called by the profile owner of a managed profile.
* @param enabled whether preferential network service should be enabled.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
**/
public void setPreferentialNetworkServiceEnabled(boolean enabled) {
throwIfParentInstance("setPreferentialNetworkServiceEnabled");
- if (mService == null) {
- return;
+ PreferentialNetworkServiceConfig.Builder configBuilder =
+ new PreferentialNetworkServiceConfig.Builder();
+ configBuilder.setEnabled(enabled);
+ if (enabled) {
+ configBuilder.setNetworkId(NET_ENTERPRISE_ID_1);
}
-
- try {
- mService.setPreferentialNetworkServiceEnabled(enabled);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ setPreferentialNetworkServiceConfigs(List.of(configBuilder.build()));
}
/**
* Indicates whether preferential network service is enabled.
*
- * <p>This method can be called by the profile owner of a managed profile.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * This method can be called by the profile owner of a managed profile
+ * or device owner.
*
* @return whether preferential network service is enabled.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
*/
public boolean isPreferentialNetworkServiceEnabled() {
throwIfParentInstance("isPreferentialNetworkServiceEnabled");
- if (mService == null) {
- return false;
- }
- try {
- return mService.isPreferentialNetworkServiceEnabled(myUserId());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getPreferentialNetworkServiceConfigs().stream().anyMatch(c -> c.isEnabled());
}
/**
- * Sets preferential network configuration on the work profile.
+ * Sets preferential network configurations.
* {@see PreferentialNetworkServiceConfig}
*
* An example of a supported preferential network service is the Enterprise
* slice on 5G networks.
*
- * By default, preferential network service is disabled on the work profile on supported
- * carriers and devices. Admins can explicitly enable it with this API.
- * On fully-managed devices this method is unsupported because all traffic is considered
- * work traffic.
+ * By default, preferential network service is disabled on the work profile and fully managed
+ * devices, on supported carriers and devices. Admins can explicitly enable it with this API.
+ * If admin wants to have multiple enterprise slices,
+ * it can be configured by passing list of {@link PreferentialNetworkServiceConfig} objects.
*
- * <p>This method can only be called by the profile owner of a managed profile.
- * @param preferentialNetworkServiceConfig preferential network configuration.
- * @throws SecurityException if the caller is not the profile owner.
+ * @param preferentialNetworkServiceConfigs list of preferential network configurations.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
**/
- public void setPreferentialNetworkServiceConfig(
- @NonNull PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- throwIfParentInstance("setPreferentialNetworkServiceConfig");
+ public void setPreferentialNetworkServiceConfigs(
+ @NonNull List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
+ throwIfParentInstance("setPreferentialNetworkServiceConfigs");
if (mService == null) {
return;
}
try {
- mService.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfig);
+ mService.setPreferentialNetworkServiceConfigs(preferentialNetworkServiceConfigs);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -11117,18 +11116,16 @@
* Get preferential network configuration
* {@see PreferentialNetworkServiceConfig}
*
- * <p>This method can be called by the profile owner of a managed profile.
- *
* @return preferential network configuration.
- * @throws SecurityException if the caller is not the profile owner.
+ * @throws SecurityException if the caller is not the profile owner or device owner.
*/
- public @NonNull PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
- throwIfParentInstance("getPreferentialNetworkServiceConfig");
+ public @NonNull List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs() {
+ throwIfParentInstance("getPreferentialNetworkServiceConfigs");
if (mService == null) {
- return PreferentialNetworkServiceConfig.DEFAULT;
+ return List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
try {
- return mService.getPreferentialNetworkServiceConfig();
+ return mService.getPreferentialNetworkServiceConfigs();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13612,13 +13609,18 @@
}
/**
- * Called by device owner to add an override APN.
+ * Called by device owner or profile owner to add an override APN.
*
* <p>This method may returns {@code -1} if {@code apnSetting} conflicts with an existing
* override APN. Update the existing conflicted APN with
* {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry.
* <p>Two override APNs are considered to conflict when all the following APIs return
* the same values on both override APNs:
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can add APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can add enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can add other type of APNs.
* <ul>
* <li>{@link ApnSetting#getOperatorNumeric()}</li>
* <li>{@link ApnSetting#getApnName()}</li>
@@ -13637,7 +13639,8 @@
* @param apnSetting the override APN to insert
* @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into
* the database.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
@@ -13654,20 +13657,26 @@
}
/**
- * Called by device owner to update an override APN.
+ * Called by device owner or profile owner to update an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
* <p>This method may also returns {@code false} if {@code apnSetting} conflicts with an
* existing override APN. Update the existing conflicted APN instead.
* <p>See {@link #addOverrideApn} for the definition of conflict.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can update APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can update enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can update other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to update
* @param apnSetting the override APN to update
* @return {@code true} if the required override APN is successfully updated,
* {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
@@ -13685,16 +13694,22 @@
}
/**
- * Called by device owner to remove an override APN.
+ * Called by device owner or profile owner to remove an override APN.
*
* <p>This method may returns {@code false} if there is no override APN with the given
* {@code apnId}.
+ * <p> Before Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Only device owners can remove APNs.
+ * <p> Starting from Android version {@link android.os.Build.VERSION_CODES#TIRAMISU}:
+ * Device and profile owners can remove enterprise APNs
+ * ({@link ApnSetting#TYPE_ENTERPRISE}), while only device owners can remove other type of APNs.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with
* @param apnId the {@code id} of the override APN to remove
* @return {@code true} if the required override APN is successfully removed, {@code false}
* otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * @throws SecurityException If request is for enterprise APN {@code admin} is either device
+ * owner or profile owner and in all other types of APN if {@code admin} is not a device owner.
*
* @see #setOverrideApnsEnabled(ComponentName, boolean)
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9d28dde..77db146 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -285,12 +285,9 @@
void setSecondaryLockscreenEnabled(in ComponentName who, boolean enabled);
boolean isSecondaryLockscreenEnabled(in UserHandle userHandle);
- void setPreferentialNetworkServiceEnabled(in boolean enabled);
- boolean isPreferentialNetworkServiceEnabled(int userHandle);
-
- void setPreferentialNetworkServiceConfig(
- in PreferentialNetworkServiceConfig preferentialNetworkServiceConfig);
- PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig();
+ void setPreferentialNetworkServiceConfigs(
+ in List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs);
+ List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs();
void setLockTaskPackages(in ComponentName who, in String[] packages);
String[] getLockTaskPackages(in ComponentName who);
diff --git a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
index 2849139..54170a2 100644
--- a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -28,7 +28,7 @@
/**
* Network configuration to be set for the user profile
- * {@see DevicePolicyManager#setPreferentialNetworkServiceConfig}.
+ * {@see DevicePolicyManager#setPreferentialNetworkServiceConfigs}.
*/
public final class PreferentialNetworkServiceConfig implements Parcelable {
final boolean mIsEnabled;
@@ -147,8 +147,6 @@
/**
* @return preference enterprise identifier.
- * valid values starts from
- * {@link #PREFERENTIAL_NETWORK_ID_1} to {@link #PREFERENTIAL_NETWORK_ID_5}.
* preference identifier is applicable only if preference network service is enabled
*
*/
@@ -286,8 +284,6 @@
/**
* Set the preferential network identifier.
- * Valid values starts from {@link #PREFERENTIAL_NETWORK_ID_1} to
- * {@link #PREFERENTIAL_NETWORK_ID_5}.
* preference identifier is applicable only if preferential network service is enabled.
* @param preferenceId preference Id
* @return The builder to facilitate chaining.
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index 4d6507a..bf78325 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -100,7 +100,7 @@
*
*/
@NonNull
- private String mSource;
+ private String mCallerPackageName;
private SearchRequest(Parcel in) {
this.mQuery = in.readString();
@@ -109,17 +109,17 @@
this.mMaxLatencyMillis = in.readFloat();
this.mSearchConstraints = in.readBundle();
this.mId = in.readString();
- this.mSource = in.readString();
+ this.mCallerPackageName = in.readString();
}
private SearchRequest(String query, int resultOffset, int resultNumber, float maxLatencyMillis,
- Bundle searchConstraints, String source) {
+ Bundle searchConstraints, String callerPackageName) {
mQuery = query;
mResultOffset = resultOffset;
mResultNumber = resultNumber;
mMaxLatencyMillis = maxLatencyMillis;
mSearchConstraints = searchConstraints;
- mSource = source;
+ mCallerPackageName = callerPackageName;
}
/** Returns the original query. */
@@ -151,8 +151,8 @@
/** Gets the caller's package name. */
@NonNull
- public String getSource() {
- return mSource;
+ public String getCallerPackageName() {
+ return mCallerPackageName;
}
/** Returns the search request id, which is used to identify the request. */
@@ -169,8 +169,8 @@
*
* @hide
*/
- public void setSource(@NonNull String source) {
- this.mSource = source;
+ public void setCallerPackageName(@NonNull String callerPackageName) {
+ this.mCallerPackageName = callerPackageName;
}
private SearchRequest(Builder b) {
@@ -179,7 +179,7 @@
mResultNumber = b.mResultNumber;
mMaxLatencyMillis = b.mMaxLatencyMillis;
mSearchConstraints = requireNonNull(b.mSearchConstraints);
- mSource = requireNonNull(b.mSource);
+ mCallerPackageName = requireNonNull(b.mCallerPackageName);
}
/**
@@ -207,7 +207,7 @@
dest.writeFloat(this.mMaxLatencyMillis);
dest.writeBundle(this.mSearchConstraints);
dest.writeString(getRequestId());
- dest.writeString(this.mSource);
+ dest.writeString(this.mCallerPackageName);
}
@Override
@@ -231,7 +231,7 @@
&& mResultNumber == that.mResultNumber
&& mMaxLatencyMillis == that.mMaxLatencyMillis
&& Objects.equals(mSearchConstraints, that.mSearchConstraints)
- && Objects.equals(mSource, that.mSource);
+ && Objects.equals(mCallerPackageName, that.mCallerPackageName);
}
@Override
@@ -246,14 +246,15 @@
}
return String.format("SearchRequest: {query:%s,offset:%d;number:%d;max_latency:%f;"
- + "is_presubmit:%b;search_provider:%s;source:%s}", mQuery, mResultOffset,
- mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider, mSource);
+ + "is_presubmit:%b;search_provider:%s;callerPackageName:%s}", mQuery,
+ mResultOffset, mResultNumber, mMaxLatencyMillis, isPresubmit, searchProvider,
+ mCallerPackageName);
}
@Override
public int hashCode() {
return Objects.hash(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints, mSource);
+ mSearchConstraints, mCallerPackageName);
}
/**
@@ -268,7 +269,7 @@
private int mResultNumber;
private float mMaxLatencyMillis;
private Bundle mSearchConstraints;
- private String mSource;
+ private String mCallerPackageName;
/**
*
@@ -284,7 +285,7 @@
mResultNumber = 10;
mMaxLatencyMillis = 200;
mSearchConstraints = Bundle.EMPTY;
- mSource = "DEFAULT_CALLER";
+ mCallerPackageName = "DEFAULT_CALLER";
}
/** Sets the input query. */
@@ -329,8 +330,8 @@
*/
@NonNull
@TestApi
- public Builder setSource(@NonNull String source) {
- this.mSource = source;
+ public Builder setCallerPackageName(@NonNull String callerPackageName) {
+ this.mCallerPackageName = callerPackageName;
return this;
}
@@ -343,7 +344,7 @@
}
return new SearchRequest(mQuery, mResultOffset, mResultNumber, mMaxLatencyMillis,
- mSearchConstraints, mSource);
+ mSearchConstraints, mCallerPackageName);
}
}
}
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index af8adac..1ca01d4 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -71,6 +71,8 @@
EXTRAINFO_APP_BADGES,
EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING,
EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING,
+ EXTRAINFO_APP_CARD_ACTION,
+ EXTRAINFO_INSTALL_BUTTON_ACTION,
EXTRAINFO_WEB_URL,
EXTRAINFO_WEB_ICON})
public @interface SearchResultExtraInfoKey {}
@@ -119,6 +121,14 @@
@SuppressLint("IntentName")
public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING =
"android.app.cloudsearch.ACTION_BUTTON_IMAGE";
+ /** Intent for tapping the app card, PendingIntent expected. */
+ @SuppressLint("IntentName")
+ public static final String EXTRAINFO_APP_CARD_ACTION =
+ "android.app.cloudsearch.APP_CARD_ACTION";
+ /** Intent for tapping the install button, PendingIntent expected. */
+ @SuppressLint("IntentName")
+ public static final String EXTRAINFO_INSTALL_BUTTON_ACTION =
+ "android.app.cloudsearch.INSTALL_BUTTON_ACTION";
/** Web content's URL, String value expected. */
public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
/** Web content's domain icon, android.graphics.drawable.Icon expected. */
diff --git a/core/java/android/app/trust/TEST_MAPPING b/core/java/android/app/trust/TEST_MAPPING
new file mode 100644
index 0000000..b9c46bf
--- /dev/null
+++ b/core/java/android/app/trust/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 41b1a1f..cbb5183 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -28,6 +28,8 @@
import android.os.UserHandle;
import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -82,7 +84,7 @@
public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1;
private final int mLockState;
- private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
+ @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NonNull private final ArraySet<ComponentName> mAllowedActivities;
@NonNull private final ArraySet<ComponentName> mBlockedActivities;
@ActivityPolicy
@@ -94,10 +96,14 @@
@NonNull Set<ComponentName> allowedActivities,
@NonNull Set<ComponentName> blockedActivities,
@ActivityPolicy int defaultActivityPolicy) {
+ Preconditions.checkNotNull(usersWithMatchingAccounts);
+ Preconditions.checkNotNull(allowedActivities);
+ Preconditions.checkNotNull(blockedActivities);
+
mLockState = lockState;
mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
- mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
- mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
+ mAllowedActivities = new ArraySet<>(allowedActivities);
+ mBlockedActivities = new ArraySet<>(blockedActivities);
mDefaultActivityPolicy = defaultActivityPolicy;
}
@@ -130,30 +136,24 @@
}
/**
- * Returns the set of activities allowed to be streamed, or {@code null} if all activities are
+ * Returns the set of activities allowed to be streamed, or empty set if all activities are
* allowed, except the ones explicitly blocked.
*
* @see Builder#setAllowedActivities(Set)
*/
@NonNull
public Set<ComponentName> getAllowedActivities() {
- if (mAllowedActivities == null) {
- return Collections.emptySet();
- }
return Collections.unmodifiableSet(mAllowedActivities);
}
/**
- * Returns the set of activities that are blocked from streaming, or {@code null} to indicate
+ * Returns the set of activities that are blocked from streaming, or empty set to indicate
* that all activities in {@link #getAllowedActivities} are allowed.
*
* @see Builder#setBlockedActivities(Set)
*/
@NonNull
public Set<ComponentName> getBlockedActivities() {
- if (mBlockedActivities == null) {
- return Collections.emptySet();
- }
return Collections.unmodifiableSet(mBlockedActivities);
}
@@ -237,7 +237,7 @@
public static final class Builder {
private @LockState int mLockState = LOCK_STATE_DEFAULT;
- private Set<UserHandle> mUsersWithMatchingAccounts;
+ @NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();;
@NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
@NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
@ActivityPolicy
@@ -282,6 +282,7 @@
@NonNull
public Builder setUsersWithMatchingAccounts(
@NonNull Set<UserHandle> usersWithMatchingAccounts) {
+ Preconditions.checkNotNull(usersWithMatchingAccounts);
mUsersWithMatchingAccounts = usersWithMatchingAccounts;
return this;
}
@@ -301,6 +302,7 @@
*/
@NonNull
public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) {
+ Preconditions.checkNotNull(allowedActivities);
if (mDefaultActivityPolicyConfigured
&& mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) {
throw new IllegalArgumentException(
@@ -327,6 +329,7 @@
*/
@NonNull
public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) {
+ Preconditions.checkNotNull(blockedActivities);
if (mDefaultActivityPolicyConfigured
&& mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) {
throw new IllegalArgumentException(
@@ -343,9 +346,6 @@
*/
@NonNull
public VirtualDeviceParams build() {
- if (mUsersWithMatchingAccounts == null) {
- mUsersWithMatchingAccounts = Collections.emptySet();
- }
return new VirtualDeviceParams(
mLockState,
mUsersWithMatchingAccounts,
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2bda020..60efb4d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2011,9 +2011,9 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
- @UnsupportedAppUsage
- public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
- UserHandle userId) {
+ @SystemApi
+ public void startActivityAsUser(@RequiresPermission @NonNull Intent intent,
+ @Nullable Bundle options, @NonNull UserHandle userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 410e106..148eacc 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -79,6 +79,11 @@
public boolean debuggable;
/**
+ * Indicates if this apk is a sdk.
+ */
+ public boolean isSdkLibrary;
+
+ /**
* Specifies the recommended install location. Can be one of
* {@link InstallLocationUtils#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
* {@link InstallLocationUtils#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 3bdef50..450e09a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2433,15 +2433,6 @@
/** {@hide} */
private static final int[] NO_SESSIONS = {};
- /** @hide */
- @IntDef(prefix = { "SESSION_" }, value = {
- SESSION_NO_ERROR,
- SESSION_VERIFICATION_FAILED,
- SESSION_ACTIVATION_FAILED,
- SESSION_UNKNOWN_ERROR,
- SESSION_CONFLICT})
- @Retention(RetentionPolicy.SOURCE)
- public @interface SessionErrorCode {}
/**
* @deprecated use {@link #SESSION_NO_ERROR}.
*/
@@ -3125,7 +3116,7 @@
* If something went wrong with a staged session, clients can check this error code to
* understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
*/
- public @SessionErrorCode int getStagedSessionErrorCode() {
+ public int getStagedSessionErrorCode() {
checkSessionIsStaged();
return mSessionErrorCode;
}
@@ -3140,7 +3131,7 @@
}
/** {@hide} */
- public void setSessionErrorCode(@SessionErrorCode int errorCode, String errorMessage) {
+ public void setSessionErrorCode(int errorCode, String errorMessage) {
mSessionErrorCode = errorCode;
mSessionErrorMessage = errorMessage;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f4bc161..f9beaa7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -121,6 +121,9 @@
/** {@hide} */
public static final boolean APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = true;
+ /** {@hide} */
+ public static final boolean ENABLE_SHARED_UID_MIGRATION = true;
+
/**
* This exception is thrown when a given package, application, or component
* name cannot be found.
@@ -2202,6 +2205,14 @@
*/
public static final int INSTALL_FAILED_BAD_PERMISSION_GROUP = -127;
+ /**
+ * Installation failed return code: an error occurred during the activation phase of this
+ * session.
+ *
+ * @hide
+ */
+ public static final int INSTALL_ACTIVATION_FAILED = -128;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -4251,8 +4262,9 @@
* for more details.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String EXTRA_VERIFICATION_ROOT_HASH =
- "android.content.pm.extra.EXTRA_VERIFICATION_ROOT_HASH";
+ "android.content.pm.extra.VERIFICATION_ROOT_HASH";
/**
* Extra field name for the ID of a intent filter pending verification.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e914432..4d4a57d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1944,19 +1944,26 @@
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
- String str = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
- if (str != null && str.length() > 0) {
- String nameError = validateName(str, true, true);
- if (nameError != null && !"android".equals(pkg.packageName)) {
- outError[0] = "<manifest> specifies bad sharedUserId name \""
- + str + "\": " + nameError;
- mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
- return null;
+ int maxSdkVersion = 0;
+ if (PackageManager.ENABLE_SHARED_UID_MIGRATION) {
+ maxSdkVersion = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserMaxSdkVersion, 0);
+ }
+ if (maxSdkVersion == 0 || maxSdkVersion >= Build.VERSION.RESOURCES_SDK_INT) {
+ String str = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
+ if (str != null && str.length() > 0) {
+ String nameError = validateName(str, true, true);
+ if (nameError != null && !"android".equals(pkg.packageName)) {
+ outError[0] = "<manifest> specifies bad sharedUserId name \""
+ + str + "\": " + nameError;
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
+ return null;
+ }
+ pkg.mSharedUserId = str.intern();
+ pkg.mSharedUserLabel = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
- pkg.mSharedUserId = str.intern();
- pkg.mSharedUserLabel = sa.getResourceId(
- com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
pkg.installLocation = sa.getInteger(
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 5ffb958..269bec2 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -133,6 +133,11 @@
*/
private final boolean mHasDeviceAdminReceiver;
+ /**
+ * Indicates if this apk is a sdk.
+ */
+ private final boolean mIsSdkLibrary;
+
public ApkLite(String path, String packageName, String splitName, boolean isFeatureSplit,
String configForSplit, String usesSplitName, boolean isSplitRequired, int versionCode,
int versionCodeMajor, int revisionCode, int installLocation,
@@ -143,7 +148,7 @@
String requiredSystemPropertyName, String requiredSystemPropertyValue,
int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
Set<String> requiredSplitTypes, Set<String> splitTypes,
- boolean hasDeviceAdminReceiver) {
+ boolean hasDeviceAdminReceiver, boolean isSdkLibrary) {
mPath = path;
mPackageName = packageName;
mSplitName = splitName;
@@ -176,6 +181,7 @@
mTargetSdkVersion = targetSdkVersion;
mRollbackDataPolicy = rollbackDataPolicy;
mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
+ mIsSdkLibrary = isSdkLibrary;
}
/**
@@ -473,11 +479,19 @@
return mHasDeviceAdminReceiver;
}
+ /**
+ * Indicates if this apk is a sdk.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsSdkLibrary() {
+ return mIsSdkLibrary;
+ }
+
@DataClass.Generated(
- time = 1635266936769L,
+ time = 1643063342990L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 165cae8..5680bcd 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -87,6 +87,7 @@
private static final String TAG_USES_SDK = "uses-sdk";
private static final String TAG_USES_SPLIT = "uses-split";
private static final String TAG_MANIFEST = "manifest";
+ private static final String TAG_SDK_LIBRARY = "sdk-library";
private static final int SDK_VERSION = Build.VERSION.SDK_INT;
private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
@@ -449,6 +450,8 @@
boolean hasDeviceAdminReceiver = false;
+ boolean isSdkLibrary = false;
+
// Only search the tree when the tag is the direct child of <manifest> tag
int type;
final int searchDepth = parser.getDepth() + 1;
@@ -506,6 +509,8 @@
} else if (TAG_RECEIVER.equals(parser.getName())) {
hasDeviceAdminReceiver |= isDeviceAdminReceiver(
parser, hasBindDeviceAdminPermission);
+ } else if (TAG_SDK_LIBRARY.equals(parser.getName())) {
+ isSdkLibrary = true;
}
}
} else if (TAG_OVERLAY.equals(parser.getName())) {
@@ -598,7 +603,7 @@
overlayIsStatic, overlayPriority, requiredSystemPropertyName,
requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
- hasDeviceAdminReceiver));
+ hasDeviceAdminReceiver, isSdkLibrary));
}
private static boolean isDeviceAdminReceiver(
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 5f5e812..e2789c9 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -105,6 +105,10 @@
* or locally compiled variants.
*/
private final boolean mUseEmbeddedDex;
+ /**
+ * Indicates if this package is a sdk.
+ */
+ private final boolean mIsSdkLibrary;
public PackageLite(String path, String baseApkPath, ApkLite baseApk,
String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
@@ -131,6 +135,7 @@
mRequiredSplitTypes = requiredSplitTypes;
mSplitRequired = (baseApk.isSplitRequired() || hasAnyRequiredSplitTypes());
mProfileableByShell = baseApk.isProfileableByShell();
+ mIsSdkLibrary = baseApk.isIsSdkLibrary();
mSplitNames = splitNames;
mSplitTypes = splitTypes;
mIsFeatureSplits = isFeatureSplits;
@@ -401,11 +406,20 @@
return mUseEmbeddedDex;
}
+ /**
+ * Indicates if this package is a sdk.
+ */
+ @DataClass.Generated.Member
+ public boolean isIsSdkLibrary() {
+ return mIsSdkLibrary;
+ }
+
@DataClass.Generated(
- time = 1628562559343L,
+ time = 1643132127068L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures =
+ "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/hardware/CameraSessionStats.java b/core/java/android/hardware/CameraSessionStats.java
index f34e2bf..698cc76 100644
--- a/core/java/android/hardware/CameraSessionStats.java
+++ b/core/java/android/hardware/CameraSessionStats.java
@@ -59,6 +59,7 @@
private long mRequestCount;
private long mResultErrorCount;
private boolean mDeviceError;
+ private float mMaxPreviewFps;
private ArrayList<CameraStreamStats> mStreamStats;
public CameraSessionStats() {
@@ -67,6 +68,7 @@
mApiLevel = -1;
mIsNdk = false;
mLatencyMs = -1;
+ mMaxPreviewFps = 0;
mSessionType = -1;
mInternalReconfigure = -1;
mRequestCount = 0;
@@ -77,7 +79,7 @@
public CameraSessionStats(String cameraId, int facing, int newCameraState,
String clientName, int apiLevel, boolean isNdk, int creationDuration,
- int sessionType, int internalReconfigure) {
+ float maxPreviewFps, int sessionType, int internalReconfigure) {
mCameraId = cameraId;
mFacing = facing;
mNewCameraState = newCameraState;
@@ -85,6 +87,7 @@
mApiLevel = apiLevel;
mIsNdk = isNdk;
mLatencyMs = creationDuration;
+ mMaxPreviewFps = maxPreviewFps;
mSessionType = sessionType;
mInternalReconfigure = internalReconfigure;
mStreamStats = new ArrayList<CameraStreamStats>();
@@ -121,6 +124,7 @@
dest.writeInt(mApiLevel);
dest.writeBoolean(mIsNdk);
dest.writeInt(mLatencyMs);
+ dest.writeFloat(mMaxPreviewFps);
dest.writeInt(mSessionType);
dest.writeInt(mInternalReconfigure);
dest.writeLong(mRequestCount);
@@ -137,6 +141,7 @@
mApiLevel = in.readInt();
mIsNdk = in.readBoolean();
mLatencyMs = in.readInt();
+ mMaxPreviewFps = in.readFloat();
mSessionType = in.readInt();
mInternalReconfigure = in.readInt();
mRequestCount = in.readLong();
@@ -176,6 +181,10 @@
return mLatencyMs;
}
+ public float getMaxPreviewFps() {
+ return mMaxPreviewFps;
+ }
+
public int getSessionType() {
return mSessionType;
}
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 823d454..7b24cc4 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -15,8 +15,8 @@
*/
package android.hardware;
-import android.hardware.camera2.params.DynamicRangeProfiles;
import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.params.DynamicRangeProfiles;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -37,6 +37,7 @@
private int mWidth;
private int mHeight;
private int mFormat;
+ private float mMaxPreviewFps;
private int mDataSpace;
private long mUsage;
private long mRequestCount;
@@ -56,6 +57,7 @@
mWidth = 0;
mHeight = 0;
mFormat = 0;
+ mMaxPreviewFps = 0;
mDataSpace = 0;
mUsage = 0;
mRequestCount = 0;
@@ -68,13 +70,14 @@
mStreamUseCase = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
}
- public CameraStreamStats(int width, int height, int format,
+ public CameraStreamStats(int width, int height, int format, float maxPreviewFps,
int dataSpace, long usage, long requestCount, long errorCount,
int startLatencyMs, int maxHalBuffers, int maxAppBuffers, long dynamicRangeProfile,
int streamUseCase) {
mWidth = width;
mHeight = height;
mFormat = format;
+ mMaxPreviewFps = maxPreviewFps;
mDataSpace = dataSpace;
mUsage = usage;
mRequestCount = requestCount;
@@ -120,6 +123,7 @@
dest.writeInt(mWidth);
dest.writeInt(mHeight);
dest.writeInt(mFormat);
+ dest.writeFloat(mMaxPreviewFps);
dest.writeInt(mDataSpace);
dest.writeLong(mUsage);
dest.writeLong(mRequestCount);
@@ -138,6 +142,7 @@
mWidth = in.readInt();
mHeight = in.readInt();
mFormat = in.readInt();
+ mMaxPreviewFps = in.readFloat();
mDataSpace = in.readInt();
mUsage = in.readLong();
mRequestCount = in.readLong();
@@ -164,6 +169,10 @@
return mFormat;
}
+ public float getMaxPreviewFps() {
+ return mMaxPreviewFps;
+ }
+
public int getDataSpace() {
return mDataSpace;
}
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index d9734b4..5981d27 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -781,10 +781,11 @@
* <li>The fpsMin and fpsMax will be a multiple 30fps.</li>
* <li>The fpsMin will be no less than 30fps, the fpsMax will be no less than 120fps.</li>
* <li>At least one range will be a fixed FPS range where fpsMin == fpsMax.</li>
- * <li>For each fixed FPS range, there will be one corresponding variable FPS range [30,
- * fps_max]. These kinds of FPS ranges are suitable for preview-only use cases where the
- * application doesn't want the camera device always produce higher frame rate than the display
- * refresh rate.</li>
+ * <li>For each fixed FPS range, there will be one corresponding variable FPS range
+ * [30, fps_max] or [60, fps_max]. These kinds of FPS ranges are suitable for preview-only
+ * use cases where the application doesn't want the camera device always produce higher frame
+ * rate than the display refresh rate. Both 30fps and 60fps preview rate will not be
+ * supported for the same recording rate.</li>
* </p>
*
* @return an array of supported high speed video recording FPS ranges The upper bound of
diff --git a/core/java/android/inputmethodservice/ImsConfigurationTracker.java b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
index 3c78888..30ef0a2 100644
--- a/core/java/android/inputmethodservice/ImsConfigurationTracker.java
+++ b/core/java/android/inputmethodservice/ImsConfigurationTracker.java
@@ -63,8 +63,9 @@
*/
@MainThread
public void onBindInput(@Nullable Resources resources) {
- Preconditions.checkState(mInitialized,
- "onBindInput can be called only after onInitialize().");
+ if (!mInitialized) {
+ return;
+ }
if (mLastKnownConfig == null && resources != null) {
mLastKnownConfig = new Configuration(resources.getConfiguration());
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 60cd418..656aea1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -348,7 +348,7 @@
*/
@AnyThread
public static boolean canImeRenderGesturalNavButtons() {
- return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
+ return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
}
/**
diff --git a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
index 3f26fa4..6b2db7d 100644
--- a/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
+++ b/core/java/android/inputmethodservice/navigationbar/ButtonDispatcher.java
@@ -67,7 +67,7 @@
}
};
- public ButtonDispatcher(int id) {
+ ButtonDispatcher(int id) {
mId = id;
}
@@ -125,8 +125,8 @@
public void setImageDrawable(KeyButtonDrawable drawable) {
mImageDrawable = drawable;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
}
@@ -143,8 +143,8 @@
}
mVisibility = visibility;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setVisibility(mVisibility);
}
}
@@ -188,8 +188,8 @@
int nextAlpha = (int) (alpha * 255);
if (prevAlpha != nextAlpha) {
mAlpha = nextAlpha / 255f;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setAlpha(mAlpha);
}
}
@@ -198,8 +198,8 @@
public void setDarkIntensity(float darkIntensity) {
mDarkIntensity = darkIntensity;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
}
@@ -208,8 +208,8 @@
public void setDelayTouchFeedback(boolean delay) {
mDelayTouchFeedback = delay;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
if (mViews.get(i) instanceof ButtonInterface) {
((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
}
@@ -218,55 +218,55 @@
public void setOnClickListener(View.OnClickListener clickListener) {
mClickListener = clickListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnClickListener(mClickListener);
}
}
public void setOnTouchListener(View.OnTouchListener touchListener) {
mTouchListener = touchListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnTouchListener(mTouchListener);
}
}
public void setLongClickable(boolean isLongClickable) {
mLongClickable = isLongClickable;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setLongClickable(mLongClickable);
}
}
public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
mLongClickListener = longClickListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnLongClickListener(mLongClickListener);
}
}
public void setOnHoverListener(View.OnHoverListener hoverListener) {
mOnHoverListener = hoverListener;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setOnHoverListener(mOnHoverListener);
}
}
public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
mAccessibilityDelegate = delegate;
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
mViews.get(i).setAccessibilityDelegate(delegate);
}
}
public void setTranslation(int x, int y, int z) {
- final int N = mViews.size();
- for (int i = 0; i < N; i++) {
+ final int numViews = mViews.size();
+ for (int i = 0; i < numViews; i++) {
final View view = mViews.get(i);
view.setTranslationX(x);
view.setTranslationY(y);
diff --git a/core/java/android/inputmethodservice/navigationbar/DeadZone.java b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
index 4adc84b..4cfd813 100644
--- a/core/java/android/inputmethodservice/navigationbar/DeadZone.java
+++ b/core/java/android/inputmethodservice/navigationbar/DeadZone.java
@@ -82,7 +82,7 @@
}
};
- public DeadZone(NavigationBarView view) {
+ DeadZone(NavigationBarView view) {
mNavigationBarView = view;
onConfigurationChanged(Surface.ROTATION_0);
}
@@ -92,13 +92,15 @@
}
private float getSize(long now) {
- if (mSizeMax == 0)
+ if (mSizeMax == 0) {
return 0;
+ }
long dt = (now - mLastPokeTime);
- if (dt > mHold + mDecay)
+ if (dt > mHold + mDecay) {
return mSizeMin;
- if (dt < mHold)
+ } else if (dt < mHold) {
return mSizeMax;
+ }
return (int) lerp(mSizeMax, mSizeMin, (float) (dt - mHold) / mDecay);
}
@@ -177,8 +179,9 @@
private void poke(MotionEvent event) {
mLastPokeTime = event.getEventTime();
- if (DEBUG)
+ if (DEBUG) {
Log.v(TAG, "poked! size=" + getSize(mLastPokeTime));
+ }
if (mShouldFlash) mNavigationBarView.postInvalidate();
}
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
index 25a443d..45c8a18 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonDrawable.java
@@ -54,30 +54,30 @@
final class KeyButtonDrawable extends Drawable {
public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_ROTATE =
- new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
- @Override
- public void setValue(KeyButtonDrawable drawable, float degree) {
- drawable.setRotation(degree);
- }
+ new FloatProperty<KeyButtonDrawable>("KeyButtonRotation") {
+ @Override
+ public void setValue(KeyButtonDrawable drawable, float degree) {
+ drawable.setRotation(degree);
+ }
- @Override
- public Float get(KeyButtonDrawable drawable) {
- return drawable.getRotation();
- }
- };
+ @Override
+ public Float get(KeyButtonDrawable drawable) {
+ return drawable.getRotation();
+ }
+ };
public static final FloatProperty<KeyButtonDrawable> KEY_DRAWABLE_TRANSLATE_Y =
- new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
- @Override
- public void setValue(KeyButtonDrawable drawable, float y) {
- drawable.setTranslationY(y);
- }
+ new FloatProperty<KeyButtonDrawable>("KeyButtonTranslateY") {
+ @Override
+ public void setValue(KeyButtonDrawable drawable, float y) {
+ drawable.setTranslationY(y);
+ }
- @Override
- public Float get(KeyButtonDrawable drawable) {
- return drawable.getTranslationY();
- }
- };
+ @Override
+ public Float get(KeyButtonDrawable drawable) {
+ return drawable.getTranslationY();
+ }
+ };
private final Paint mIconPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
@@ -100,7 +100,7 @@
}
};
- public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
+ KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
boolean horizontalFlip, Color ovalBackgroundColor) {
this(d, new ShadowDrawableState(lightColor, darkColor,
d instanceof AnimatedVectorDrawable, horizontalFlip, ovalBackgroundColor));
@@ -433,8 +433,8 @@
final boolean mSupportsAnimation;
final Color mOvalBackgroundColor;
- public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
- boolean animated, boolean horizontalFlip, Color ovalBackgroundColor) {
+ ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor, boolean animated,
+ boolean horizontalFlip, Color ovalBackgroundColor) {
mLightColor = lightColor;
mDarkColor = darkColor;
mSupportsAnimation = animated;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
index 38a63b6..cf77c898 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonRipple.java
@@ -90,7 +90,7 @@
private Type mType = Type.ROUNDED_RECT;
- public KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
+ KeyButtonRipple(Context ctx, View targetView, @DimenRes int maxWidthResource) {
mMaxWidthResource = maxWidthResource;
mMaxWidth = ctx.getResources().getDimensionPixelSize(maxWidthResource);
mTargetView = targetView;
@@ -126,7 +126,7 @@
private void drawSoftware(Canvas canvas) {
if (mGlowAlpha > 0f) {
final Paint p = getRipplePaint();
- p.setAlpha((int)(mGlowAlpha * 255f));
+ p.setAlpha((int) (mGlowAlpha * 255f));
final float w = getBounds().width();
final float h = getBounds().height();
@@ -412,7 +412,7 @@
mDrawingHardwareGlow = true;
setExtendStart(CanvasProperty.createFloat(getExtendSize() / 2));
final RenderNodeAnimator startAnim = new RenderNodeAnimator(getExtendStart(),
- getExtendSize()/2 - GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+ getExtendSize() / 2 - GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
startAnim.setDuration(ANIMATION_DURATION_SCALE);
startAnim.setInterpolator(mInterpolator);
startAnim.addListener(mAnimatorListener);
@@ -420,7 +420,7 @@
setExtendEnd(CanvasProperty.createFloat(getExtendSize() / 2));
final RenderNodeAnimator endAnim = new RenderNodeAnimator(getExtendEnd(),
- getExtendSize()/2 + GLOW_MAX_SCALE_FACTOR * getRippleSize()/2);
+ getExtendSize() / 2 + GLOW_MAX_SCALE_FACTOR * getRippleSize() / 2);
endAnim.setDuration(ANIMATION_DURATION_SCALE);
endAnim.setInterpolator(mInterpolator);
endAnim.addListener(mAnimatorListener);
@@ -430,13 +430,13 @@
if (isHorizontal()) {
mTopProp = CanvasProperty.createFloat(0f);
mBottomProp = CanvasProperty.createFloat(getBounds().height());
- mRxProp = CanvasProperty.createFloat(getBounds().height()/2);
- mRyProp = CanvasProperty.createFloat(getBounds().height()/2);
+ mRxProp = CanvasProperty.createFloat(getBounds().height() / 2);
+ mRyProp = CanvasProperty.createFloat(getBounds().height() / 2);
} else {
mLeftProp = CanvasProperty.createFloat(0f);
mRightProp = CanvasProperty.createFloat(getBounds().width());
- mRxProp = CanvasProperty.createFloat(getBounds().width()/2);
- mRyProp = CanvasProperty.createFloat(getBounds().width()/2);
+ mRxProp = CanvasProperty.createFloat(getBounds().width() / 2);
+ mRyProp = CanvasProperty.createFloat(getBounds().width() / 2);
}
mGlowScale = GLOW_MAX_SCALE_FACTOR;
diff --git a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
index 74d30f8..cfdb6ca 100644
--- a/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
+++ b/core/java/android/inputmethodservice/navigationbar/KeyButtonView.java
@@ -200,8 +200,8 @@
postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
break;
case MotionEvent.ACTION_MOVE:
- x = (int)ev.getRawX();
- y = (int)ev.getRawY();
+ x = (int) ev.getRawX();
+ y = (int) ev.getRawY();
float slop = getQuickStepTouchSlopPx(getContext());
if (Math.abs(x - mTouchDownX) > slop || Math.abs(y - mTouchDownY) > slop) {
@@ -272,12 +272,13 @@
: KeyButtonRipple.Type.ROUNDED_RECT);
}
+ @Override
public void playSoundEffect(int soundConstant) {
if (!mPlaySounds) return;
mAudioManager.playSoundEffect(soundConstant);
}
- public void sendEvent(int action, int flags) {
+ private void sendEvent(int action, int flags) {
sendEvent(action, flags, SystemClock.uptimeMillis());
}
@@ -309,8 +310,8 @@
switch (action) {
case KeyEvent.ACTION_DOWN:
handled = ims.onKeyDown(ev.getKeyCode(), ev);
- mTracking = handled && ev.getRepeatCount() == 0 &&
- (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
+ mTracking = handled && ev.getRepeatCount() == 0
+ && (ev.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
break;
case KeyEvent.ACTION_UP:
handled = ims.onKeyUp(ev.getKeyCode(), ev);
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
index f01173e..a270675 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarFrame.java
@@ -59,4 +59,4 @@
}
return super.dispatchTouchEvent(event);
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
index d488890..e93bda2 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarInflaterView.java
@@ -121,7 +121,7 @@
return CONFIG_NAV_BAR_LAYOUT_HANDLE;
}
- public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
+ void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
mButtonDispatchers = buttonDispatchers;
for (int i = 0; i < buttonDispatchers.size(); i++) {
initiallyFill(buttonDispatchers.valueAt(i));
@@ -376,7 +376,7 @@
}
*/
- public static String extractSize(String buttonSpec) {
+ private static String extractSize(String buttonSpec) {
if (!buttonSpec.contains(SIZE_MOD_START)) {
return null;
}
@@ -384,7 +384,7 @@
return buttonSpec.substring(sizeStart + 1, buttonSpec.indexOf(SIZE_MOD_END));
}
- public static String extractButton(String buttonSpec) {
+ private static String extractButton(String buttonSpec) {
if (!buttonSpec.contains(SIZE_MOD_START)) {
return buttonSpec;
}
@@ -398,9 +398,9 @@
mButtonDispatchers.valueAt(indexOfKey).addView(v);
}
if (v instanceof ViewGroup) {
- final ViewGroup viewGroup = (ViewGroup)v;
- final int N = viewGroup.getChildCount();
- for (int i = 0; i < N; i++) {
+ final ViewGroup viewGroup = (ViewGroup) v;
+ final int numChildViews = viewGroup.getChildCount();
+ for (int i = 0; i < numChildViews; i++) {
addToDispatchers(viewGroup.getChildAt(i));
}
}
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index a2d7105..510b14e 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -48,8 +48,8 @@
* @hide
*/
public final class NavigationBarView extends FrameLayout {
- final static boolean DEBUG = false;
- final static String TAG = "NavBarView";
+ private static final boolean DEBUG = false;
+ private static final String TAG = "NavBarView";
// Copied from com.android.systemui.animation.Interpolators#FAST_OUT_SLOW_IN
private static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -139,7 +139,7 @@
}
/**
- * Applies {@param consumer} to each of the nav bar views.
+ * Applies {@code consumer} to each of the nav bar views.
*/
public void forEachView(Consumer<View> consumer) {
if (mHorizontal != null) {
@@ -181,7 +181,7 @@
}
}
- public KeyButtonDrawable getBackDrawable() {
+ private KeyButtonDrawable getBackDrawable() {
KeyButtonDrawable drawable = getDrawable(com.android.internal.R.drawable.ic_ime_nav_back);
orientBackButton(drawable);
return drawable;
@@ -211,7 +211,7 @@
// Animate the back button's rotation to the new degrees and only in portrait move up the
// back button to line up with the other buttons
float targetY = useAltBack
- ? - dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
+ ? -dpToPx(NAVBAR_BACK_BUTTON_IME_OFFSET, getResources())
: 0;
ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
PropertyValuesHolder.ofFloat(KeyButtonDrawable.KEY_DRAWABLE_ROTATE, degrees),
@@ -233,6 +233,11 @@
super.setLayoutDirection(layoutDirection);
}
+ /**
+ * Updates the navigation icons based on {@code hints}.
+ *
+ * @param hints bit flags defined in {@link StatusBarManager}.
+ */
public void setNavigationIconHints(int hints) {
if (hints == mNavigationIconHints) return;
final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
@@ -250,15 +255,7 @@
updateNavButtonIcons();
}
- public void setDisabledFlags(int disabledFlags) {
- if (mDisabledFlags == disabledFlags) return;
-
- mDisabledFlags = disabledFlags;
-
- updateNavButtonIcons();
- }
-
- public void updateNavButtonIcons() {
+ private void updateNavButtonIcons() {
// We have to replace or restore the back and home button icons when exiting or entering
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
@@ -319,7 +316,7 @@
mHorizontal.setVisibility(View.GONE);
}
- public void reorient() {
+ private void reorient() {
updateCurrentView();
final android.inputmethodservice.navigationbar.NavigationBarFrame frame =
@@ -372,6 +369,11 @@
}
}
+ /**
+ * Updates the dark intensity.
+ *
+ * @param intensity The intensity of darkness from {@code 0.0f} to {@code 1.0f}.
+ */
public void setDarkIntensity(@FloatRange(from = 0.0f, to = 1.0f) float intensity) {
for (int i = 0; i < mButtonDispatchers.size(); ++i) {
mButtonDispatchers.valueAt(i).setDarkIntensity(intensity);
diff --git a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
index 68163c3..9b36cc5 100644
--- a/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
+++ b/core/java/android/inputmethodservice/navigationbar/ReverseLinearLayout.java
@@ -30,9 +30,8 @@
/**
* Automatically reverses the order of children as they are added.
* Also reverse the width and height values of layout params
- * @hide
*/
-public class ReverseLinearLayout extends LinearLayout {
+class ReverseLinearLayout extends LinearLayout {
/** If true, the layout is reversed vs. a regular linear layout */
private boolean mIsLayoutReverse;
@@ -40,7 +39,7 @@
/** If true, the layout is opposite to it's natural reversity from the layout direction */
private boolean mIsAlternativeOrder;
- public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@@ -129,7 +128,7 @@
public static class ReverseRelativeLayout extends RelativeLayout implements Reversible {
- public ReverseRelativeLayout(Context context) {
+ ReverseRelativeLayout(Context context) {
super(context);
}
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 010459d..9e47a70 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -293,7 +293,10 @@
*
* @return Returns the result from {@link Binder#onTransact}. A successful call
* generally returns true; false generally means the transaction code was not
- * understood.
+ * understood. For a oneway call to a different process false should never be
+ * returned. If a oneway call is made to code in the same process (usually to
+ * a C++ or Rust implementation), then there are no oneway semantics, and
+ * false can still be returned.
*/
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
throws RemoteException;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 39ca596..3cde031 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -109,7 +109,7 @@
boolean someUserHasAccount(in String accountName, in String accountType);
String getProfileType(int userId);
boolean isMediaSharedWithParent(int userId);
- boolean isCredentialSharedWithParent(int userId);
+ boolean isCredentialSharableWithParent(int userId);
boolean isDemoUser(int userId);
boolean isPreCreated(int userId);
UserInfo createProfileForUserEvenWhenDisallowedWithThrow(in String name, in String userType, int flags,
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9428ac9..e06e732 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -257,6 +257,14 @@
public static final int UWB_UID = 1083;
/**
+ * Defines a virtual UID that is used to aggregate data related to SDK sandbox UIDs.
+ * {@see SdkSandboxManager}
+ * @hide
+ */
+ @TestApi
+ public static final int SDK_SANDBOX_VIRTUAL_UID = 1090;
+
+ /**
* GID that corresponds to the INTERNET permission.
* Must match the value of AID_INET.
* @hide
@@ -920,7 +928,7 @@
*/
@SystemApi(client = MODULE_LIBRARIES)
@TestApi
- public static final int sdkSandboxToAppUid(int uid) {
+ public static final int getAppUidForSdkSandboxUid(int uid) {
return uid - (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index a715c69..276578e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4763,7 +4763,7 @@
}
/**
- * Returns {@code true} if the user shares lock settings credential with its parent user
+ * Returns whether the user can have shared lockscreen credential with its parent user.
*
* This API only works for {@link UserManager#isProfile() profiles}
* and will always return false for any other user type.
@@ -4776,9 +4776,9 @@
Manifest.permission.MANAGE_USERS,
Manifest.permission.INTERACT_ACROSS_USERS})
@SuppressAutoDoc
- public boolean isCredentialSharedWithParent() {
+ public boolean isCredentialSharableWithParent() {
try {
- return mService.isCredentialSharedWithParent(mUserId);
+ return mService.isCredentialSharableWithParent(mUserId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index b501730..312abf8 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -83,7 +83,6 @@
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings;
-import android.sysprop.VoldProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -1739,10 +1738,7 @@
* false not encrypted or file encrypted
*/
public static boolean isBlockEncrypted() {
- if (!isEncrypted()) {
- return false;
- }
- return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
+ return false;
}
/** {@hide}
@@ -1752,18 +1748,7 @@
* false not encrypted, file encrypted or default block encrypted
*/
public static boolean isNonDefaultBlockEncrypted() {
- if (!isBlockEncrypted()) {
- return false;
- }
-
- try {
- IStorageManager storageManager = IStorageManager.Stub.asInterface(
- ServiceManager.getService("mount"));
- return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
- } catch (RemoteException e) {
- Log.e(TAG, "Error getting encryption type");
- return false;
- }
+ return false;
}
/** {@hide}
@@ -1777,8 +1762,7 @@
* framework, so no service needs to check for changes during their lifespan
*/
public static boolean isBlockEncrypting() {
- final String state = VoldProperties.encrypt_progress().orElse("");
- return !"".equalsIgnoreCase(state);
+ return false;
}
/** {@hide}
@@ -1793,8 +1777,7 @@
* framework, so no service needs to check for changes during their lifespan
*/
public static boolean inCryptKeeperBounce() {
- final String status = VoldProperties.decrypt().orElse("");
- return "trigger_restart_min_framework".equals(status);
+ return false;
}
/** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cfef7ad..a6ad5e5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10729,14 +10729,6 @@
"communal_mode_trusted_networks";
/**
- * Setting to allow Fast Pair scans to be enabled.
- * @hide
- */
- @SystemApi
- @Readable
- public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
-
- /**
* Setting to store denylisted system languages by the CEC {@code <Set Menu Language>}
* confirmation dialog.
*
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index db622d3..001707d 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -231,7 +231,7 @@
* The default value for whether to show complications on the overlay.
* @hide
*/
- public static final boolean DEFAULT_SHOW_COMPLICATIONS = true;
+ public static final boolean DEFAULT_SHOW_COMPLICATIONS = false;
private final IDreamManager mDreamManager;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -1341,7 +1341,9 @@
public void onViewDetachedFromWindow(View v) {
if (mActivity == null || !mActivity.isChangingConfigurations()) {
// Only stop the dream if the view is not detached by relaunching
- // activity for configuration changes.
+ // activity for configuration changes. It is important to also clear
+ // the window reference in order to fully release the DreamActivity.
+ mWindow = null;
mActivity = null;
finish();
}
diff --git a/core/java/android/service/games/GameScreenshotResult.java b/core/java/android/service/games/GameScreenshotResult.java
index ae76e08..5490aef 100644
--- a/core/java/android/service/games/GameScreenshotResult.java
+++ b/core/java/android/service/games/GameScreenshotResult.java
@@ -18,8 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,9 +28,7 @@
/**
* Result object for calls to {@link IGameSessionController#takeScreenshot}.
*
- * It includes a status (see {@link #getStatus}) and, if the status is
- * {@link #GAME_SCREENSHOT_SUCCESS} an {@link android.graphics.Bitmap} result (see {@link
- * #getBitmap}).
+ * It includes a status only (see {@link #getStatus}).
*
* @hide
*/
@@ -54,8 +50,7 @@
/**
* Indicates that the result of a call to {@link IGameSessionController#takeScreenshot} was
- * successful and an {@link android.graphics.Bitmap} result should be available by calling
- * {@link #getBitmap}.
+ * successful.
*
* @hide
*/
@@ -81,9 +76,7 @@
new Parcelable.Creator<GameScreenshotResult>() {
@Override
public GameScreenshotResult createFromParcel(Parcel source) {
- return new GameScreenshotResult(
- source.readInt(),
- source.readParcelable(null, Bitmap.class));
+ return new GameScreenshotResult(source.readInt());
}
@Override
@@ -95,14 +88,11 @@
@GameScreenshotStatus
private final int mStatus;
- @Nullable
- private final Bitmap mBitmap;
-
/**
- * Creates a successful {@link GameScreenshotResult} with the provided bitmap.
+ * Creates a successful {@link GameScreenshotResult}.
*/
- public static GameScreenshotResult createSuccessResult(@NonNull Bitmap bitmap) {
- return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS, bitmap);
+ public static GameScreenshotResult createSuccessResult() {
+ return new GameScreenshotResult(GAME_SCREENSHOT_SUCCESS);
}
/**
@@ -110,12 +100,11 @@
* {@link #GAME_SCREENSHOT_ERROR_INTERNAL_ERROR} status.
*/
public static GameScreenshotResult createInternalErrorResult() {
- return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR, null);
+ return new GameScreenshotResult(GAME_SCREENSHOT_ERROR_INTERNAL_ERROR);
}
- private GameScreenshotResult(@GameScreenshotStatus int status, @Nullable Bitmap bitmap) {
+ private GameScreenshotResult(@GameScreenshotStatus int status) {
this.mStatus = status;
- this.mBitmap = bitmap;
}
@Override
@@ -126,7 +115,6 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStatus);
- dest.writeParcelable(mBitmap, flags);
}
@GameScreenshotStatus
@@ -134,29 +122,12 @@
return mStatus;
}
- /**
- * Gets the {@link Bitmap} result from a successful screenshot attempt.
- *
- * @return The bitmap.
- * @throws IllegalStateException if this method is called when {@link #getStatus} does not
- * return {@link #GAME_SCREENSHOT_SUCCESS}.
- */
- @NonNull
- public Bitmap getBitmap() {
- if (mBitmap == null) {
- throw new IllegalStateException("Bitmap not available for failed screenshot result");
- }
- return mBitmap;
- }
-
@Override
public String toString() {
return "GameScreenshotResult{"
+ "mStatus="
+ mStatus
- + ", has bitmap='"
- + mBitmap != null ? "yes" : "no"
- + "\'}";
+ + "}";
}
@Override
@@ -170,12 +141,11 @@
}
GameScreenshotResult that = (GameScreenshotResult) o;
- return mStatus == that.mStatus
- && Objects.equals(mBitmap, that.mBitmap);
+ return mStatus == that.mStatus;
}
@Override
public int hashCode() {
- return Objects.hash(mStatus, mBitmap);
+ return Objects.hash(mStatus);
}
}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index 468e087c..1548f52 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
@@ -367,7 +366,7 @@
}
/**
- * Interface for returning screenshot outcome from calls to {@link #takeScreenshot}.
+ * Interface for handling result of {@link #takeScreenshot}.
*/
public interface ScreenshotCallback {
@@ -402,18 +401,16 @@
/**
* Called when taking the screenshot succeeded.
- *
- * @param bitmap The screenshot.
*/
- void onSuccess(@NonNull Bitmap bitmap);
+ void onSuccess();
}
/**
* Takes a screenshot of the associated game. For this call to succeed, the device screen
* must be turned on and the game task must be visible.
*
- * If the callback is called with {@link ScreenshotCallback#onSuccess}, the provided {@link
- * Bitmap} may be used.
+ * If the callback is called with {@link ScreenshotCallback#onSuccess}, the screenshot is
+ * taken successfully.
*
* If the callback is called with {@link ScreenshotCallback#onFailure}, the provided status
* code should be checked.
@@ -460,7 +457,7 @@
@GameScreenshotResult.GameScreenshotStatus int status = result.getStatus();
switch (status) {
case GameScreenshotResult.GAME_SCREENSHOT_SUCCESS:
- callback.onSuccess(result.getBitmap());
+ callback.onSuccess();
break;
case GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR:
Slog.w(TAG, "Error taking screenshot");
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 4541f3a..34e7ea7 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -71,8 +71,8 @@
* Hide back key in the Settings two pane design.
* @hide
*/
- public static final String SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE =
- "settings_hide_secondary_page_back_button_in_two_pane";
+ public static final String SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE =
+ "settings_hide_second_layer_page_navigate_up_button_in_two_pane";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -96,10 +96,10 @@
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SECURITY_HUB, "true");
DEFAULT_FLAGS.put(SETTINGS_SUPPORT_LARGE_SCREEN, "true");
DEFAULT_FLAGS.put("settings_search_always_expand", "true");
- DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
+ DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "false");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
- DEFAULT_FLAGS.put(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE, "true");
+ DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -109,7 +109,7 @@
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
- PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE);
+ PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE);
}
/**
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 71c1b7c..a4841f6 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -23,6 +23,7 @@
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.toInternalType;
import static android.view.InsetsState.toPublicType;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
@@ -682,9 +683,15 @@
@VisibleForTesting
public boolean onStateChanged(InsetsState state) {
- boolean stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
- false /* excludeInvisibleIme */)
- || !captionInsetsUnchanged();
+ boolean stateChanged = false;
+ if (!CAPTION_ON_SHELL) {
+ stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
+ false /* excludeInvisibleIme */)
+ || captionInsetsUnchanged();
+ } else {
+ stateChanged = !mState.equals(state, false /* excludingCaptionInsets */,
+ false /* excludeInvisibleIme */);
+ }
if (!stateChanged && mLastDispatchedState.equals(state)) {
return false;
}
@@ -758,16 +765,20 @@
}
private boolean captionInsetsUnchanged() {
+ if (CAPTION_ON_SHELL) {
+ return false;
+ }
if (mState.peekSource(ITYPE_CAPTION_BAR) == null
&& mCaptionInsetsHeight == 0) {
- return true;
+ return false;
}
if (mState.peekSource(ITYPE_CAPTION_BAR) != null
&& mCaptionInsetsHeight
== mState.peekSource(ITYPE_CAPTION_BAR).getFrame().height()) {
- return true;
+ return false;
}
- return false;
+
+ return true;
}
private void startResizingAnimationIfNeeded(InsetsState fromState) {
@@ -1582,11 +1593,15 @@
@Override
public void setCaptionInsetsHeight(int height) {
+ // This method is to be removed once the caption is moved to the shell.
+ if (CAPTION_ON_SHELL) {
+ return;
+ }
if (mCaptionInsetsHeight != height) {
mCaptionInsetsHeight = height;
if (mCaptionInsetsHeight != 0) {
- mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(mFrame.left, mFrame.top,
- mFrame.right, mFrame.top + mCaptionInsetsHeight));
+ mState.getSource(ITYPE_CAPTION_BAR).setFrame(mFrame.left, mFrame.top,
+ mFrame.right, mFrame.top + mCaptionInsetsHeight);
} else {
mState.removeSource(ITYPE_CAPTION_BAR);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index bde761e..18e65c9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -277,6 +277,12 @@
private static final boolean ENABLE_INPUT_LATENCY_TRACKING = true;
/**
+ * Whether the caption is drawn by the shell.
+ * @hide
+ */
+ public static final boolean CAPTION_ON_SHELL = false;
+
+ /**
* Set this system property to true to force the view hierarchy to render
* at 60 Hz. This can be used to measure the potential framerate.
*/
@@ -2561,6 +2567,9 @@
}
private boolean updateCaptionInsets() {
+ if (CAPTION_ON_SHELL) {
+ return false;
+ }
if (!(mView instanceof DecorView)) return false;
final int captionInsetsHeight = ((DecorView) mView).getCaptionInsetsHeight();
final Rect captionFrame = new Rect();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3a7a544..7f8a68d 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4595,7 +4595,7 @@
if (includeEditorBounds) {
final RectF bounds = new RectF();
- mTextView.getBoundsOnScreen(bounds, false /* clipToParent */);
+ bounds.set(0 /* left */, 0 /* top */, mTextView.getWidth(), mTextView.getHeight());
EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
//TODO(b/210039666): add Handwriting bounds once they're available.
builder.setEditorBoundsInfo(
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 022d05d..172456e4 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -52,7 +52,7 @@
/** Gets all root tasks on a display (ordered from top-to-bottom) */
List<ActivityManager.RunningTaskInfo> getRootTasks(int displayId, in int[] activityTypes);
- /** Get the root task which contains the current ime target */
+ /** Get the {@link WindowContainerToken} of the task which contains the current ime target */
WindowContainerToken getImeTarget(int display);
/**
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 3ec18db..8d88f80 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -199,7 +199,7 @@
}
}
- /** Get the root task which contains the current ime target */
+ /** Get the {@link WindowContainerToken} of the task which contains the current ime target */
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
@Nullable
public WindowContainerToken getImeTarget(int display) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 5f82fb0..5dbb551 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -28,6 +28,7 @@
import android.view.IWindow;
import android.view.IWindowSession;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.TreeMap;
@@ -185,35 +186,58 @@
}
private static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
- private final OnBackInvokedCallback mCallback;
+ private final WeakReference<OnBackInvokedCallback> mCallback;
OnBackInvokedCallbackWrapper(@NonNull OnBackInvokedCallback callback) {
- mCallback = callback;
- }
-
- @NonNull
- public OnBackInvokedCallback getCallback() {
- return mCallback;
+ mCallback = new WeakReference<>(callback);
}
@Override
public void onBackStarted() {
- Handler.getMain().post(() -> mCallback.onBackStarted());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackStarted();
+ });
}
@Override
public void onBackProgressed(BackEvent backEvent) {
- Handler.getMain().post(() -> mCallback.onBackProgressed(backEvent));
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackProgressed(backEvent);
+ });
}
@Override
public void onBackCancelled() {
- Handler.getMain().post(() -> mCallback.onBackCancelled());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackCancelled();
+ });
}
@Override
public void onBackInvoked() throws RemoteException {
- Handler.getMain().post(() -> mCallback.onBackInvoked());
+ Handler.getMain().post(() -> {
+ final OnBackInvokedCallback callback = mCallback.get();
+ if (callback == null) {
+ return;
+ }
+
+ callback.onBackInvoked();
+ });
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 3746bfd..5947e66 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -62,6 +62,10 @@
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_AVD;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SPLASHSCREEN_EXIT_ANIM;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS;
+import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__USER_SWITCH;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__WALLPAPER_TRANSITION;
@@ -176,6 +180,10 @@
public static final int CUJ_ONE_HANDED_ENTER_TRANSITION = 42;
public static final int CUJ_ONE_HANDED_EXIT_TRANSITION = 43;
public static final int CUJ_UNFOLD_ANIM = 44;
+ public static final int CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS = 45;
+ public static final int CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS = 46;
+ public static final int CUJ_SUW_LOADING_TO_NEXT_FLOW = 47;
+ public static final int CUJ_SUW_LOADING_SCREEN_FOR_STATUS = 48;
private static final int NO_STATSD_LOGGING = -1;
@@ -229,6 +237,10 @@
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_ENTER_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__ONE_HANDED_EXIT_TRANSITION,
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__UNFOLD_ANIM,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_TO_NEXT_FLOW,
+ UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__SUW_LOADING_SCREEN_FOR_STATUS,
};
private static volatile InteractionJankMonitor sInstance;
@@ -294,6 +306,10 @@
CUJ_ONE_HANDED_ENTER_TRANSITION,
CUJ_ONE_HANDED_EXIT_TRANSITION,
CUJ_UNFOLD_ANIM,
+ CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS,
+ CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS,
+ CUJ_SUW_LOADING_TO_NEXT_FLOW,
+ CUJ_SUW_LOADING_SCREEN_FOR_STATUS
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {
@@ -701,6 +717,14 @@
return "ONE_HANDED_EXIT_TRANSITION";
case CUJ_UNFOLD_ANIM:
return "UNFOLD_ANIM";
+ case CUJ_SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS:
+ return "SUW_LOADING_TO_SHOW_INFO_WITH_ACTIONS";
+ case CUJ_SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS:
+ return "SUW_SHOW_FUNCTION_SCREEN_WITH_ACTIONS";
+ case CUJ_SUW_LOADING_TO_NEXT_FLOW:
+ return "SUW_LOADING_TO_NEXT_FLOW";
+ case CUJ_SUW_LOADING_SCREEN_FOR_STATUS:
+ return "SUW_LOADING_SCREEN_FOR_STATUS";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 40e4085..89ac722 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -30,6 +30,7 @@
import static android.view.View.MeasureSpec.getMode;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -2120,7 +2121,9 @@
* corresponding insets change to the InsetsController.
*/
public void notifyCaptionHeightChanged() {
- getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+ if (!CAPTION_ON_SHELL) {
+ getWindowInsetsController().setCaptionInsetsHeight(getCaptionInsetsHeight());
+ }
}
void setWindow(PhoneWindow phoneWindow) {
diff --git a/core/java/com/android/internal/policy/TransitionAnimation.java b/core/java/com/android/internal/policy/TransitionAnimation.java
index 7ee1f17..74749cc 100644
--- a/core/java/com/android/internal/policy/TransitionAnimation.java
+++ b/core/java/com/android/internal/policy/TransitionAnimation.java
@@ -100,7 +100,7 @@
// TODO (b/215515255): remove once we full migrate to shell transitions
private static final boolean SHELL_TRANSITIONS_ENABLED =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
private final Context mContext;
private final String mTag;
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index d3c3917..f4f438b 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -11,8 +11,12 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
import android.graphics.Insets;
+import android.graphics.ParcelableColorSpace;
import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -26,6 +30,7 @@
import android.util.Log;
import android.view.WindowManager;
+import java.util.Objects;
import java.util.function.Consumer;
public class ScreenshotHelper {
@@ -154,6 +159,72 @@
};
}
+ /**
+ * Bundler used to convert between a hardware bitmap and a bundle without copying the internal
+ * content. This is expected to be used together with {@link #provideScreenshot} to handle a
+ * hardware bitmap as a screenshot.
+ */
+ public static final class HardwareBitmapBundler {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private HardwareBitmapBundler() {
+ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing
+ * this
+ * Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
+ colorSpace.getColorSpace());
+ }
+ }
+
private static final String TAG = "ScreenshotHelper";
// Time until we give up on the screenshot & show an error instead.
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index db4bc2c..851e8e0 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -97,7 +97,6 @@
boolean hasSecureLockScreen();
boolean tryUnlockWithCachedUnifiedChallenge(int userId);
void removeCachedUnifiedChallenge(int userId);
- void updateEncryptionPassword(int type, in byte[] password);
boolean registerWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener);
boolean unregisterWeakEscrowTokenRemovedListener(in IWeakEscrowTokenRemovedListener listener);
long addWeakEscrowToken(in byte[] token, int userId, in IWeakEscrowTokenActivatedListener callback);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 1e11c6d..f835792 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -722,38 +722,14 @@
return true;
}
- private void updateCryptoUserInfo(int userId) {
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- final String ownerInfo = isOwnerInfoEnabled(userId) ? getOwnerInfo(userId) : "";
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- Log.d(TAG, "Setting owner info");
- storageManager.setField(StorageManager.OWNER_INFO_KEY, ownerInfo);
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing user info", e);
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setOwnerInfo(String info, int userId) {
setString(LOCK_SCREEN_OWNER_INFO, info, userId);
- updateCryptoUserInfo(userId);
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setOwnerInfoEnabled(boolean enabled, int userId) {
setBoolean(LOCK_SCREEN_OWNER_INFO_ENABLED, enabled, userId);
- updateCryptoUserInfo(userId);
}
@UnsupportedAppUsage
@@ -808,17 +784,6 @@
}
/**
- * Clears the encryption password.
- */
- public void clearEncryptionPassword() {
- try {
- getLockSettings().updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't clear encryption password");
- }
- }
-
- /**
* Retrieves the quality mode for {@code userHandle}.
* @see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)
*
@@ -843,7 +808,7 @@
*/
public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled,
LockscreenCredential profilePassword) {
- if (!isCredentialSharedWithParent(userHandle)) {
+ if (!isCredentialSharableWithParent(userHandle)) {
return;
}
try {
@@ -859,7 +824,7 @@
* Returns true if {@code userHandle} is a managed profile with separate challenge.
*/
public boolean isSeparateProfileChallengeEnabled(int userHandle) {
- return isCredentialSharedWithParent(userHandle) && hasSeparateChallenge(userHandle);
+ return isCredentialSharableWithParent(userHandle) && hasSeparateChallenge(userHandle);
}
/**
@@ -884,8 +849,8 @@
return info != null && info.isManagedProfile();
}
- private boolean isCredentialSharedWithParent(int userHandle) {
- return getUserManager(userHandle).isCredentialSharedWithParent();
+ private boolean isCredentialSharableWithParent(int userHandle) {
+ return getUserManager(userHandle).isCredentialSharableWithParent();
}
/**
@@ -1042,24 +1007,6 @@
*/
public void setVisiblePatternEnabled(boolean enabled, int userId) {
setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
-
- // Update for crypto if owner
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- storageManager.setField(StorageManager.PATTERN_VISIBLE_KEY, enabled ? "1" : "0");
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing pattern visible state", e);
- }
}
public boolean isVisiblePatternEverChosen(int userId) {
@@ -1070,23 +1017,7 @@
* Set whether the visible password is enabled for cryptkeeper screen.
*/
public void setVisiblePasswordEnabled(boolean enabled, int userId) {
- // Update for crypto if owner
- if (userId != UserHandle.USER_SYSTEM) {
- return;
- }
-
- IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Log.e(TAG, "Could not find the mount service to update the user info");
- return;
- }
-
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- try {
- storageManager.setField(StorageManager.PASSWORD_VISIBLE_KEY, enabled ? "1" : "0");
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing password visible state", e);
- }
+ // No longer does anything.
}
/**
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 2b6b933..01cec77 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -45,6 +45,7 @@
import android.util.IntArray;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.RenderNodeAnimator;
@@ -82,10 +83,12 @@
private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
+ private static final float MIN_DOT_HIT_FACTOR = 0.2f;
private final CellState[][] mCellStates;
private final int mDotSize;
private final int mDotSizeActivated;
+ private final float mDotHitFactor;
private final int mPathWidth;
private boolean mDrawingProfilingStarted = false;
@@ -143,12 +146,11 @@
private boolean mPatternInProgress = false;
private boolean mFadePattern = true;
- private float mHitFactor = 0.6f;
-
@UnsupportedAppUsage
private float mSquareWidth;
@UnsupportedAppUsage
private float mSquareHeight;
+ private float mDotHitRadius;
private final LinearGradient mFadeOutGradientShader;
private final Path mCurrentPath = new Path();
@@ -164,8 +166,7 @@
private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mLinearOutSlowInInterpolator;
- private PatternExploreByTouchHelper mExploreByTouchHelper;
- private AudioManager mAudioManager;
+ private final PatternExploreByTouchHelper mExploreByTouchHelper;
private Drawable mSelectedDrawable;
private Drawable mNotSelectedDrawable;
@@ -349,6 +350,9 @@
mDotSize = getResources().getDimensionPixelSize(R.dimen.lock_pattern_dot_size);
mDotSizeActivated = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_dot_size_activated);
+ TypedValue outValue = new TypedValue();
+ getResources().getValue(R.dimen.lock_pattern_dot_hit_factor, outValue, true);
+ mDotHitFactor = Math.max(Math.min(outValue.getFloat(), 1f), MIN_DOT_HIT_FACTOR);
mUseLockPatternDrawable = getResources().getBoolean(R.bool.use_lock_pattern_drawable);
if (mUseLockPatternDrawable) {
@@ -375,7 +379,6 @@
AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mExploreByTouchHelper = new PatternExploreByTouchHelper(this);
setAccessibilityDelegate(mExploreByTouchHelper);
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int fadeAwayGradientWidth = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_fade_away_gradient_width);
@@ -679,6 +682,7 @@
final int height = h - mPaddingTop - mPaddingBottom;
mSquareHeight = height / 3.0f;
mExploreByTouchHelper.invalidateRoot();
+ mDotHitRadius = Math.min(mSquareHeight / 2, mSquareWidth / 2) * mDotHitFactor;
if (mUseLockPatternDrawable) {
mNotSelectedDrawable.setBounds(mPaddingLeft, mPaddingTop, width, height);
@@ -890,63 +894,30 @@
return set;
}
- // helper method to find which cell a point maps to
+ @Nullable
private Cell checkForNewHit(float x, float y) {
-
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
- return null;
+ Cell cellHit = detectCellHit(x, y);
+ if (cellHit != null && !mPatternDrawLookup[cellHit.row][cellHit.column]) {
+ return cellHit;
}
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return null;
- }
-
- if (mPatternDrawLookup[rowHit][columnHit]) {
- return null;
- }
- return Cell.of(rowHit, columnHit);
+ return null;
}
- /**
- * Helper method to find the row that y falls into.
- * @param y The y coordinate
- * @return The row that y falls in, or -1 if it falls in no row.
- */
- private int getRowHit(float y) {
-
- final float squareHeight = mSquareHeight;
- float hitSize = squareHeight * mHitFactor;
-
- float offset = mPaddingTop + (squareHeight - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitTop = offset + squareHeight * i;
- if (y >= hitTop && y <= hitTop + hitSize) {
- return i;
+ /** Helper method to find which cell a point maps to. */
+ @Nullable
+ private Cell detectCellHit(float x, float y) {
+ final float hitRadiusSquared = mDotHitRadius * mDotHitRadius;
+ for (int row = 0; row < 3; row++) {
+ for (int column = 0; column < 3; column++) {
+ float centerY = getCenterYForRow(row);
+ float centerX = getCenterXForColumn(column);
+ if ((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)
+ < hitRadiusSquared) {
+ return Cell.of(row, column);
+ }
}
}
- return -1;
- }
-
- /**
- * Helper method to find the column x fallis into.
- * @param x The x coordinate.
- * @return The column that x falls in, or -1 if it falls in no column.
- */
- private int getColumnHit(float x) {
- final float squareWidth = mSquareWidth;
- float hitSize = squareWidth * mHitFactor;
-
- float offset = mPaddingLeft + (squareWidth - hitSize) / 2f;
- for (int i = 0; i < 3; i++) {
-
- final float hitLeft = offset + squareWidth * i;
- if (x >= hitLeft && x <= hitLeft + hitSize) {
- return i;
- }
- }
- return -1;
+ return null;
}
@Override
@@ -1553,8 +1524,7 @@
protected int getVirtualViewAt(float x, float y) {
// This must use the same hit logic for the screen to ensure consistency whether
// accessibility is on or off.
- int id = getVirtualViewIdForHit(x, y);
- return id;
+ return getVirtualViewIdForHit(x, y);
}
@Override
@@ -1670,12 +1640,11 @@
final int col = ordinal % 3;
float centerX = getCenterXForColumn(col);
float centerY = getCenterYForRow(row);
- float cellheight = mSquareHeight * mHitFactor * 0.5f;
- float cellwidth = mSquareWidth * mHitFactor * 0.5f;
- bounds.left = (int) (centerX - cellwidth);
- bounds.right = (int) (centerX + cellwidth);
- bounds.top = (int) (centerY - cellheight);
- bounds.bottom = (int) (centerY + cellheight);
+ float cellHitRadius = mDotHitRadius;
+ bounds.left = (int) (centerX - cellHitRadius);
+ bounds.right = (int) (centerX + cellHitRadius);
+ bounds.top = (int) (centerY - cellHitRadius);
+ bounds.bottom = (int) (centerY + cellHitRadius);
return bounds;
}
@@ -1694,16 +1663,12 @@
* @return VIRTUAL_BASE_VIEW_ID+id or 0 if no view was hit
*/
private int getVirtualViewIdForHit(float x, float y) {
- final int rowHit = getRowHit(y);
- if (rowHit < 0) {
+ Cell cellHit = detectCellHit(x, y);
+ if (cellHit == null) {
return ExploreByTouchHelper.INVALID_ID;
}
- final int columnHit = getColumnHit(x);
- if (columnHit < 0) {
- return ExploreByTouchHelper.INVALID_ID;
- }
- boolean dotAvailable = mPatternDrawLookup[rowHit][columnHit];
- int dotId = (rowHit * 3 + columnHit) + VIRTUAL_BASE_VIEW_ID;
+ boolean dotAvailable = mPatternDrawLookup[cellHit.row][cellHit.column];
+ int dotId = (cellHit.row * 3 + cellHit.column) + VIRTUAL_BASE_VIEW_ID;
int view = dotAvailable ? dotId : ExploreByTouchHelper.INVALID_ID;
if (DEBUG_A11Y) Log.v(TAG, "getVirtualViewIdForHit(" + x + "," + y + ") => "
+ view + "avail =" + dotAvailable);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5b7092c..7bc6905 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -895,7 +895,7 @@
// pthread_setname_np fails rather than truncating long strings.
char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded into bionic
- strlcpy(buf, name_start_ptr, sizeof(buf) - 1);
+ strlcpy(buf, name_start_ptr, sizeof(buf));
errno = pthread_setname_np(pthread_self(), buf);
if (errno != 0) {
ALOGW("Unable to set the name of current thread to '%s': %s", buf, strerror(errno));
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fa9eba3..becac7f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1901,11 +1901,21 @@
<!-- Allows applications to enable/disable wifi auto join. This permission
is used to let OEMs grant their trusted app access to a subset of privileged wifi APIs
to improve wifi performance.
- <p>Not for use by third-party applications. -->
+ <p>Not for use by third-party applications.
+ @deprecated will be replaced with MANAGE_WIFI_NETWORK_SELECTION -->
<permission android:name="android.permission.MANAGE_WIFI_AUTO_JOIN"
android:protectionLevel="signature|privileged|knownSigner"
android:knownCerts="@array/wifi_known_signers" />
+ <!-- This permission is used to let OEMs grant their trusted app access to a subset of
+ privileged wifi APIs to improve wifi performance. Allows applications to manage
+ Wi-Fi network selection related features such as enable or disable global auto-join,
+ modify connectivity scan intervals, and approve Wi-Fi Direct connections.
+ <p>Not for use by third-party applications. -->
+ <permission android:name="android.permission.MANAGE_WIFI_NETWORK_SELECTION"
+ android:protectionLevel="signature|privileged|knownSigner"
+ android:knownCerts="@array/wifi_known_signers" />
+
<!-- Allows applications to get notified when a Wi-Fi interface request cannot
be satisfied without tearing down one or more other interfaces, and provide a decision
whether to approve the request or reject it.
@@ -3089,7 +3099,7 @@
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY"
- android:protectionLevel="signature|recents|role"/>
+ android:protectionLevel="signature|recents|role|installer"/>
<!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND}
@hide
@@ -6668,10 +6678,9 @@
android:exported="false">
</activity>
- <activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
- android:theme="@style/Theme.Dialog.Confirmation"
+ <activity android:name="com.android.server.logcat.LogAccessDialogActivity"
+ android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
android:excludeFromRecents="true"
- android:process=":ui"
android:label="@string/log_access_confirmation_title"
android:exported="false">
</activity>
@@ -6830,6 +6839,13 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.sdksandbox.SdkSandboxVerifierReceiver"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION"/>
+ </intent-filter>
+ </receiver>
+
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
diff --git a/core/res/res/drawable/grant_permissions_buttons_bottom.xml b/core/res/res/drawable/grant_permissions_buttons_bottom.xml
new file mode 100644
index 0000000..a800f15
--- /dev/null
+++ b/core/res/res/drawable/grant_permissions_buttons_bottom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+</shape>
\ No newline at end of file
diff --git a/core/res/res/drawable/grant_permissions_buttons_top.xml b/core/res/res/drawable/grant_permissions_buttons_top.xml
new file mode 100644
index 0000000..2bf803e
--- /dev/null
+++ b/core/res/res/drawable/grant_permissions_buttons_top.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+</shape>
\ No newline at end of file
diff --git a/core/res/res/layout/log_access_user_consent_dialog_permission.xml b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
new file mode 100644
index 0000000..bd7efbd
--- /dev/null
+++ b/core/res/res/layout/log_access_user_consent_dialog_permission.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2022, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="380dp"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="24dp"
+ android:paddingRight="24dp"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp"
+ android:background="?attr/colorSurface">
+
+ <ImageView
+ android:id="@+id/log_access_image_view"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_marginBottom="16dp"
+ android:src="@drawable/ic_doc_document"
+ tools:layout_editor_absoluteX="148dp"
+ tools:layout_editor_absoluteY="35dp"
+ android:gravity="center" />
+
+
+ <TextView
+ android:id="@+id/log_access_dialog_title"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginBottom="32dp"
+ android:text="@string/log_access_confirmation_title"
+ android:textAppearance="?attr/textAppearanceLarge"
+ android:textColor="@android:color/system_neutral1_900"
+ android:gravity="center" />
+
+ <TextView
+ android:id="@+id/log_access_dialog_body"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/log_access_confirmation_body"
+ android:textAppearance="@style/PrimaryAllowLogAccess"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/log_access_dialog_allow_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/log_access_confirmation_allow"
+ style="@style/PermissionGrantButtonTop"
+ android:layout_marginBottom="5dp"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+
+ <Button
+ android:id="@+id/log_access_dialog_deny_button"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:text="@string/log_access_confirmation_deny"
+ style="@style/PermissionGrantButtonBottom"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentBottom="true"
+ android:clipToOutline="true"
+ android:gravity="center" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 879fc9e..0a572be 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2335,7 +2335,7 @@
<!-- Remote server that can provide NTP responses. -->
<string translatable="false" name="config_ntpServer">time.android.com</string>
<!-- Normal polling frequency in milliseconds -->
- <integer name="config_ntpPollingInterval">86400000</integer>
+ <integer name="config_ntpPollingInterval">64800000</integer>
<!-- Try-again polling interval in milliseconds, in case the network request failed -->
<integer name="config_ntpPollingIntervalShorter">60000</integer>
<!-- Number of times to try again with the shorter interval, before backing
@@ -2723,7 +2723,7 @@
<string name="config_bandwidthEstimateSource">bandwidth_estimator</string>
<!-- Whether force to enable telephony new data stack or not -->
- <bool name="config_force_enable_telephony_new_data_stack">false</bool>
+ <bool name="config_force_enable_telephony_new_data_stack">true</bool>
<!-- Whether WiFi display is supported by this device.
There are many prerequisites for this feature to work correctly.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1b9f7fe..44c5512 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -668,6 +668,9 @@
<dimen name="lock_pattern_dot_line_width">22dp</dimen>
<dimen name="lock_pattern_dot_size">14dp</dimen>
<dimen name="lock_pattern_dot_size_activated">30dp</dimen>
+ <!-- How much of the cell space is classified as hit areas [0..1] where 1 means that hit area is
+ a circle with diameter equals to cell minimum side min(width, height). -->
+ <item type="dimen" format="float" name="lock_pattern_dot_hit_factor">0.6</item>
<!-- Width of a gradient applied to a lock pattern line while its disappearing animation. -->
<dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public-final.xml
similarity index 97%
rename from core/res/res/values/public.xml
rename to core/res/res/values/public-final.xml
index 80664eb..19a4842 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public-final.xml
@@ -3222,149 +3222,4 @@
<public type="id" name="accessibilityActionDragDrop" id="0x01020056" />
<public type="id" name="accessibilityActionDragCancel" id="0x01020057" />
- <!-- ===============================================================
- Resources added in version T of the platform
-
- NOTE: add <public> elements within a <staging-public-group> like so:
-
- <staging-public-group type="attr" first-id="0x01ff0000">
- <public name="exampleAttr1" />
- <public name="exampleAttr2" />
- </staging-public-group>
-
- To add a new <staging-public-group> block, find the id value for the
- last <staging-public-group> block defined for thie API level, and
- subtract 0x00010000 from it to get to the id of the new block.
-
- For example, if the block closest to the end of this file has an id
- of 0x01ee0000, the id of the new block should be 0x01ed0000
- (0x01ee0000 - 0x00010000 = 0x01ed0000).
- =============================================================== -->
- <eat-comment />
-
- <staging-public-group type="attr" first-id="0x01df0000">
- <public name="sharedUserMaxSdkVersion" />
- <public name="requiredSplitTypes" />
- <public name="splitTypes" />
- <public name="canDisplayOnRemoteDevices" />
- <public name="supportedTypes" />
- <public name="resetEnabledSettingsOnAppDataCleared" />
- <public name="supportsStylusHandwriting" />
- <public name="showClockAndComplications" />
- <!-- @hide @SystemApi -->
- <public name="gameSessionService" />
- <public name="supportsBatteryGameMode" />
- <public name="supportsPerformanceGameMode" />
- <public name="allowGameAngleDriver" />
- <public name="allowGameDownscaling" />
- <public name="allowGameFpsOverride" />
- <public name="localeConfig" />
- <public name="showBackground" />
- <public name="useTargetActivityForQuickAccess"/>
- <public name="inheritKeyStoreKeys" />
- <public name="preferKeepClear" />
- <public name="autoHandwritingEnabled" />
- <public name="fromExtendLeft" />
- <public name="fromExtendTop" />
- <public name="fromExtendRight" />
- <public name="fromExtendBottom" />
- <public name="toExtendLeft" />
- <public name="toExtendTop" />
- <public name="toExtendRight" />
- <public name="toExtendBottom" />
- <public name="tileService" />
- <public name="windowSplashScreenBehavior" />
- <public name="allowUntrustedActivityEmbedding" />
- <public name="knownActivityEmbeddingCerts" />
- <public name="intro" />
- <public name="enableOnBackInvokedCallback" />
- <public name="supportsInlineSuggestionsWithTouchExploration" />
- <public name="lineBreakStyle" />
- <public name="lineBreakWordStyle" />
- </staging-public-group>
-
- <staging-public-group type="id" first-id="0x01de0000">
- <public name="removed_accessibilityActionSwipeLeft" />
- <public name="removed_accessibilityActionSwipeRight" />
- <public name="removed_accessibilityActionSwipeUp" />
- <public name="removed_accessibilityActionSwipeDown" />
- <public name="accessibilityActionShowTextSuggestions" />
- <public name="inputExtractAction" />
- <public name="inputExtractAccessories" />
- </staging-public-group>
-
- <staging-public-group type="style" first-id="0x01dd0000">
- <public name="TextAppearance.DeviceDefault.Headline" />
- </staging-public-group>
-
- <staging-public-group type="string" first-id="0x01dc0000">
- <!-- @hide @SystemApi -->
- <public name="config_systemSupervision" />
- <!-- @hide @SystemApi -->
- <public name="config_devicePolicyManagement" />
- <!-- @hide @SystemApi -->
- <public name="config_systemAppProtectionService" />
- <!-- @hide @SystemApi @TestApi -->
- <public name="config_systemAutomotiveCalendarSyncManager" />
- <!-- @hide @SystemApi -->
- <public name="config_defaultAutomotiveNavigation" />
- </staging-public-group>
-
- <staging-public-group type="dimen" first-id="0x01db0000">
- </staging-public-group>
-
- <staging-public-group type="color" first-id="0x01da0000">
- </staging-public-group>
-
- <staging-public-group type="array" first-id="0x01d90000">
- <!-- @hide @SystemApi -->
- <public name="config_optionalIpSecAlgorithms" />
- </staging-public-group>
-
- <staging-public-group type="drawable" first-id="0x01d80000">
- </staging-public-group>
-
- <staging-public-group type="layout" first-id="0x01d70000">
- </staging-public-group>
-
- <staging-public-group type="anim" first-id="0x01d60000">
- </staging-public-group>
-
- <staging-public-group type="animator" first-id="0x01d50000">
- </staging-public-group>
-
- <staging-public-group type="interpolator" first-id="0x01d40000">
- </staging-public-group>
-
- <staging-public-group type="mipmap" first-id="0x01d30000">
- </staging-public-group>
-
- <staging-public-group type="integer" first-id="0x01d20000">
- </staging-public-group>
-
- <staging-public-group type="transition" first-id="0x01d10000">
- </staging-public-group>
-
- <staging-public-group type="raw" first-id="0x01d00000">
- </staging-public-group>
-
- <staging-public-group type="bool" first-id="0x01cf0000">
- <!-- @hide @TestApi -->
- <public name="config_preventImeStartupUnlessTextEditor" />
- <!-- @hide @SystemApi -->
- <public name="config_enableQrCodeScannerOnLockScreen" />
- </staging-public-group>
-
- <staging-public-group type="fraction" first-id="0x01ce0000">
- </staging-public-group>
-
- <!-- ===============================================================
- DO NOT ADD UN-GROUPED ITEMS HERE
-
- Any new items (attrs, styles, ids, etc.) *must* be added in a
- staging-public-group block, as the preceding comment explains.
- Items added outside of a group may have their value recalculated
- every time something new is added to this file.
- =============================================================== -->
-
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
new file mode 100644
index 0000000..2dc17b8
--- /dev/null
+++ b/core/res/res/values/public-staging.xml
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Exposing a new resource:
+ To add a new entry, find the corresponding "staging-public-group" with the correct type for
+ your resource, and add a new entry to the BOTTOM of the list. This ensures that indexes
+ don't shift for previously added resources, and the new one will be appended to the end.
+
+ To add R.attr.exampleAttrName:
+ <staging-public-group type="attr" first-id="0x1ff0000">
+ <public name="previouslyAdded1"/>
+ <public name="previouslyAdded2"/>
+ <public name="exampleAttrName"/>
+ </staging-public-group>
+
+ Deleting a resource:
+ If a resource is no longer supported/used, it can be marked removed by renaming the
+ resource with a `removed_` prefix. This preserves the indexes of other resources so as not
+ to break apps that have compiled with their integers previously.
+
+ To remove R.attr.previouslyAdded2:
+ <staging-public-group type="attr" first-id="0x1ff0000">
+ <public name="previouslyAdded1"/>
+ <public name="removed_previouslyAdded2"/>
+ <public name="exampleAttrName"/>
+ </staging-public-group>
+
+ IMPORTANT: Deleting an entry is never allowed, even across branches or reverts. Please take
+ this into account before merging a change which edits this file. Small, isolated changes
+ which only add/remove resources is recommended to avoid reverts due to build/test failures.
+
+ Renaming a resource:
+ This is generally fine and can be done to the entry directly, with no other changes. But
+ note that any apps/tooling that resolve against resource names rather than IDs may break
+ as a result. This is uncommon, but not rare.
+
+ Finalizing a release's resources:
+ 1. $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-staging.xml \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-final.xml
+ 2. Rename "NEXT" in the new public-staging.xml resources header to the next platform short
+ version code
+
+ Finalizing a release's resources (manually; only for reference):
+ 1. Delete all "staging-public-group" blocks for the release with no entries inside them
+ 2. Rename the remaining "staging-public-group" blocks for that release to
+ "staging-public-group-final"
+ 3. Cut them out this file and place at the bottom of public-final.xml; also move the
+ "Resources added in version ? of the platform" header
+ 4. Copy-paste all of the non-"removed_" resources outside of the staging blocks into being
+ siblings alongside them
+ 5. Assign them final public IDs in the form of
+ <public type="attr" name="exampleAttrName" id="0x0101088a" />
+ by finding the last ID for that type and incrementing the last 4 characters by 1 in
+ hexadecimal
+ 6. Back in this file, seed the next release's resources by adding "staging-public-group"
+ tags with their "first-id" value shifted by -0x00010000 from the lowest "first-id"
+ in the last used "staging-public-group-final"
+
+ Example:
+ Starting public-staging.xml:
+ <!\- ===============================================================
+ Resources added in version ? of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group type="attr" first-id="0x01ff0000">
+ <public name="exampleAttr1"/>
+ <public name="removed_exampleAttr2"/>
+ <public name="exampleAttr3"/>
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01fe0000">
+ </staging-public-group>
+
+ Resulting public-final.xml:
+ <!\- ===============================================================
+ Resources added in version ? of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group-final type="attr" first-id="0x01ff0000">
+ <public name="exampleAttr1"/>
+ <public name="removed_exampleAttr2"/>
+ <public name="exampleAttr3"/>
+ </staging-public-group-final>
+
+ <public type="id" name="exampleAttr1" id="0x0101088a"/>
+ <public type="id" name="exampleAttr3" id="0x0101088b"/>
+
+ Resulting public-staging.xml:
+ <!\- ===============================================================
+ Resources added in version (? + 1) of the platform
+ =============================================================== -\>
+ <eat-comment />
+
+ <staging-public-group type="attr" first-id="0x01fd0000">
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01fc0000">
+ </staging-public-group>
+-->
+<resources>
+
+ <!-- ===============================================================
+ Resources added in version T of the platform
+
+ NOTE: After this version of the platform is forked, changes cannot be made to the root
+ branch's groups for that release. Only merge changes to the forked platform branch.
+ =============================================================== -->
+ <eat-comment/>
+
+ <staging-public-group type="attr" first-id="0x01df0000">
+ <public name="sharedUserMaxSdkVersion" />
+ <public name="requiredSplitTypes" />
+ <public name="splitTypes" />
+ <public name="canDisplayOnRemoteDevices" />
+ <public name="supportedTypes" />
+ <public name="resetEnabledSettingsOnAppDataCleared" />
+ <public name="supportsStylusHandwriting" />
+ <public name="showClockAndComplications" />
+ <!-- @hide @SystemApi -->
+ <public name="gameSessionService" />
+ <public name="supportsBatteryGameMode" />
+ <public name="supportsPerformanceGameMode" />
+ <public name="allowGameAngleDriver" />
+ <public name="allowGameDownscaling" />
+ <public name="allowGameFpsOverride" />
+ <public name="localeConfig" />
+ <public name="showBackground" />
+ <public name="useTargetActivityForQuickAccess"/>
+ <public name="inheritKeyStoreKeys" />
+ <public name="preferKeepClear" />
+ <public name="autoHandwritingEnabled" />
+ <public name="fromExtendLeft" />
+ <public name="fromExtendTop" />
+ <public name="fromExtendRight" />
+ <public name="fromExtendBottom" />
+ <public name="toExtendLeft" />
+ <public name="toExtendTop" />
+ <public name="toExtendRight" />
+ <public name="toExtendBottom" />
+ <public name="tileService" />
+ <public name="windowSplashScreenBehavior" />
+ <public name="allowUntrustedActivityEmbedding" />
+ <public name="knownActivityEmbeddingCerts" />
+ <public name="intro" />
+ <public name="enableOnBackInvokedCallback" />
+ <public name="supportsInlineSuggestionsWithTouchExploration" />
+ <public name="lineBreakStyle" />
+ <public name="lineBreakWordStyle" />
+ </staging-public-group>
+
+ <staging-public-group type="id" first-id="0x01de0000">
+ <public name="removed_accessibilityActionSwipeLeft" />
+ <public name="removed_accessibilityActionSwipeRight" />
+ <public name="removed_accessibilityActionSwipeUp" />
+ <public name="removed_accessibilityActionSwipeDown" />
+ <public name="accessibilityActionShowTextSuggestions" />
+ <public name="inputExtractAction" />
+ <public name="inputExtractAccessories" />
+ </staging-public-group>
+
+ <staging-public-group type="style" first-id="0x01dd0000">
+ <public name="TextAppearance.DeviceDefault.Headline" />
+ </staging-public-group>
+
+ <staging-public-group type="string" first-id="0x01dc0000">
+ <!-- @hide @SystemApi -->
+ <public name="config_systemSupervision" />
+ <!-- @hide @SystemApi -->
+ <public name="config_devicePolicyManagement" />
+ <!-- @hide @SystemApi -->
+ <public name="config_systemAppProtectionService" />
+ <!-- @hide @SystemApi @TestApi -->
+ <public name="config_systemAutomotiveCalendarSyncManager" />
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultAutomotiveNavigation" />
+ </staging-public-group>
+
+ <staging-public-group type="dimen" first-id="0x01db0000">
+ </staging-public-group>
+
+ <staging-public-group type="color" first-id="0x01da0000">
+ </staging-public-group>
+
+ <staging-public-group type="array" first-id="0x01d90000">
+ <!-- @hide @SystemApi -->
+ <public name="config_optionalIpSecAlgorithms" />
+ </staging-public-group>
+
+ <staging-public-group type="drawable" first-id="0x01d80000">
+ </staging-public-group>
+
+ <staging-public-group type="layout" first-id="0x01d70000">
+ </staging-public-group>
+
+ <staging-public-group type="anim" first-id="0x01d60000">
+ </staging-public-group>
+
+ <staging-public-group type="animator" first-id="0x01d50000">
+ </staging-public-group>
+
+ <staging-public-group type="interpolator" first-id="0x01d40000">
+ </staging-public-group>
+
+ <staging-public-group type="mipmap" first-id="0x01d30000">
+ </staging-public-group>
+
+ <staging-public-group type="integer" first-id="0x01d20000">
+ </staging-public-group>
+
+ <staging-public-group type="transition" first-id="0x01d10000">
+ </staging-public-group>
+
+ <staging-public-group type="raw" first-id="0x01d00000">
+ </staging-public-group>
+
+ <staging-public-group type="bool" first-id="0x01cf0000">
+ <!-- @hide @TestApi -->
+ <public name="config_preventImeStartupUnlessTextEditor" />
+ <!-- @hide @SystemApi -->
+ <public name="config_enableQrCodeScannerOnLockScreen" />
+ </staging-public-group>
+
+ <staging-public-group type="fraction" first-id="0x01ce0000">
+ </staging-public-group>
+
+</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 05ebef9..5de8fec 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1248,14 +1248,13 @@
Malicious apps may use this to erase or modify your call log.</string>
<!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=80] -->
- <string name="permlab_bodySensors">access body sensors (like heart rate monitors)
- </string>
+ <string name="permlab_bodySensors">Access body sensor data, like heart rate, while in use</string>
<!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
- <string name="permdesc_bodySensors" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc.</string>
+ <string name="permdesc_bodySensors" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in use.</string>
<!-- Title of the background body sensors permission, listed so the user can decide whether to allow the application to access body sensor data in the background. [CHAR LIMIT=80] -->
- <string name="permlab_bodySensors_background">access body sensors (like heart rate monitors) while in the background</string>
+ <string name="permlab_bodySensors_background">Access body sensor data, like heart rate, while in the background</string>
<!-- Description of the background body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors in the background. [CHAR LIMIT=NONE] -->
- <string name="permdesc_bodySensors_background" product="default">Access to data from body sensors such as heart rate, temperature, blood oxygen percentage, etc. while in the background.</string>
+ <string name="permdesc_bodySensors_background" product="default">Allows the app to access body sensor data, such as heart rate, temperature, and blood oxygen percentage, while the app is in the background.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readCalendar">Read calendar events and details</string>
@@ -2415,7 +2414,7 @@
<!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. -->
<string name="lockscreen_pattern_instructions">Draw pattern to unlock</string>
<!-- Button at the bottom of the unlock screen to make an emergency call or access other emergency assistance functions. -->
- <string name="lockscreen_emergency_call">Emergency call</string>
+ <string name="lockscreen_emergency_call">Emergency</string>
<!-- Button at the bottom of the unlock screen that lets the user return to a call -->
<string name="lockscreen_return_to_call">Return to call</string>
<!-- Shown to confirm that the user entered their lock pattern correctly. -->
@@ -5731,16 +5730,17 @@
<!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
<string name="harmful_app_warning_title">Harmful app detected</string>
- <!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
- <string name="log_access_confirmation_title">System log access request</string>
+ <!-- Title for the log access confirmation dialog. [CHAR LIMIT=NONE] -->
+ <string name="log_access_confirmation_title">Allow <xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> to access all device logs?</string>
<!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
<string name="log_access_confirmation_allow">Only this time</string>
<!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
<string name="log_access_confirmation_deny">Don\u2019t allow</string>
<!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
- <string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
- These logs might contain information that apps and services on your device have written.</string>
+ <string name="log_access_confirmation_body">Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps you trust to access all device logs.
+ \n\nIf you don’t allow this app to access all device logs, it can still access its own logs, and your device manufacturer may still be able to access some logs or info on your device. Learn more
+ </string>
<!-- Privacy notice do not show [CHAR LIMIT=20] -->
<string name="log_access_do_not_show_again">Don\u2019t show again</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 9553f95..7a9f520 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1499,5 +1499,43 @@
<item name="textColor">#555555</item>
</style>
+ <!-- The style for log access consent text -->
+ <style name="AllowLogAccess">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:textSize">24sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:fontFamily">google-sans</item>
+ </style>
+
+ <style name="PrimaryAllowLogAccess">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:fontFamily">google-sans</item>
+ </style>
+
+ <style name="PermissionGrantButtonTop"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginTop">2dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/grant_permissions_buttons_top</item>
+ </style>
+
+ <style name="PermissionGrantButtonBottom"
+ parent="@android:style/Widget.DeviceDefault.Button.Borderless.Colored">
+ <item name="android:layout_width">332dp</item>
+ <item name="android:layout_height">56dp</item>
+ <item name="android:layout_marginTop">2dp</item>
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:fontFamily">google-sans-medium</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/grant_permissions_buttons_bottom</item>
+ </style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2e1c6c2..6f34b3f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1325,6 +1325,7 @@
<java-symbol type="dimen" name="lock_pattern_dot_line_width" />
<java-symbol type="dimen" name="lock_pattern_dot_size" />
<java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
+ <java-symbol type="dimen" name="lock_pattern_dot_hit_factor" />
<java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" />
<java-symbol type="drawable" name="clock_dial" />
<java-symbol type="drawable" name="clock_hand_hour" />
@@ -3883,6 +3884,10 @@
<java-symbol type="string" name="log_access_confirmation_deny" />
<java-symbol type="string" name="log_access_confirmation_title" />
<java-symbol type="string" name="log_access_confirmation_body" />
+ <java-symbol type="layout" name="log_access_user_consent_dialog_permission" />
+ <java-symbol type="id" name="log_access_dialog_title" />
+ <java-symbol type="id" name="log_access_dialog_allow_button" />
+ <java-symbol type="id" name="log_access_dialog_deny_button" />
<java-symbol type="string" name="config_defaultAssistantAccessComponent" />
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 227a8657..c504f0c 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -30,6 +30,7 @@
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.LAST_TYPE;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
@@ -758,6 +759,11 @@
@Test
public void testCaptionInsetsStateAssemble() {
+ if (CAPTION_ON_SHELL) {
+ // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+ // test can be removed after the caption is moved to shell completely.
+ return;
+ }
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.onFrameChanged(new Rect(0, 0, 100, 300));
final InsetsState state = new InsetsState(mController.getState(), true);
@@ -769,6 +775,7 @@
assertEquals(captionFrame, currentState.peekSource(ITYPE_CAPTION_BAR).getFrame());
assertTrue(currentState.equals(state, true /* excludingCaptionInsets*/,
true /* excludeInvisibleIme */));
+ // Test update to remove the caption bar
mController.setCaptionInsetsHeight(0);
mController.onStateChanged(state);
// The caption bar source should not be there at all, because we don't add empty
@@ -779,6 +786,11 @@
@Test
public void testNotifyCaptionInsetsOnlyChange() {
+ if (CAPTION_ON_SHELL) {
+ // For this case, the test is covered by WindowContainerInsetsSourceProviderTest, This
+ // test can be removed after the caption is moved to shell completely.
+ return;
+ }
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
final InsetsState state = new InsetsState(mController.getState(), true);
reset(mTestHost);
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
new file mode 100644
index 0000000..8ba4966
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternViewTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2022 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.widget;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+
+import android.content.Context;
+
+import androidx.test.annotation.UiThreadTest;
+
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toolbar;
+
+
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.UiThreadTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import com.android.internal.R;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+@SmallTest
+public class LockPatternViewTest {
+
+ @Rule
+ public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
+
+ private final int mViewSize;
+ private final float mDefaultError;
+ private final float mDot1x;
+ private final float mDot1y;
+ private final float mDot2x;
+ private final float mDot2y;
+ private final float mDot3x;
+ private final float mDot3y;
+ private final float mDot5x;
+ private final float mDot5y;
+ private final float mDot7x;
+ private final float mDot7y;
+ private final float mDot9x;
+ private final float mDot9y;
+
+ private Context mContext;
+ private LockPatternView mLockPatternView;
+ @Mock
+ private LockPatternView.OnPatternListener mPatternListener;
+ @Captor
+ private ArgumentCaptor<List<LockPatternView.Cell>> mCellsArgumentCaptor;
+
+ public LockPatternViewTest(int viewSize) {
+ mViewSize = viewSize;
+ float cellSize = viewSize / 3f;
+ mDefaultError = cellSize * 0.2f;
+ mDot1x = cellSize / 2f;
+ mDot1y = cellSize / 2f;
+ mDot2x = cellSize + mDot1x;
+ mDot2y = mDot1y;
+ mDot3x = cellSize + mDot2x;
+ mDot3y = mDot1y;
+ // dot4 is skipped as redundant
+ mDot5x = cellSize + mDot1x;
+ mDot5y = cellSize + mDot1y;
+ // dot6 is skipped as redundant
+ mDot7x = mDot1x;
+ mDot7y = cellSize * 2 + mDot1y;
+ // dot8 is skipped as redundant
+ mDot9x = cellSize * 2 + mDot7x;
+ mDot9y = mDot7y;
+ }
+
+ @Parameterized.Parameters
+ public static Collection primeNumbers() {
+ return Arrays.asList(192, 512, 768, 1024);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = InstrumentationRegistry.getContext();
+ mLockPatternView = new LockPatternView(mContext, null);
+ int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+ View.MeasureSpec.EXACTLY);
+ int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(mViewSize,
+ View.MeasureSpec.EXACTLY);
+ mLockPatternView.measure(widthMeasureSpec, heightMeasureSpec);
+ mLockPatternView.layout(0, 0, mLockPatternView.getMeasuredWidth(),
+ mLockPatternView.getMeasuredHeight());
+ }
+
+ @UiThreadTest
+ @Test
+ public void downStartsPattern() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void up_completesPattern() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, mDot1x, mDot1y, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternDetected(any());
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveToDot_hitsDot() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, mDot1x, mDot1y, 1));
+ verify(mPatternListener).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveOutside_doesNotHitsDot() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 2f, 2f, 1));
+ verify(mPatternListener, never()).onPatternStart();
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongTwoDots_hitsTwo() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot2x, mDot2y, 6);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot2x, mDot2y, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(2));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(0, 1)));
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongTwoDotsDiagonally_hitsTwo() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot5x, mDot5y, 6);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 3, MotionEvent.ACTION_UP, mDot5x, mDot5y, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(2));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0), LockPatternView.Cell.of(1, 1)));
+ }
+
+ @UiThreadTest
+ @Test
+ public void moveAlongZPattern_hitsDots() {
+ mLockPatternView.setOnPatternListener(mPatternListener);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 1f, 1f, 1));
+ makeMove(mDot1x, mDot1y, mDot3x + mDefaultError, mDot3y, 10);
+ makeMove(mDot3x - mDefaultError, mDot3y, mDot7x, mDot7y, 10);
+ makeMove(mDot7x, mDot7y - mDefaultError, mDot9x, mDot9y - mDefaultError, 10);
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, mViewSize - mDefaultError,
+ mViewSize - mDefaultError, 1));
+
+ verify(mPatternListener).onPatternDetected(mCellsArgumentCaptor.capture());
+ List<LockPatternView.Cell> patternCells = mCellsArgumentCaptor.getValue();
+ assertThat(patternCells, hasSize(7));
+ assertThat(patternCells,
+ contains(LockPatternView.Cell.of(0, 0),
+ LockPatternView.Cell.of(0, 1),
+ LockPatternView.Cell.of(0, 2),
+ LockPatternView.Cell.of(1, 1),
+ LockPatternView.Cell.of(2, 0),
+ LockPatternView.Cell.of(2, 1),
+ LockPatternView.Cell.of(2, 2)));
+ }
+
+ private void makeMove(float xFrom, float yFrom, float xTo, float yTo, int numberOfSteps) {
+ for (int i = 0; i < numberOfSteps; i++) {
+ float progress = i / (numberOfSteps - 1f);
+ float rest = 1f - progress;
+ mLockPatternView.onTouchEvent(
+ MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE,
+ /* x= */ xFrom * rest + xTo * progress,
+ /* y= */ yFrom * rest + yTo * progress,
+ 1));
+ }
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 31dd10a..e7961c9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -108,6 +108,16 @@
}
}
+ /**
+ * XDH represents Curve 25519 providers.
+ */
+ public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
+ // XDH is treated as EC.
+ public XDH() {
+ super(KeymasterDefs.KM_ALGORITHM_EC);
+ }
+ }
+
/*
* These must be kept in sync with system/security/keystore/defaults.h
*/
@@ -242,6 +252,23 @@
} catch (NullPointerException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
+ } else if (params instanceof NamedParameterSpec) {
+ NamedParameterSpec namedSpec = (NamedParameterSpec) params;
+ // Android Keystore cannot support initialization from a NamedParameterSpec
+ // because an alias for the key is needed (a KeyGenParameterSpec cannot be
+ // constructed).
+ if (namedSpec.getName().equalsIgnoreCase(NamedParameterSpec.X25519.getName())
+ || namedSpec.getName().equalsIgnoreCase(
+ NamedParameterSpec.ED25519.getName())) {
+ throw new IllegalArgumentException(
+ "This KeyPairGenerator cannot be initialized using NamedParameterSpec."
+ + " use " + KeyGenParameterSpec.class.getName() + " or "
+ + KeyPairGeneratorSpec.class.getName());
+ } else {
+ throw new InvalidAlgorithmParameterException(
+ "Unsupported algorithm specified via NamedParameterSpec: "
+ + namedSpec.getName());
+ }
} else {
throw new InvalidAlgorithmParameterException(
"Unsupported params class: " + params.getClass().getName()
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index e5d1276..d31499e 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -83,10 +83,12 @@
// java.security.KeyPairGenerator
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
+ put("KeyPairGenerator.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$XDH");
// java.security.KeyFactory
putKeyFactoryImpl("EC");
putKeyFactoryImpl("RSA");
+ putKeyFactoryImpl("XDH");
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index 89d7a40..b3becad 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -33,6 +33,12 @@
* The base adapter can be used for {@link RemoteAnimationTarget} that is simple open/close.
*/
class TaskFragmentAnimationAdapter {
+
+ /**
+ * If {@link #mOverrideLayer} is set to this value, we don't want to override the surface layer.
+ */
+ private static final int LAYER_NO_OVERRIDE = -1;
+
final Animation mAnimation;
final RemoteAnimationTarget mTarget;
final SurfaceControl mLeash;
@@ -42,6 +48,7 @@
final float[] mVecs = new float[4];
final Rect mRect = new Rect();
private boolean mIsFirstFrame = true;
+ private int mOverrideLayer = LAYER_NO_OVERRIDE;
TaskFragmentAnimationAdapter(@NonNull Animation animation,
@NonNull RemoteAnimationTarget target) {
@@ -58,10 +65,21 @@
mLeash = leash;
}
+ /**
+ * Surface layer to be set at the first frame of the animation. We will not set the layer if it
+ * is set to {@link #LAYER_NO_OVERRIDE}.
+ */
+ final void overrideLayer(int layer) {
+ mOverrideLayer = layer;
+ }
+
/** Called on frame update. */
final void onAnimationUpdate(@NonNull SurfaceControl.Transaction t, long currentPlayTime) {
if (mIsFirstFrame) {
t.show(mLeash);
+ if (mOverrideLayer != LAYER_NO_OVERRIDE) {
+ t.setLayer(mLeash, mOverrideLayer);
+ }
mIsFirstFrame = false;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 46bdf6d..1ac3317 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
+import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import android.animation.Animator;
import android.animation.ValueAnimator;
@@ -181,18 +182,22 @@
private List<TaskFragmentAnimationAdapter> createOpenAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets,
+ return createOpenCloseAnimationAdapters(targets, true /* isOpening */,
mAnimationSpec::loadOpenAnimation);
}
private List<TaskFragmentAnimationAdapter> createCloseAnimationAdapters(
@NonNull RemoteAnimationTarget[] targets) {
- return createOpenCloseAnimationAdapters(targets,
+ return createOpenCloseAnimationAdapters(targets, false /* isOpening */,
mAnimationSpec::loadCloseAnimation);
}
+ /**
+ * Creates {@link TaskFragmentAnimationAdapter} for OPEN and CLOSE types of transition.
+ * @param isOpening {@code true} for OPEN type, {@code false} for CLOSE type.
+ */
private List<TaskFragmentAnimationAdapter> createOpenCloseAnimationAdapters(
- @NonNull RemoteAnimationTarget[] targets,
+ @NonNull RemoteAnimationTarget[] targets, boolean isOpening,
@NonNull BiFunction<RemoteAnimationTarget, Rect, Animation> animationProvider) {
// We need to know if the target window is only a partial of the whole animation screen.
// If so, we will need to adjust it to make the whole animation screen looks like one.
@@ -210,14 +215,25 @@
}
}
+ // For OPEN transition, open windows should be above close windows.
+ // For CLOSE transition, open windows should be below close windows.
+ int offsetLayer = TYPE_LAYER_OFFSET;
final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
for (RemoteAnimationTarget target : openingTargets) {
- adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
- openingWholeScreenBounds));
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, openingWholeScreenBounds);
+ if (isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
}
for (RemoteAnimationTarget target : closingTargets) {
- adapters.add(createOpenCloseAnimationAdapter(target, animationProvider,
- closingWholeScreenBounds));
+ final TaskFragmentAnimationAdapter adapter = createOpenCloseAnimationAdapter(target,
+ animationProvider, closingWholeScreenBounds);
+ if (!isOpening) {
+ adapter.overrideLayer(offsetLayer++);
+ }
+ adapters.add(adapter);
}
return adapters;
}
diff --git a/libs/WindowManager/Shell/res/values-television/config.xml b/libs/WindowManager/Shell/res/values-television/config.xml
index 552048e..dcb4c10 100644
--- a/libs/WindowManager/Shell/res/values-television/config.xml
+++ b/libs/WindowManager/Shell/res/values-television/config.xml
@@ -33,4 +33,10 @@
<!-- The default gravity for the picture-in-picture window.
Currently, this maps to Gravity.BOTTOM | Gravity.RIGHT -->
<integer name="config_defaultPictureInPictureGravity">0x55</integer>
+
+ <!-- Fraction of screen width/height restricted keep clear areas can move the PiP. -->
+ <fraction name="config_pipMaxRestrictedMoveDistance">15%</fraction>
+
+ <!-- Duration (in milliseconds) the PiP stays stashed before automatically unstashing. -->
+ <integer name="config_pipStashDuration">5000</integer>
</resources>
diff --git a/libs/WindowManager/Shell/res/values-television/dimen.xml b/libs/WindowManager/Shell/res/values-television/dimen.xml
new file mode 100644
index 0000000..14e89f8
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-television/dimen.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<!-- These resources are around just to allow their values to be customized
+ for TV products. Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Padding between PIP and keep clear areas that caused it to move. -->
+ <dimen name="pip_keep_clear_area_padding">16dp</dimen>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml
index c7b8a13..09ed9b8 100644
--- a/libs/WindowManager/Shell/res/values/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values/strings_tv.xml
@@ -39,5 +39,10 @@
<!-- Button to collapse/shrink the picture-in-picture (PIP) window [CHAR LIMIT=30] -->
<string name="pip_collapse">Collapse PIP</string>
+
+ <!-- Educative text instructing the user to double press the HOME button to access the pip
+ controls menu [CHAR LIMIT=50] -->
+ <string name="pip_edu_text"> Double press <annotation icon="home_icon"> HOME </annotation> for
+ controls </string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
index 908a31d..8483f07 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java
@@ -21,6 +21,7 @@
import com.android.wm.shell.apppairs.AppPairsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
@@ -46,11 +47,13 @@
private final Optional<AppPairsController> mAppPairsOptional;
private final Optional<RecentTasksController> mRecentTasks;
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
public ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
@@ -60,6 +63,7 @@
Optional<RecentTasksController> recentTasks,
ShellExecutor mainExecutor) {
mShellTaskOrganizer = shellTaskOrganizer;
+ mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mRecentTasks = recentTasks;
mLegacySplitScreenOptional = legacySplitScreenOptional;
mSplitScreenOptional = splitScreenOptional;
@@ -92,6 +96,9 @@
pw.println();
pw.println();
mRecentTasks.ifPresent(recentTasks -> recentTasks.dump(pw, ""));
+ pw.println();
+ pw.println();
+ mKidsModeTaskOrganizer.dump(pw, "");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
index c3ce362..b729fe1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java
@@ -29,6 +29,7 @@
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.recents.RecentTasksController;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -48,6 +49,7 @@
private final DisplayInsetsController mDisplayInsetsController;
private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer;
+ private final KidsModeTaskOrganizer mKidsModeTaskOrganizer;
private final Optional<BubbleController> mBubblesOptional;
private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<AppPairsController> mAppPairsOptional;
@@ -68,6 +70,7 @@
DisplayInsetsController displayInsetsController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
@@ -84,6 +87,7 @@
mDisplayInsetsController = displayInsetsController;
mDragAndDropController = dragAndDropController;
mShellTaskOrganizer = shellTaskOrganizer;
+ mKidsModeTaskOrganizer = kidsModeTaskOrganizer;
mBubblesOptional = bubblesOptional;
mSplitScreenOptional = splitScreenOptional;
mAppPairsOptional = appPairsOptional;
@@ -136,6 +140,9 @@
mFullscreenUnfoldController.ifPresent(FullscreenUnfoldController::init);
mRecentTasks.ifPresent(RecentTasksController::init);
+
+ // Initialize kids mode task organizer
+ mKidsModeTaskOrganizer.initialize(mStartingWindow);
}
@ExternalThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 3f8343a..8442994 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -196,8 +196,8 @@
}
@VisibleForTesting
- ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
- Context context, @Nullable CompatUIController compatUI,
+ protected ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController,
+ ShellExecutor mainExecutor, Context context, @Nullable CompatUIController compatUI,
Optional<RecentTasksController> recentTasks) {
super(taskOrganizerController, mainExecutor);
mCompatUI = compatUI;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index d22fb50..4ba32e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -110,6 +110,14 @@
}
/**
+ * Get the InsetsState of a display.
+ */
+ public InsetsState getInsetsState(int displayId) {
+ final DisplayRecord r = mDisplays.get(displayId);
+ return r != null ? r.mInsetsState : null;
+ }
+
+ /**
* Updates the insets for a given display.
*/
public void updateDisplayInsets(int displayId, InsetsState state) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
index 1e934c5..1dd5ebc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java
@@ -69,7 +69,8 @@
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper windowManagerShellWrapper,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler) {
return Optional.of(
TvPipController.create(
context,
@@ -83,7 +84,8 @@
taskStackListener,
displayController,
windowManagerShellWrapper,
- mainExecutor));
+ mainExecutor,
+ mainHandler));
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 0362b3f..bf0337d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -68,6 +68,7 @@
import com.android.wm.shell.fullscreen.FullscreenUnfoldController;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.onehanded.OneHanded;
@@ -184,7 +185,23 @@
@WMSingleton
@Provides
- static Optional<CompatUI> provideCompatUI(CompatUIController compatUIController) {
+ static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler,
+ Context context,
+ CompatUIController compatUI,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasksOptional
+ ) {
+ return new KidsModeTaskOrganizer(mainExecutor, mainHandler, context, compatUI,
+ syncTransactionQueue, displayController, displayInsetsController,
+ recentTasksOptional);
+ }
+
+ @WMSingleton
+ @Provides static Optional<CompatUI> provideCompatUI(CompatUIController compatUIController) {
return Optional.of(compatUIController.asCompatUI());
}
@@ -637,6 +654,7 @@
DisplayInsetsController displayInsetsController,
DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<BubbleController> bubblesOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
@@ -653,6 +671,7 @@
displayInsetsController,
dragAndDropController,
shellTaskOrganizer,
+ kidsModeTaskOrganizer,
bubblesOptional,
splitScreenOptional,
appPairsOptional,
@@ -680,6 +699,7 @@
@Provides
static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
+ KidsModeTaskOrganizer kidsModeTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional,
@@ -688,7 +708,7 @@
Optional<AppPairsController> appPairsOptional,
Optional<RecentTasksController> recentTasksOptional,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellCommandHandlerImpl(shellTaskOrganizer,
+ return new ShellCommandHandlerImpl(shellTaskOrganizer, kidsModeTaskOrganizer,
legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional,
hideDisplayCutout, appPairsOptional, recentTasksOptional, mainExecutor);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
new file mode 100644
index 0000000..429eb99
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.kidsmode;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.view.InsetsSource;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.compatui.CompatUIController;
+import com.android.wm.shell.recents.RecentTasksController;
+import com.android.wm.shell.startingsurface.StartingWindowController;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * A dedicated task organizer when kids mode is enabled.
+ * - Creates a root task with bounds that exclude the navigation bar area
+ * - Launch all task into the root task except for Launcher
+ */
+public class KidsModeTaskOrganizer extends ShellTaskOrganizer {
+ private static final String TAG = "KidsModeTaskOrganizer";
+
+ private static final int[] CONTROLLED_ACTIVITY_TYPES =
+ {ACTIVITY_TYPE_UNDEFINED, ACTIVITY_TYPE_STANDARD};
+ private static final int[] CONTROLLED_WINDOWING_MODES =
+ {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
+
+ private final Handler mMainHandler;
+ private final Context mContext;
+ private final SyncTransactionQueue mSyncQueue;
+ private final DisplayController mDisplayController;
+ private final DisplayInsetsController mDisplayInsetsController;
+
+ @VisibleForTesting
+ ActivityManager.RunningTaskInfo mLaunchRootTask;
+ @VisibleForTesting
+ SurfaceControl mLaunchRootLeash;
+ @VisibleForTesting
+ final IBinder mCookie = new Binder();
+
+ private final InsetsState mInsetsState = new InsetsState();
+ private int mDisplayWidth;
+ private int mDisplayHeight;
+
+ private ForceShowNavigationBarSettingsObserver mForceShowNavigationBarSettingsObserver;
+ private boolean mEnabled;
+
+ DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
+ new DisplayController.OnDisplaysChangedListener() {
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ final DisplayLayout displayLayout =
+ mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout == null) {
+ return;
+ }
+ final int displayWidth = displayLayout.width();
+ final int displayHeight = displayLayout.height();
+ if (displayWidth == mDisplayWidth || displayHeight == mDisplayHeight) {
+ return;
+ }
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ updateBounds();
+ }
+ };
+
+ DisplayInsetsController.OnInsetsChangedListener mOnInsetsChangedListener =
+ new DisplayInsetsController.OnInsetsChangedListener() {
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ // Update bounds only when the insets of navigation bar or task bar is changed.
+ if (Objects.equals(insetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR),
+ mInsetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR))
+ && Objects.equals(insetsState.peekSource(
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR),
+ mInsetsState.peekSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR))) {
+ return;
+ }
+ mInsetsState.set(insetsState);
+ updateBounds();
+ }
+ };
+
+ @VisibleForTesting
+ KidsModeTaskOrganizer(
+ ITaskOrganizerController taskOrganizerController,
+ ShellExecutor mainExecutor,
+ Handler mainHandler,
+ Context context,
+ @Nullable CompatUIController compatUI,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasks,
+ ForceShowNavigationBarSettingsObserver forceShowNavigationBarSettingsObserver) {
+ super(taskOrganizerController, mainExecutor, context, compatUI, recentTasks);
+ mContext = context;
+ mMainHandler = mainHandler;
+ mSyncQueue = syncTransactionQueue;
+ mDisplayController = displayController;
+ mDisplayInsetsController = displayInsetsController;
+ mForceShowNavigationBarSettingsObserver = forceShowNavigationBarSettingsObserver;
+ }
+
+ public KidsModeTaskOrganizer(
+ ShellExecutor mainExecutor,
+ Handler mainHandler,
+ Context context,
+ @Nullable CompatUIController compatUI,
+ SyncTransactionQueue syncTransactionQueue,
+ DisplayController displayController,
+ DisplayInsetsController displayInsetsController,
+ Optional<RecentTasksController> recentTasks) {
+ super(mainExecutor, context, compatUI, recentTasks);
+ mContext = context;
+ mMainHandler = mainHandler;
+ mSyncQueue = syncTransactionQueue;
+ mDisplayController = displayController;
+ mDisplayInsetsController = displayInsetsController;
+ }
+
+ /**
+ * Initializes kids mode status.
+ */
+ public void initialize(StartingWindowController startingWindowController) {
+ initStartingWindow(startingWindowController);
+ if (mForceShowNavigationBarSettingsObserver == null) {
+ mForceShowNavigationBarSettingsObserver = new ForceShowNavigationBarSettingsObserver(
+ mMainHandler, mContext);
+ }
+ mForceShowNavigationBarSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
+ updateKidsModeState();
+ mForceShowNavigationBarSettingsObserver.register();
+ }
+
+ @Override
+ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ if (mEnabled && mLaunchRootTask == null && taskInfo.launchCookies != null
+ && taskInfo.launchCookies.contains(mCookie)) {
+ mLaunchRootTask = taskInfo;
+ mLaunchRootLeash = leash;
+ updateTask();
+ }
+ super.onTaskAppeared(taskInfo, leash);
+
+ mSyncQueue.runInSync(t -> {
+ // Reset several properties back to fullscreen (PiP, for example, leaves all these
+ // properties in a bad state).
+ t.setCrop(leash, null);
+ t.setPosition(leash, 0, 0);
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ t.show(leash);
+ });
+ }
+
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mLaunchRootTask != null && mLaunchRootTask.taskId == taskInfo.taskId
+ && !taskInfo.equals(mLaunchRootTask)) {
+ mLaunchRootTask = taskInfo;
+ }
+
+ super.onTaskInfoChanged(taskInfo);
+ }
+
+ @VisibleForTesting
+ void updateKidsModeState() {
+ final boolean enabled = mForceShowNavigationBarSettingsObserver.isEnabled();
+ if (mEnabled == enabled) {
+ return;
+ }
+ mEnabled = enabled;
+ if (mEnabled) {
+ enable();
+ } else {
+ disable();
+ }
+ }
+
+ @VisibleForTesting
+ void enable() {
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY);
+ if (displayLayout != null) {
+ mDisplayWidth = displayLayout.width();
+ mDisplayHeight = displayLayout.height();
+ }
+ mInsetsState.set(mDisplayController.getInsetsState(DEFAULT_DISPLAY));
+ mDisplayInsetsController.addInsetsChangedListener(DEFAULT_DISPLAY,
+ mOnInsetsChangedListener);
+ mDisplayController.addDisplayWindowListener(mOnDisplaysChangedListener);
+ List<TaskAppearedInfo> taskAppearedInfos = registerOrganizer();
+ for (int i = 0; i < taskAppearedInfos.size(); i++) {
+ final TaskAppearedInfo info = taskAppearedInfos.get(i);
+ onTaskAppeared(info.getTaskInfo(), info.getLeash());
+ }
+ createRootTask(DEFAULT_DISPLAY, WINDOWING_MODE_FULLSCREEN, mCookie);
+ updateTask();
+ }
+
+ @VisibleForTesting
+ void disable() {
+ mDisplayInsetsController.removeInsetsChangedListener(DEFAULT_DISPLAY,
+ mOnInsetsChangedListener);
+ mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
+ updateTask();
+ final WindowContainerToken token = mLaunchRootTask.token;
+ if (token != null) {
+ deleteRootTask(token);
+ }
+ mLaunchRootTask = null;
+ mLaunchRootLeash = null;
+ unregisterOrganizer();
+ }
+
+ private void updateTask() {
+ updateTask(getWindowContainerTransaction());
+ }
+
+ private void updateTask(WindowContainerTransaction wct) {
+ if (mLaunchRootTask == null || mLaunchRootLeash == null) {
+ return;
+ }
+ final Rect taskBounds = calculateBounds();
+ final WindowContainerToken rootToken = mLaunchRootTask.token;
+ wct.setBounds(rootToken, mEnabled ? taskBounds : null);
+ wct.setLaunchRoot(rootToken,
+ mEnabled ? CONTROLLED_WINDOWING_MODES : null,
+ mEnabled ? CONTROLLED_ACTIVITY_TYPES : null);
+ wct.reparentTasks(
+ mEnabled ? null : rootToken /* currentParent */,
+ mEnabled ? rootToken : null /* newParent */,
+ CONTROLLED_WINDOWING_MODES,
+ CONTROLLED_ACTIVITY_TYPES,
+ true /* onTop */);
+ wct.reorder(rootToken, mEnabled /* onTop */);
+ mSyncQueue.queue(wct);
+ final SurfaceControl rootLeash = mLaunchRootLeash;
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(rootLeash, taskBounds.left, taskBounds.top);
+ t.setWindowCrop(rootLeash, taskBounds.width(), taskBounds.height());
+ });
+ }
+
+ private Rect calculateBounds() {
+ final Rect bounds = new Rect(0, 0, mDisplayWidth, mDisplayHeight);
+ final InsetsSource navBarSource = mInsetsState.peekSource(InsetsState.ITYPE_NAVIGATION_BAR);
+ final InsetsSource taskBarSource = mInsetsState.peekSource(
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ if (navBarSource != null && !navBarSource.getFrame().isEmpty()) {
+ bounds.inset(navBarSource.calculateInsets(bounds, false /* ignoreVisibility */));
+ } else if (taskBarSource != null && !taskBarSource.getFrame().isEmpty()) {
+ bounds.inset(taskBarSource.calculateInsets(bounds, false /* ignoreVisibility */));
+ } else {
+ bounds.setEmpty();
+ }
+ return bounds;
+ }
+
+ private void updateBounds() {
+ if (mLaunchRootTask == null) {
+ return;
+ }
+ final WindowContainerTransaction wct = getWindowContainerTransaction();
+ final Rect taskBounds = calculateBounds();
+ wct.setBounds(mLaunchRootTask.token, taskBounds);
+ mSyncQueue.queue(wct);
+ final SurfaceControl finalLeash = mLaunchRootLeash;
+ mSyncQueue.runInSync(t -> {
+ t.setPosition(finalLeash, taskBounds.left, taskBounds.top);
+ t.setWindowCrop(finalLeash, taskBounds.width(), taskBounds.height());
+ });
+ }
+
+ @VisibleForTesting
+ WindowContainerTransaction getWindowContainerTransaction() {
+ return new WindowContainerTransaction();
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + " mEnabled=" + mEnabled);
+ pw.println(innerPrefix + " mLaunchRootTask=" + mLaunchRootTask);
+ pw.println(innerPrefix + " mLaunchRootLeash=" + mLaunchRootLeash);
+ pw.println(innerPrefix + " mDisplayWidth=" + mDisplayWidth);
+ pw.println(innerPrefix + " mDisplayHeight=" + mDisplayHeight);
+ pw.println(innerPrefix + " mInsetsState=" + mInsetsState);
+ super.dump(pw, innerPrefix);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 797df41..c2d5823 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -74,7 +74,7 @@
/**
* TODO: move the resources to SysUI package.
*/
- protected void reloadResources(Context context) {
+ private void reloadResources(Context context) {
final Resources res = context.getResources();
mDefaultAspectRatio = res.getFloat(
R.dimen.config_pictureInPictureDefaultAspectRatio);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index ddcd4bd..17d7f5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -55,11 +55,15 @@
public static final int STASH_TYPE_NONE = 0;
public static final int STASH_TYPE_LEFT = 1;
public static final int STASH_TYPE_RIGHT = 2;
+ public static final int STASH_TYPE_BOTTOM = 3;
+ public static final int STASH_TYPE_TOP = 4;
@IntDef(prefix = { "STASH_TYPE_" }, value = {
STASH_TYPE_NONE,
STASH_TYPE_LEFT,
- STASH_TYPE_RIGHT
+ STASH_TYPE_RIGHT,
+ STASH_TYPE_BOTTOM,
+ STASH_TYPE_TOP
})
@Retention(RetentionPolicy.SOURCE)
public @interface StashType {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 8ab78e6..72b93480 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -28,15 +28,21 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Size;
import android.view.Gravity;
import androidx.annotation.NonNull;
+import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
+
+import java.util.Set;
/**
* Contains pip bounds calculations that are specific to TV.
@@ -46,91 +52,129 @@
private static final String TAG = TvPipBoundsAlgorithm.class.getSimpleName();
private static final boolean DEBUG = TvPipController.DEBUG;
- private final @android.annotation.NonNull TvPipBoundsState mTvPipBoundsState;
+ private final @NonNull TvPipBoundsState mTvPipBoundsState;
private int mFixedExpandedHeightInPx;
private int mFixedExpandedWidthInPx;
+ private final TvPipKeepClearAlgorithm mKeepClearAlgorithm;
+
public TvPipBoundsAlgorithm(Context context,
@NonNull TvPipBoundsState tvPipBoundsState,
@NonNull PipSnapAlgorithm pipSnapAlgorithm) {
super(context, tvPipBoundsState, pipSnapAlgorithm);
this.mTvPipBoundsState = tvPipBoundsState;
+ this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm(SystemClock::uptimeMillis);
+ reloadResources(context);
}
- @Override
- protected void reloadResources(Context context) {
- super.reloadResources(context);
+ private void reloadResources(Context context) {
final Resources res = context.getResources();
mFixedExpandedHeightInPx = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_pictureInPictureExpandedHorizontalHeight);
mFixedExpandedWidthInPx = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_pictureInPictureExpandedVerticalWidth);
+ mKeepClearAlgorithm.setPipAreaPadding(
+ res.getDimensionPixelSize(R.dimen.pip_keep_clear_area_padding));
+ mKeepClearAlgorithm.setMaxRestrictedDistanceFraction(
+ res.getFraction(R.fraction.config_pipMaxRestrictedMoveDistance, 1, 1));
+ mKeepClearAlgorithm.setStashDuration(res.getInteger(R.integer.config_pipStashDuration));
+ }
+
+ @Override
+ public void onConfigurationChanged(Context context) {
+ super.onConfigurationChanged(context);
+ reloadResources(context);
}
/** Returns the destination bounds to place the PIP window on entry. */
@Override
public Rect getEntryDestinationBounds() {
if (DEBUG) Log.d(TAG, "getEntryDestinationBounds()");
- if (mTvPipBoundsState.getTvExpandedAspectRatio() != 0
+ if (mTvPipBoundsState.isTvExpandedPipSupported()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0
&& !mTvPipBoundsState.isTvPipManuallyCollapsed()) {
- updatePositionOnExpandToggled(Gravity.NO_GRAVITY, true);
+ updateExpandedPipSize();
+ updateGravityOnExpandToggled(Gravity.NO_GRAVITY, true);
+ mTvPipBoundsState.setTvPipExpanded(true);
}
- return getTvPipBounds(true);
+ return getTvPipBounds().getBounds();
}
/** Returns the current bounds adjusted to the new aspect ratio, if valid. */
@Override
public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
if (DEBUG) Log.d(TAG, "getAdjustedDestinationBounds: " + newAspectRatio);
- return getTvPipBounds(mTvPipBoundsState.isTvPipExpanded());
+ return getTvPipBounds().getBounds();
}
/**
- * The normal bounds at a different position on the screen.
+ * Calculates the PiP bounds.
*/
- public Rect getTvNormalBounds() {
- Rect normalBounds = getNormalBounds();
- Rect insetBounds = new Rect();
+ public Placement getTvPipBounds() {
+ final Size pipSize = getPipSize();
+ final Rect displayBounds = mTvPipBoundsState.getDisplayBounds();
+ final Size screenSize = new Size(displayBounds.width(), displayBounds.height());
+ final Rect insetBounds = new Rect();
getInsetBounds(insetBounds);
+ Set<Rect> restrictedKeepClearAreas = mTvPipBoundsState.getRestrictedKeepClearAreas();
+ Set<Rect> unrestrictedKeepClearAreas = mTvPipBoundsState.getUnrestrictedKeepClearAreas();
+
if (mTvPipBoundsState.isImeShowing()) {
if (DEBUG) Log.d(TAG, "IME showing, height: " + mTvPipBoundsState.getImeHeight());
- insetBounds.bottom -= mTvPipBoundsState.getImeHeight();
+
+ final Rect imeBounds = new Rect(
+ 0,
+ insetBounds.bottom - mTvPipBoundsState.getImeHeight(),
+ insetBounds.right,
+ insetBounds.bottom);
+
+ unrestrictedKeepClearAreas = new ArraySet<>(unrestrictedKeepClearAreas);
+ unrestrictedKeepClearAreas.add(imeBounds);
}
- Rect result = new Rect();
- Gravity.apply(mTvPipBoundsState.getTvPipGravity(), normalBounds.width(),
- normalBounds.height(), insetBounds, result);
+ mKeepClearAlgorithm.setGravity(mTvPipBoundsState.getTvPipGravity());
+ mKeepClearAlgorithm.setScreenSize(screenSize);
+ mKeepClearAlgorithm.setMovementBounds(insetBounds);
+ mKeepClearAlgorithm.setStashOffset(mTvPipBoundsState.getStashOffset());
+
+ final Placement placement = mKeepClearAlgorithm.calculatePipPosition(
+ pipSize,
+ restrictedKeepClearAreas,
+ unrestrictedKeepClearAreas);
if (DEBUG) {
- Log.d(TAG, "normalBounds: " + normalBounds.toShortString());
+ Log.d(TAG, "pipSize: " + pipSize);
+ Log.d(TAG, "screenSize: " + screenSize);
+ Log.d(TAG, "stashOffset: " + mTvPipBoundsState.getStashOffset());
Log.d(TAG, "insetBounds: " + insetBounds.toShortString());
+ Log.d(TAG, "pipSize: " + pipSize);
Log.d(TAG, "gravity: " + Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
- Log.d(TAG, "resultBounds: " + result.toShortString());
+ Log.d(TAG, "restrictedKeepClearAreas: " + restrictedKeepClearAreas);
+ Log.d(TAG, "unrestrictedKeepClearAreas: " + unrestrictedKeepClearAreas);
+ Log.d(TAG, "placement: " + placement);
}
- mTvPipBoundsState.setTvPipExpanded(false);
-
- return result;
+ return placement;
}
/**
- * @return previous gravity if it is to be saved, or Gravity.NO_GRAVITY if not.
+ * @return previous gravity if it is to be saved, or {@link Gravity#NO_GRAVITY} if not.
*/
- int updatePositionOnExpandToggled(int previousGravity, boolean expanding) {
+ int updateGravityOnExpandToggled(int previousGravity, boolean expanding) {
if (DEBUG) {
- Log.d(TAG, "updatePositionOnExpandToggle(), expanding: " + expanding
+ Log.d(TAG, "updateGravityOnExpandToggled(), expanding: " + expanding
+ ", mOrientation: " + mTvPipBoundsState.getTvFixedPipOrientation()
+ ", previous gravity: " + Gravity.toString(previousGravity));
}
- if (!mTvPipBoundsState.isTvExpandedPipEnabled()) {
+ if (!mTvPipBoundsState.isTvExpandedPipSupported()) {
return Gravity.NO_GRAVITY;
}
if (expanding && mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_UNDETERMINED) {
- float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio();
+ float expandedRatio = mTvPipBoundsState.getDesiredTvExpandedAspectRatio();
if (expandedRatio == 0) {
return Gravity.NO_GRAVITY;
}
@@ -139,7 +183,6 @@
} else {
mTvPipBoundsState.setTvFixedPipOrientation(ORIENTATION_HORIZONTAL);
}
-
}
int gravityToSave = Gravity.NO_GRAVITY;
@@ -181,10 +224,10 @@
}
/**
- * @return true if position changed
+ * @return true if gravity changed
*/
- boolean updatePosition(int keycode) {
- if (DEBUG) Log.d(TAG, "updatePosition, keycode: " + keycode);
+ boolean updateGravity(int keycode) {
+ if (DEBUG) Log.d(TAG, "updateGravity, keycode: " + keycode);
// Check if position change is valid
if (mTvPipBoundsState.isTvPipExpanded()) {
@@ -247,26 +290,31 @@
return false;
}
+ private Size getPipSize() {
+ final boolean isExpanded =
+ mTvPipBoundsState.isTvExpandedPipSupported() && mTvPipBoundsState.isTvPipExpanded()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0;
+ if (isExpanded) {
+ return mTvPipBoundsState.getTvExpandedSize();
+ } else {
+ final Rect normalBounds = getNormalBounds();
+ return new Size(normalBounds.width(), normalBounds.height());
+ }
+ }
+
/**
- * Calculates the PiP bounds.
+ * Updates {@link TvPipBoundsState#getTvExpandedSize()} based on
+ * {@link TvPipBoundsState#getDesiredTvExpandedAspectRatio()}, the screen size.
*/
- public Rect getTvPipBounds(boolean expandedIfPossible) {
- if (DEBUG) {
- Log.d(TAG, "getExpandedBoundsIfPossible with gravity "
- + Gravity.toString(mTvPipBoundsState.getTvPipGravity())
- + ", fixed orientation: " + mTvPipBoundsState.getTvFixedPipOrientation());
- }
+ void updateExpandedPipSize() {
+ final DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
+ final float expandedRatio =
+ mTvPipBoundsState.getDesiredTvExpandedAspectRatio(); // width / height
- if (!mTvPipBoundsState.isTvExpandedPipEnabled() || !expandedIfPossible) {
- return getTvNormalBounds();
- }
-
- DisplayLayout displayLayout = mTvPipBoundsState.getDisplayLayout();
- float expandedRatio = mTvPipBoundsState.getTvExpandedAspectRatio(); // width / height
- Size expandedSize;
+ final Size expandedSize;
if (expandedRatio == 0) {
- Log.d(TAG, "Expanded mode not supported");
- return getTvNormalBounds();
+ Log.d(TAG, "updateExpandedPipSize(): Expanded mode aspect ratio of 0 not supported");
+ return;
} else if (expandedRatio < 1) {
// vertical
if (mTvPipBoundsState.getTvFixedPipOrientation() == ORIENTATION_HORIZONTAL) {
@@ -300,26 +348,14 @@
}
}
- if (expandedSize == null) {
- return getTvNormalBounds();
- }
-
- if (DEBUG) {
- Log.d(TAG, "expanded size, width: " + expandedSize.getWidth()
- + ", height: " + expandedSize.getHeight());
- }
-
- Rect insetBounds = new Rect();
- getInsetBounds(insetBounds);
-
- Rect expandedBounds = new Rect();
- Gravity.apply(mTvPipBoundsState.getTvPipGravity(), expandedSize.getWidth(),
- expandedSize.getHeight(), insetBounds, expandedBounds);
- if (DEBUG) Log.d(TAG, "expanded bounds: " + expandedBounds.toShortString());
-
mTvPipBoundsState.setTvExpandedSize(expandedSize);
- mTvPipBoundsState.setTvPipExpanded(true);
- return expandedBounds;
+ if (DEBUG) {
+ Log.d(TAG, "updateExpandedPipSize(): expanded size, width=" + expandedSize.getWidth()
+ + ", height=" + expandedSize.getHeight());
+ }
}
+ void keepUnstashedForCurrentKeepClearAreas() {
+ mKeepClearAlgorithm.keepUnstashedForCurrentKeepClearAreas();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
index 9370e33..d880f82 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsState.java
@@ -53,10 +53,10 @@
public static final int DEFAULT_TV_GRAVITY = Gravity.BOTTOM | Gravity.RIGHT;
- private boolean mIsTvExpandedPipEnabled;
+ private final boolean mIsTvExpandedPipSupported;
private boolean mIsTvPipExpanded;
private boolean mTvPipManuallyCollapsed;
- private float mTvExpandedAspectRatio;
+ private float mDesiredTvExpandedAspectRatio;
private @Orientation int mTvFixedPipOrientation;
private int mTvPipGravity;
private @Nullable Size mTvExpandedSize;
@@ -64,8 +64,8 @@
public TvPipBoundsState(@NonNull Context context) {
super(context);
- setIsTvExpandedPipEnabled(context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE));
+ mIsTvExpandedPipSupported = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_EXPANDED_PICTURE_IN_PICTURE);
}
/**
@@ -75,7 +75,7 @@
public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
- setTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
+ setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
}
/** Resets the TV PiP state for a new activity. */
@@ -85,32 +85,32 @@
}
/** Set the tv expanded bounds of PIP */
- public void setTvExpandedSize(@Nullable Size bounds) {
- mTvExpandedSize = bounds;
+ public void setTvExpandedSize(@Nullable Size size) {
+ mTvExpandedSize = size;
}
- /** Get the PIP tv expanded bounds. */
+ /** Get the expanded size of the PiP. */
@Nullable
public Size getTvExpandedSize() {
return mTvExpandedSize;
}
/** Set the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
- public void setTvExpandedAspectRatio(float aspectRatio, boolean override) {
+ public void setDesiredTvExpandedAspectRatio(float aspectRatio, boolean override) {
if (override || mTvFixedPipOrientation == ORIENTATION_UNDETERMINED || aspectRatio == 0) {
- mTvExpandedAspectRatio = aspectRatio;
+ mDesiredTvExpandedAspectRatio = aspectRatio;
resetTvPipState();
return;
}
if ((aspectRatio > 1 && mTvFixedPipOrientation == ORIENTATION_HORIZONTAL)
|| (aspectRatio <= 1 && mTvFixedPipOrientation == ORIENTATION_VERTICAL)) {
- mTvExpandedAspectRatio = aspectRatio;
+ mDesiredTvExpandedAspectRatio = aspectRatio;
}
}
/** Get the PIP aspect ratio for the expanded PIP (TV) that is desired by the app. */
- public float getTvExpandedAspectRatio() {
- return mTvExpandedAspectRatio;
+ public float getDesiredTvExpandedAspectRatio() {
+ return mDesiredTvExpandedAspectRatio;
}
/** Sets the orientation the expanded TV PiP activity has been fixed to. */
@@ -154,13 +154,9 @@
return mTvPipManuallyCollapsed;
}
- /** Sets whether expanded PiP is supported by the device. */
- public void setIsTvExpandedPipEnabled(boolean enabled) {
- mIsTvExpandedPipEnabled = enabled;
+ /** Returns whether expanded PiP is supported by the device. */
+ public boolean isTvExpandedPipSupported() {
+ return mIsTvExpandedPipSupported;
}
- /** Returns whether expanded PiP is supported by the device. */
- public boolean isTvExpandedPipEnabled() {
- return mIsTvExpandedPipEnabled;
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 3c830e0..03c5e98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -30,9 +30,9 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.view.DisplayInfo;
import android.view.Gravity;
import com.android.wm.shell.R;
@@ -45,9 +45,11 @@
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
+import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,6 +64,7 @@
private static final String TAG = "TvPipController";
static final boolean DEBUG = false;
+ private static final double EPS = 1e-7;
private static final int NONEXISTENT_TASK_ID = -1;
@Retention(RetentionPolicy.SOURCE)
@@ -97,11 +100,13 @@
private final TvPipNotificationController mPipNotificationController;
private final TvPipMenuController mTvPipMenuController;
private final ShellExecutor mMainExecutor;
+ private final Handler mMainHandler;
private final TvPipImpl mImpl = new TvPipImpl();
private @State int mState = STATE_NO_PIP;
private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY;
private int mPinnedTaskId = NONEXISTENT_TASK_ID;
+ private Runnable mUnstashRunnable;
private int mResizeAnimationDuration;
@@ -117,7 +122,8 @@
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
return new TvPipController(
context,
tvPipBoundsState,
@@ -130,7 +136,8 @@
taskStackListener,
displayController,
wmShell,
- mainExecutor).mImpl;
+ mainExecutor,
+ mainHandler).mImpl;
}
private TvPipController(
@@ -145,9 +152,11 @@
TaskStackListenerImpl taskStackListener,
DisplayController displayController,
WindowManagerShellWrapper wmShell,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Handler mainHandler) {
mContext = context;
mMainExecutor = mainExecutor;
+ mMainHandler = mainHandler;
mTvPipBoundsState = tvPipBoundsState;
mTvPipBoundsState.setDisplayId(context.getDisplayId());
@@ -182,6 +191,7 @@
loadConfigurations();
mPipNotificationController.onConfigurationChanged(mContext);
+ mTvPipBoundsAlgorithm.onConfigurationChanged(mContext);
}
/**
@@ -206,13 +216,20 @@
}
setState(STATE_PIP_MENU);
- movePinnedStack();
+ updatePinnedStackBounds();
}
@Override
public void closeMenu() {
if (DEBUG) Log.d(TAG, "closeMenu(), state before=" + stateToName(mState));
setState(STATE_PIP);
+ mTvPipBoundsAlgorithm.keepUnstashedForCurrentKeepClearAreas();
+ updatePinnedStackBounds();
+ }
+
+ @Override
+ public void onInMoveModeChanged() {
+ updatePinnedStackBounds();
}
/**
@@ -231,21 +248,21 @@
if (DEBUG) Log.d(TAG, "togglePipExpansion()");
boolean expanding = !mTvPipBoundsState.isTvPipExpanded();
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, expanding);
+ .updateGravityOnExpandToggled(mPreviousGravity, expanding);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipManuallyCollapsed(!expanding);
mTvPipBoundsState.setTvPipExpanded(expanding);
- movePinnedStack();
+ updatePinnedStackBounds();
}
@Override
public void movePip(int keycode) {
- if (mTvPipBoundsAlgorithm.updatePosition(keycode)) {
+ if (mTvPipBoundsAlgorithm.updateGravity(keycode)) {
mTvPipMenuController.updateGravity(mTvPipBoundsState.getTvPipGravity());
mPreviousGravity = Gravity.NO_GRAVITY;
- movePinnedStack();
+ updatePinnedStackBounds();
} else {
if (DEBUG) Log.d(TAG, "Position hasn't changed");
}
@@ -265,20 +282,48 @@
Set<Rect> unrestricted) {
if (mTvPipBoundsState.getDisplayId() == displayId) {
mTvPipBoundsState.setKeepClearAreas(restricted, unrestricted);
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
/**
- * Animate to the updated position of the PiP based on the state and position of the PiP.
+ * Update the PiP bounds based on the state of the PiP and keep clear areas.
+ * Animates to the current PiP bounds, and schedules unstashing the PiP if necessary.
*/
- private void movePinnedStack() {
+ private void updatePinnedStackBounds() {
if (mState == STATE_NO_PIP) {
return;
}
- Rect bounds = mTvPipBoundsAlgorithm.getTvPipBounds(mTvPipBoundsState.isTvPipExpanded());
- if (DEBUG) Log.d(TAG, "movePinnedStack() - new pip bounds: " + bounds.toShortString());
+ final boolean stayAtAnchorPosition = mTvPipMenuController.isInMoveMode();
+ final boolean disallowStashing = mState == STATE_PIP_MENU || stayAtAnchorPosition;
+ final Placement placement = mTvPipBoundsAlgorithm.getTvPipBounds();
+
+ int stashType =
+ disallowStashing ? PipBoundsState.STASH_TYPE_NONE : placement.getStashType();
+ mTvPipBoundsState.setStashed(stashType);
+
+ if (stayAtAnchorPosition) {
+ movePinnedStackTo(placement.getAnchorBounds());
+ } else if (disallowStashing) {
+ movePinnedStackTo(placement.getUnstashedBounds());
+ } else {
+ movePinnedStackTo(placement.getBounds());
+ }
+
+ if (mUnstashRunnable != null) {
+ mMainHandler.removeCallbacks(mUnstashRunnable);
+ mUnstashRunnable = null;
+ }
+ if (!disallowStashing && placement.getUnstashDestinationBounds() != null) {
+ mUnstashRunnable = () -> movePinnedStackTo(placement.getUnstashDestinationBounds());
+ mMainHandler.postAtTime(mUnstashRunnable, placement.getUnstashTime());
+ }
+ }
+
+ /** Animates the PiP to the given bounds. */
+ private void movePinnedStackTo(Rect bounds) {
+ if (DEBUG) Log.d(TAG, "movePinnedStackTo() - new pip bounds: " + bounds.toShortString());
mPipTaskOrganizer.scheduleAnimateResizePip(bounds,
mResizeAnimationDuration, rect -> {
if (DEBUG) Log.d(TAG, "movePinnedStack() animation done");
@@ -359,6 +404,8 @@
if (DEBUG) Log.d(TAG, " > show menu");
mTvPipMenuController.showMenu();
}
+
+ updatePinnedStackBounds();
}
private void loadConfigurations() {
@@ -366,12 +413,6 @@
mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
}
- private DisplayInfo getDisplayInfo() {
- final DisplayInfo displayInfo = new DisplayInfo();
- mContext.getDisplay().getDisplayInfo(displayInfo);
- return displayInfo;
- }
-
private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) {
taskStackListener.addListener(new TaskStackListenerCallback() {
@Override
@@ -417,7 +458,7 @@
mTvPipBoundsState.setImeVisibility(imeVisible, imeHeight);
if (mState != STATE_NO_PIP) {
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
@@ -429,7 +470,7 @@
mTvPipBoundsState.setAspectRatio(ratio);
if (!mTvPipBoundsState.isTvPipExpanded() && ratioChanged) {
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
@@ -438,41 +479,45 @@
if (DEBUG) Log.d(TAG, "onExpandedAspectRatioChanged: " + ratio);
// 0) No update to the ratio --> don't do anything
- if (mTvPipBoundsState.getTvExpandedAspectRatio() == ratio) {
+
+ if (Math.abs(mTvPipBoundsState.getDesiredTvExpandedAspectRatio() - ratio)
+ < EPS) {
return;
}
- mTvPipBoundsState.setTvExpandedAspectRatio(ratio, false);
+ mTvPipBoundsState.setDesiredTvExpandedAspectRatio(ratio, false);
// 1) PiP is expanded and only aspect ratio changed, but wasn't disabled
// --> update bounds, but don't toggle
if (mTvPipBoundsState.isTvPipExpanded() && ratio != 0) {
- movePinnedStack();
+ mTvPipBoundsAlgorithm.updateExpandedPipSize();
+ updatePinnedStackBounds();
}
// 2) PiP is expanded, but expanded PiP was disabled
// --> collapse PiP
if (mTvPipBoundsState.isTvPipExpanded() && ratio == 0) {
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, false);
+ .updateGravityOnExpandToggled(mPreviousGravity, false);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipExpanded(false);
- movePinnedStack();
+ updatePinnedStackBounds();
}
// 3) PiP not expanded and not manually collapsed and expand was enabled
// --> expand to new ratio
if (!mTvPipBoundsState.isTvPipExpanded() && ratio != 0
&& !mTvPipBoundsState.isTvPipManuallyCollapsed()) {
+ mTvPipBoundsAlgorithm.updateExpandedPipSize();
int saveGravity = mTvPipBoundsAlgorithm
- .updatePositionOnExpandToggled(mPreviousGravity, true);
+ .updateGravityOnExpandToggled(mPreviousGravity, true);
if (saveGravity != Gravity.NO_GRAVITY) {
mPreviousGravity = saveGravity;
}
mTvPipBoundsState.setTvPipExpanded(true);
- movePinnedStack();
+ updatePinnedStackBounds();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
new file mode 100644
index 0000000..5ac7a72
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithm.kt
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.pip.tv
+
+import android.graphics.Point
+import android.graphics.Rect
+import android.util.Size
+import android.view.Gravity
+import com.android.wm.shell.pip.PipBoundsState
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_BOTTOM
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_TOP
+import kotlin.math.abs
+import kotlin.math.max
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+private const val DEFAULT_PIP_MARGINS = 48
+private const val DEFAULT_STASH_DURATION = 5000L
+private const val RELAX_DEPTH = 1
+private const val DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION = 0.15
+
+/**
+ * This class calculates an appropriate position for a Picture-In-Picture (PiP) window, taking
+ * into account app defined keep clear areas.
+ *
+ * @param clock A function returning a current timestamp (in milliseconds)
+ */
+class TvPipKeepClearAlgorithm(private val clock: () -> Long) {
+ /**
+ * Result of the positioning algorithm.
+ *
+ * @param bounds The bounds the PiP should be placed at
+ * @param anchorBounds The bounds of the PiP anchor position
+ * (where the PiP would be placed if there were no keep clear areas)
+ * @param stashType Where the PiP has been stashed, if at all
+ * @param unstashDestinationBounds If stashed, the PiP should move to this position after
+ * [stashDuration] has passed.
+ * @param unstashTime If stashed, the time at which the PiP should move
+ * to [unstashDestinationBounds]
+ */
+ data class Placement(
+ val bounds: Rect,
+ val anchorBounds: Rect,
+ @PipBoundsState.StashType val stashType: Int = STASH_TYPE_NONE,
+ val unstashDestinationBounds: Rect? = null,
+ val unstashTime: Long = 0L
+ ) {
+ /** Bounds to use if the PiP should not be stashed. */
+ fun getUnstashedBounds() = unstashDestinationBounds ?: bounds
+ }
+
+ /** The size of the screen */
+ private var screenSize = Size(0, 0)
+
+ /** The bounds the PiP is allowed to move in */
+ private var movementBounds = Rect()
+
+ /** Padding to add between a keep clear area that caused the PiP to move and the PiP */
+ var pipAreaPadding = DEFAULT_PIP_MARGINS
+
+ /** The distance the PiP peeks into the screen when stashed */
+ var stashOffset = DEFAULT_PIP_MARGINS
+
+ /**
+ * How long (in milliseconds) the PiP should stay stashed for after the last time the
+ * keep clear areas causing the PiP to stash have changed.
+ */
+ var stashDuration = DEFAULT_STASH_DURATION
+
+ /** The fraction of screen width/height restricted keep clear areas can move the PiP */
+ var maxRestrictedDistanceFraction = DEFAULT_MAX_RESTRICTED_DISTANCE_FRACTION
+
+ private var pipGravity = Gravity.BOTTOM or Gravity.RIGHT
+ private var transformedScreenBounds = Rect()
+ private var transformedMovementBounds = Rect()
+
+ private var lastAreasOverlappingUnstashPosition: Set<Rect> = emptySet()
+ private var lastStashTime: Long = Long.MIN_VALUE
+
+ /**
+ * Calculates the position the PiP should be placed at, taking into consideration the
+ * given keep clear areas.
+ *
+ * Restricted keep clear areas can move the PiP only by a limited amount, and may be ignored
+ * if there is no space for the PiP to move to.
+ * Apps holding the permission [android.Manifest.permission.USE_UNRESTRICTED_KEEP_CLEAR_AREAS]
+ * can declare unrestricted keep clear areas, which can move the PiP farther and placement will
+ * always try to respect these areas.
+ *
+ * If no free space the PiP is allowed to move to can be found, a stashed position is returned
+ * as [Placement.bounds], along with a position to move to once [Placement.unstashTime] has
+ * passed as [Placement.unstashDestinationBounds].
+ *
+ * @param pipSize The size of the PiP window
+ * @param restrictedAreas The restricted keep clear areas
+ * @param unrestrictedAreas The unrestricted keep clear areas
+ *
+ */
+ fun calculatePipPosition(
+ pipSize: Size,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Placement {
+ val transformedRestrictedAreas = transformAndFilterAreas(restrictedAreas)
+ val transformedUnrestrictedAreas = transformAndFilterAreas(unrestrictedAreas)
+ val pipAnchorBounds = getNormalPipAnchorBounds(pipSize, transformedMovementBounds)
+
+ val result = calculatePipPositionTransformed(
+ pipAnchorBounds,
+ transformedRestrictedAreas,
+ transformedUnrestrictedAreas
+ )
+
+ val screenSpaceBounds = fromTransformedSpace(result.bounds)
+ return Placement(
+ screenSpaceBounds,
+ fromTransformedSpace(result.anchorBounds),
+ getStashType(screenSpaceBounds, movementBounds),
+ result.unstashDestinationBounds?.let { fromTransformedSpace(it) },
+ result.unstashTime
+ )
+ }
+
+ /**
+ * Filters out areas that encompass the entire movement bounds and returns them mapped to
+ * the base case space.
+ *
+ * Areas encompassing the entire movement bounds can occur when a full-screen View gets focused,
+ * but we don't want this to cause the PiP to get stashed.
+ */
+ private fun transformAndFilterAreas(areas: Set<Rect>): Set<Rect> {
+ return areas.mapNotNullTo(mutableSetOf()) {
+ when {
+ it.contains(movementBounds) -> null
+ else -> toTransformedSpace(it)
+ }
+ }
+ }
+
+ /**
+ * Calculates the position the PiP should be placed at, taking into consideration the
+ * given keep clear areas.
+ * All parameters are transformed from screen space to the base case space, where the PiP
+ * anchor is in the bottom right corner / on the right side.
+ *
+ * @see [calculatePipPosition]
+ */
+ private fun calculatePipPositionTransformed(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Placement {
+ if (restrictedAreas.isEmpty() && unrestrictedAreas.isEmpty()) {
+ return Placement(pipAnchorBounds, pipAnchorBounds)
+ }
+
+ // First try to find a free position to move to
+ val freeMovePos = findFreeMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ if (freeMovePos != null) {
+ lastAreasOverlappingUnstashPosition = emptySet()
+ return Placement(freeMovePos, pipAnchorBounds)
+ }
+
+ // If no free position is found, we have to stash the PiP.
+ // Find the position the PiP should return to once it unstashes by doing a relaxed
+ // search, or ignoring restricted areas, or returning to the anchor position
+ val unstashBounds =
+ findRelaxedMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ ?: findFreeMovePosition(pipAnchorBounds, emptySet(), unrestrictedAreas)
+ ?: pipAnchorBounds
+
+ val keepClearAreas = restrictedAreas + unrestrictedAreas
+ val areasOverlappingUnstashPosition =
+ keepClearAreas.filter { Rect.intersects(it, unstashBounds) }.toSet()
+ val areasOverlappingUnstashPositionChanged =
+ !lastAreasOverlappingUnstashPosition.containsAll(areasOverlappingUnstashPosition)
+ lastAreasOverlappingUnstashPosition = areasOverlappingUnstashPosition
+
+ val now = clock()
+ if (areasOverlappingUnstashPositionChanged) {
+ lastStashTime = now
+ }
+
+ // If overlapping areas haven't changed and the stash duration has passed, we can
+ // place the PiP at the unstash position
+ val unstashTime = lastStashTime + stashDuration
+ if (now >= unstashTime) {
+ return Placement(unstashBounds, pipAnchorBounds)
+ }
+
+ // Otherwise, we'll stash it close to the unstash position
+ val stashedBounds = getNearbyStashedPosition(unstashBounds, keepClearAreas)
+ return Placement(
+ stashedBounds,
+ pipAnchorBounds,
+ getStashType(stashedBounds, transformedMovementBounds),
+ unstashBounds,
+ unstashTime
+ )
+ }
+
+ @PipBoundsState.StashType
+ private fun getStashType(stashedBounds: Rect, movementBounds: Rect): Int {
+ return when {
+ stashedBounds.left < movementBounds.left -> STASH_TYPE_LEFT
+ stashedBounds.right > movementBounds.right -> STASH_TYPE_RIGHT
+ stashedBounds.top < movementBounds.top -> STASH_TYPE_TOP
+ stashedBounds.bottom > movementBounds.bottom -> STASH_TYPE_BOTTOM
+ else -> STASH_TYPE_NONE
+ }
+ }
+
+ private fun findRelaxedMovePosition(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ if (RELAX_DEPTH <= 0) {
+ // relaxed search disabled
+ return null
+ }
+
+ return findRelaxedMovePosition(
+ RELAX_DEPTH,
+ pipAnchorBounds,
+ restrictedAreas.toMutableSet(),
+ unrestrictedAreas
+ )
+ }
+
+ private fun findRelaxedMovePosition(
+ depth: Int,
+ pipAnchorBounds: Rect,
+ restrictedAreas: MutableSet<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ if (depth == 0) {
+ return findFreeMovePosition(pipAnchorBounds, restrictedAreas, unrestrictedAreas)
+ }
+
+ val candidates = mutableListOf<Rect>()
+ val areasToExclude = restrictedAreas.toList()
+ for (area in areasToExclude) {
+ restrictedAreas.remove(area)
+ val candidate = findRelaxedMovePosition(
+ depth - 1,
+ pipAnchorBounds,
+ restrictedAreas,
+ unrestrictedAreas
+ )
+ restrictedAreas.add(area)
+
+ if (candidate != null) {
+ candidates.add(candidate)
+ }
+ }
+ return candidates.minByOrNull { candidateCost(it, pipAnchorBounds) }
+ }
+
+ /** Cost function to evaluate candidate bounds */
+ private fun candidateCost(candidateBounds: Rect, pipAnchorBounds: Rect): Int {
+ // squared euclidean distance of corresponding rect corners
+ val dx = candidateBounds.left - pipAnchorBounds.left
+ val dy = candidateBounds.top - pipAnchorBounds.top
+ return dx * dx + dy * dy
+ }
+
+ private fun findFreeMovePosition(
+ pipAnchorBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): Rect? {
+ val movementBounds = transformedMovementBounds
+ val candidateEdgeRects = mutableListOf<Rect>()
+ val minRestrictedLeft =
+ pipAnchorBounds.right - screenSize.width * maxRestrictedDistanceFraction
+
+ candidateEdgeRects.add(
+ movementBounds.offsetCopy(movementBounds.width() + pipAreaPadding, 0)
+ )
+ candidateEdgeRects.addAll(unrestrictedAreas)
+ candidateEdgeRects.addAll(restrictedAreas.filter { it.left >= minRestrictedLeft })
+
+ // throw out edges that are too close to the left screen edge to fit the PiP
+ val minLeft = movementBounds.left + pipAnchorBounds.width()
+ candidateEdgeRects.retainAll { it.left - pipAreaPadding > minLeft }
+ candidateEdgeRects.sortBy { -it.left }
+
+ val maxRestrictedDY = (screenSize.height * maxRestrictedDistanceFraction).roundToInt()
+
+ val candidateBounds = mutableListOf<Rect>()
+ for (edgeRect in candidateEdgeRects) {
+ val edge = edgeRect.left - pipAreaPadding
+ val dx = (edge - pipAnchorBounds.width()) - pipAnchorBounds.left
+ val candidatePipBounds = pipAnchorBounds.offsetCopy(dx, 0)
+ val searchUp = true
+ val searchDown = !isPipAnchoredToCorner()
+
+ if (searchUp) {
+ val event = findMinMoveUp(candidatePipBounds, restrictedAreas, unrestrictedAreas)
+ val padding = if (event.start) 0 else pipAreaPadding
+ val dy = event.pos - pipAnchorBounds.bottom - padding
+ val maxDY = if (event.unrestricted) movementBounds.height() else maxRestrictedDY
+ val candidate = pipAnchorBounds.offsetCopy(dx, dy)
+ val isOnScreen = candidate.top > movementBounds.top
+ val hangingMidAir = !candidate.intersectsY(edgeRect)
+ if (isOnScreen && abs(dy) <= maxDY && !hangingMidAir) {
+ candidateBounds.add(candidate)
+ }
+ }
+
+ if (searchDown) {
+ val event = findMinMoveDown(candidatePipBounds, restrictedAreas, unrestrictedAreas)
+ val padding = if (event.start) 0 else pipAreaPadding
+ val dy = event.pos - pipAnchorBounds.top + padding
+ val maxDY = if (event.unrestricted) movementBounds.height() else maxRestrictedDY
+ val candidate = pipAnchorBounds.offsetCopy(dx, dy)
+ val isOnScreen = candidate.bottom < movementBounds.bottom
+ val hangingMidAir = !candidate.intersectsY(edgeRect)
+ if (isOnScreen && abs(dy) <= maxDY && !hangingMidAir) {
+ candidateBounds.add(candidate)
+ }
+ }
+ }
+
+ candidateBounds.sortBy { candidateCost(it, pipAnchorBounds) }
+ return candidateBounds.firstOrNull()
+ }
+
+ private fun getNearbyStashedPosition(bounds: Rect, keepClearAreas: Set<Rect>): Rect {
+ val screenBounds = transformedScreenBounds
+ val stashCandidates = Array(2) { Rect(bounds) }
+ val areasOverlappingPipX = keepClearAreas.filter { it.intersectsX(bounds) }
+ val areasOverlappingPipY = keepClearAreas.filter { it.intersectsY(bounds) }
+
+ if (screenBounds.bottom - bounds.bottom <= bounds.top - screenBounds.top) {
+ // bottom is closer than top, stash downwards
+ val fullStashTop = screenBounds.bottom - stashOffset
+
+ val maxBottom = areasOverlappingPipX.maxByOrNull { it.bottom }!!.bottom
+ val partialStashTop = maxBottom + pipAreaPadding
+
+ val downPosition = stashCandidates[0]
+ downPosition.offsetTo(bounds.left, min(fullStashTop, partialStashTop))
+ } else {
+ // top is closer than bottom, stash upwards
+ val fullStashY = screenBounds.top - bounds.height() + stashOffset
+
+ val minTop = areasOverlappingPipX.minByOrNull { it.top }!!.top
+ val partialStashY = minTop - bounds.height() - pipAreaPadding
+
+ val upPosition = stashCandidates[0]
+ upPosition.offsetTo(bounds.left, max(fullStashY, partialStashY))
+ }
+
+ if (screenBounds.right - bounds.right <= bounds.left - screenBounds.left) {
+ // right is closer than left, stash rightwards
+ val fullStashLeft = screenBounds.right - stashOffset
+
+ val maxRight = areasOverlappingPipY.maxByOrNull { it.right }!!.right
+ val partialStashLeft = maxRight + pipAreaPadding
+
+ val rightPosition = stashCandidates[1]
+ rightPosition.offsetTo(min(fullStashLeft, partialStashLeft), bounds.top)
+ } else {
+ // left is closer than right, stash leftwards
+ val fullStashLeft = screenBounds.left - bounds.width() + stashOffset
+
+ val minLeft = areasOverlappingPipY.minByOrNull { it.left }!!.left
+ val partialStashLeft = minLeft - bounds.width() - pipAreaPadding
+
+ val rightPosition = stashCandidates[1]
+ rightPosition.offsetTo(max(fullStashLeft, partialStashLeft), bounds.top)
+ }
+
+ return stashCandidates.minByOrNull {
+ val dx = abs(it.left - bounds.left)
+ val dy = abs(it.top - bounds.top)
+ dx * bounds.height() + dy * bounds.width()
+ }!!
+ }
+
+ /**
+ * Prevents the PiP from being stashed for the current set of keep clear areas.
+ * The PiP may stash again if keep clear areas change.
+ */
+ fun keepUnstashedForCurrentKeepClearAreas() {
+ lastStashTime = Long.MIN_VALUE
+ }
+
+ /**
+ * Updates the size of the screen.
+ *
+ * @param size The new size of the screen
+ */
+ fun setScreenSize(size: Size) {
+ if (screenSize == size) {
+ return
+ }
+
+ screenSize = size
+ transformedScreenBounds =
+ toTransformedSpace(Rect(0, 0, screenSize.width, screenSize.height))
+ transformedMovementBounds = toTransformedSpace(transformedMovementBounds)
+ }
+
+ /**
+ * Updates the bounds within which the PiP is allowed to move.
+ *
+ * @param bounds The new movement bounds
+ */
+ fun setMovementBounds(bounds: Rect) {
+ if (movementBounds == bounds) {
+ return
+ }
+
+ movementBounds.set(bounds)
+ transformedMovementBounds = toTransformedSpace(movementBounds)
+ }
+
+ /**
+ * Sets the corner/side of the PiP's home position.
+ */
+ fun setGravity(gravity: Int) {
+ if (pipGravity == gravity) return
+
+ pipGravity = gravity
+ transformedScreenBounds =
+ toTransformedSpace(Rect(0, 0, screenSize.width, screenSize.height))
+ transformedMovementBounds = toTransformedSpace(movementBounds)
+ }
+
+ /**
+ * @param open Whether this event marks the opening of an occupied segment
+ * @param pos The coordinate of this event
+ * @param unrestricted Whether this event was generated by an unrestricted keep clear area
+ * @param start Marks the special start event. Earlier events are skipped when sweeping
+ */
+ data class SweepLineEvent(
+ val open: Boolean,
+ val pos: Int,
+ val unrestricted: Boolean,
+ val start: Boolean = false
+ )
+
+ /**
+ * Returns a [SweepLineEvent] representing the minimal move up from [pipBounds] that clears
+ * the given keep clear areas.
+ */
+ private fun findMinMoveUp(
+ pipBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): SweepLineEvent {
+ val events = mutableListOf<SweepLineEvent>()
+ val generateEvents: (Boolean) -> (Rect) -> Unit = { unrestricted ->
+ { area ->
+ if (pipBounds.intersectsX(area)) {
+ events.add(SweepLineEvent(true, area.bottom, unrestricted))
+ events.add(SweepLineEvent(false, area.top, unrestricted))
+ }
+ }
+ }
+
+ restrictedAreas.forEach(generateEvents(false))
+ unrestrictedAreas.forEach(generateEvents(true))
+
+ return sweepLineFindEarliestGap(
+ events,
+ pipBounds.height() + pipAreaPadding,
+ pipBounds.bottom,
+ pipBounds.height()
+ )
+ }
+
+ /**
+ * Returns a [SweepLineEvent] representing the minimal move down from [pipBounds] that clears
+ * the given keep clear areas.
+ */
+ private fun findMinMoveDown(
+ pipBounds: Rect,
+ restrictedAreas: Set<Rect>,
+ unrestrictedAreas: Set<Rect>
+ ): SweepLineEvent {
+ val events = mutableListOf<SweepLineEvent>()
+ val generateEvents: (Boolean) -> (Rect) -> Unit = { unrestricted ->
+ { area ->
+ if (pipBounds.intersectsX(area)) {
+ events.add(SweepLineEvent(true, -area.top, unrestricted))
+ events.add(SweepLineEvent(false, -area.bottom, unrestricted))
+ }
+ }
+ }
+
+ restrictedAreas.forEach(generateEvents(false))
+ unrestrictedAreas.forEach(generateEvents(true))
+
+ val earliestEvent = sweepLineFindEarliestGap(
+ events,
+ pipBounds.height() + pipAreaPadding,
+ -pipBounds.top,
+ pipBounds.height()
+ )
+
+ return earliestEvent.copy(pos = -earliestEvent.pos)
+ }
+
+ /**
+ * Takes a list of events representing the starts & ends of occupied segments, and
+ * returns the earliest event whose position is unoccupied and has [gapSize] distance to the
+ * next event.
+ *
+ * @param events List of [SweepLineEvent] representing occupied segments
+ * @param gapSize Size of the gap to search for
+ * @param startPos The position to start the search on.
+ * Inserts a special event marked with [SweepLineEvent.start].
+ * @param startGapSize Used instead of [gapSize] for the start event
+ */
+ private fun sweepLineFindEarliestGap(
+ events: MutableList<SweepLineEvent>,
+ gapSize: Int,
+ startPos: Int,
+ startGapSize: Int
+ ): SweepLineEvent {
+ events.add(
+ SweepLineEvent(
+ open = false,
+ pos = startPos,
+ unrestricted = true,
+ start = true
+ )
+ )
+ events.sortBy { -it.pos }
+
+ // sweep
+ var openCount = 0
+ var i = 0
+ while (i < events.size) {
+ val event = events[i]
+ if (!event.start) {
+ if (event.open) {
+ openCount++
+ } else {
+ openCount--
+ }
+ }
+
+ if (openCount == 0) {
+ // check if placement is possible
+ val candidate = event.pos
+ if (candidate > startPos) {
+ i++
+ continue
+ }
+
+ val eventGapSize = if (event.start) startGapSize else gapSize
+ val nextEvent = events.getOrNull(i + 1)
+ if (nextEvent == null || nextEvent.pos < candidate - eventGapSize) {
+ return event
+ }
+ }
+ i++
+ }
+
+ return events.last()
+ }
+
+ private fun shouldTransformFlipX(): Boolean {
+ return when (pipGravity) {
+ (Gravity.TOP), (Gravity.TOP or Gravity.CENTER_HORIZONTAL) -> true
+ (Gravity.TOP or Gravity.LEFT) -> true
+ (Gravity.LEFT), (Gravity.LEFT or Gravity.CENTER_VERTICAL) -> true
+ (Gravity.BOTTOM or Gravity.LEFT) -> true
+ else -> false
+ }
+ }
+
+ private fun shouldTransformFlipY(): Boolean {
+ return when (pipGravity) {
+ (Gravity.TOP or Gravity.LEFT) -> true
+ (Gravity.TOP or Gravity.RIGHT) -> true
+ else -> false
+ }
+ }
+
+ private fun shouldTransformRotate(): Boolean {
+ val horizontalGravity = pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK
+ val leftOrRight = horizontalGravity == Gravity.LEFT || horizontalGravity == Gravity.RIGHT
+
+ if (leftOrRight) return false
+ return when (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) {
+ (Gravity.TOP) -> true
+ (Gravity.BOTTOM) -> true
+ else -> false
+ }
+ }
+
+ /**
+ * Transforms the given rect from screen space into the base case space, where the PiP
+ * anchor is positioned in the bottom right corner or on the right side (for expanded PiP).
+ *
+ * @see [fromTransformedSpace]
+ */
+ private fun toTransformedSpace(r: Rect): Rect {
+ var screenWidth = screenSize.width
+ var screenHeight = screenSize.height
+
+ val tl = Point(r.left, r.top)
+ val tr = Point(r.right, r.top)
+ val br = Point(r.right, r.bottom)
+ val bl = Point(r.left, r.bottom)
+ val corners = arrayOf(tl, tr, br, bl)
+
+ // rotate first (CW)
+ if (shouldTransformRotate()) {
+ corners.forEach { p ->
+ val px = p.x
+ val py = p.y
+ p.x = py
+ p.y = -px
+ p.y += screenWidth // shift back screen into positive quadrant
+ }
+ screenWidth = screenSize.height
+ screenHeight = screenSize.width
+ }
+
+ // flip second
+ corners.forEach {
+ if (shouldTransformFlipX()) it.x = screenWidth - it.x
+ if (shouldTransformFlipY()) it.y = screenHeight - it.y
+ }
+
+ val top = corners.minByOrNull { it.y }!!.y
+ val right = corners.maxByOrNull { it.x }!!.x
+ val bottom = corners.maxByOrNull { it.y }!!.y
+ val left = corners.minByOrNull { it.x }!!.x
+
+ return Rect(left, top, right, bottom)
+ }
+
+ /**
+ * Transforms the given rect from the base case space, where the PiP anchor is positioned in
+ * the bottom right corner or on the right side, back into screen space.
+ *
+ * @see [toTransformedSpace]
+ */
+ private fun fromTransformedSpace(r: Rect): Rect {
+ val rotate = shouldTransformRotate()
+ val transformedScreenWidth = if (rotate) screenSize.height else screenSize.width
+ val transformedScreenHeight = if (rotate) screenSize.width else screenSize.height
+
+ val tl = Point(r.left, r.top)
+ val tr = Point(r.right, r.top)
+ val br = Point(r.right, r.bottom)
+ val bl = Point(r.left, r.bottom)
+ val corners = arrayOf(tl, tr, br, bl)
+
+ // flip first
+ corners.forEach {
+ if (shouldTransformFlipX()) it.x = transformedScreenWidth - it.x
+ if (shouldTransformFlipY()) it.y = transformedScreenHeight - it.y
+ }
+
+ // rotate second (CCW)
+ if (rotate) {
+ corners.forEach { p ->
+ p.y -= screenSize.width // undo shift back screen into positive quadrant
+ val px = p.x
+ val py = p.y
+ p.x = -py
+ p.y = px
+ }
+ }
+
+ val top = corners.minByOrNull { it.y }!!.y
+ val right = corners.maxByOrNull { it.x }!!.x
+ val bottom = corners.maxByOrNull { it.y }!!.y
+ val left = corners.minByOrNull { it.x }!!.x
+
+ return Rect(left, top, right, bottom)
+ }
+
+ /** PiP anchor bounds in base case for given gravity */
+ private fun getNormalPipAnchorBounds(pipSize: Size, movementBounds: Rect): Rect {
+ var size = pipSize
+ val rotateCW = shouldTransformRotate()
+ if (rotateCW) {
+ size = Size(pipSize.height, pipSize.width)
+ }
+
+ val pipBounds = Rect()
+ if (isPipAnchoredToCorner()) {
+ // bottom right
+ Gravity.apply(
+ Gravity.BOTTOM or Gravity.RIGHT,
+ size.width,
+ size.height,
+ movementBounds,
+ pipBounds
+ )
+ return pipBounds
+ } else {
+ // expanded, right side
+ Gravity.apply(Gravity.RIGHT, size.width, size.height, movementBounds, pipBounds)
+ return pipBounds
+ }
+ }
+
+ private fun isPipAnchoredToCorner(): Boolean {
+ val left = (pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT
+ val right = (pipGravity and Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.RIGHT
+ val top = (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP
+ val bottom = (pipGravity and Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM
+
+ val horizontal = left || right
+ val vertical = top || bottom
+
+ return horizontal && vertical
+ }
+
+ private fun Rect.offsetCopy(dx: Int, dy: Int) = Rect(this).apply { offset(dx, dy) }
+ private fun Rect.intersectsY(other: Rect) = bottom >= other.top && top <= other.bottom
+ private fun Rect.intersectsX(other: Rect) = right >= other.left && left <= other.right
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 32ebe2d..b3c2306 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -174,8 +174,8 @@
}
void updateExpansionState() {
- mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipEnabled()
- && mTvPipBoundsState.getTvExpandedAspectRatio() != 0);
+ mPipMenuView.setExpandedModeEnabled(mTvPipBoundsState.isTvExpandedPipSupported()
+ && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0);
mPipMenuView.setIsExpanded(mTvPipBoundsState.isTvPipExpanded());
}
@@ -202,12 +202,17 @@
}
}
+ boolean isInMoveMode() {
+ return mInMoveMode;
+ }
+
@Override
public void onEnterMoveMode() {
if (DEBUG) Log.d(TAG, "onEnterMoveMode - " + mInMoveMode);
mInMoveMode = true;
mPipMenuView.showMenuButtons(false);
mPipMenuView.showMovementHints(mDelegate.getPipGravity());
+ mDelegate.onInMoveModeChanged();
}
@Override
@@ -217,6 +222,7 @@
mInMoveMode = false;
mPipMenuView.showMenuButtons(true);
mPipMenuView.hideMovementHints();
+ mDelegate.onInMoveModeChanged();
return true;
}
return false;
@@ -447,6 +453,8 @@
void movePip(int keycode);
+ void onInMoveModeChanged();
+
int getPipGravity();
void togglePipExpansion();
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 1a5e3f2..48dd1fe 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
@@ -1117,9 +1117,9 @@
return SPLIT_POSITION_UNDEFINED;
}
- if (token.equals(mMainStage.mRootTaskInfo.getToken())) {
+ if (mMainStage.containsToken(token)) {
return getMainStagePosition();
- } else if (token.equals(mSideStage.mRootTaskInfo.getToken())) {
+ } else if (mSideStage.containsToken(token)) {
return getSideStagePosition();
}
@@ -1329,8 +1329,11 @@
// Once the pending enter transition got merged, make sure to bring divider bar visible and
// clear the pending transition from cache to prevent mess-up the following state.
if (transition == mSplitTransitions.mPendingEnter) {
- finishEnterSplitScreen(null);
+ final SurfaceControl.Transaction t = mTransactionPool.acquire();
+ finishEnterSplitScreen(t);
mSplitTransitions.mPendingEnter = null;
+ t.apply();
+ mTransactionPool.release(t);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 109f96e..5f0cd01 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -124,6 +124,20 @@
return mChildrenTaskInfo.contains(taskId);
}
+ boolean containsToken(WindowContainerToken token) {
+ if (token.equals(mRootTaskInfo.token)) {
+ return true;
+ }
+
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ if (token.equals(mChildrenTaskInfo.valueAt(i).token)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Returns the top visible child task's id.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 610d2cc..fb3cd87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -73,9 +73,9 @@
/** Set to {@code true} to enable shell transitions. */
public static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
- && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+ && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
/** Transition type for exiting PIP via the Shell, via pressing the expand button. */
public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 57bc0d5..3dd9e05 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -61,7 +61,7 @@
private const val APP_CLOSE_WAIT_TIME_MS = 3_000L
fun isShellTransitionsEnabled() =
- SystemProperties.getBoolean("persist.debug.shell_transit", false)
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false)
fun executeShellCommand(instrumentation: Instrumentation, cmd: String) {
try {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
index 46fe201..4523e2c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/fullscreen/FullscreenTaskListenerTest.java
@@ -50,7 +50,7 @@
@SmallTest
public class FullscreenTaskListenerTest {
private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
@Mock
private SyncTransactionQueue mSyncQueue;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
new file mode 100644
index 0000000..78903dc
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.kidsmode;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.window.ITaskOrganizerController;
+import android.window.TaskAppearedInfo;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.compatui.CompatUIController;
+import com.android.wm.shell.startingsurface.StartingWindowController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KidsModeTaskOrganizerTest {
+ @Mock private ITaskOrganizerController mTaskOrganizerController;
+ @Mock private Context mContext;
+ @Mock private Handler mHandler;
+ @Mock private CompatUIController mCompatUI;
+ @Mock private SyncTransactionQueue mSyncTransactionQueue;
+ @Mock private ShellExecutor mTestExecutor;
+ @Mock private DisplayController mDisplayController;
+ @Mock private SurfaceControl mLeash;
+ @Mock private WindowContainerToken mToken;
+ @Mock private WindowContainerTransaction mTransaction;
+ @Mock private ForceShowNavigationBarSettingsObserver mObserver;
+ @Mock private StartingWindowController mStartingWindowController;
+ @Mock private DisplayInsetsController mDisplayInsetsController;
+
+ KidsModeTaskOrganizer mOrganizer;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ try {
+ doReturn(ParceledListSlice.<TaskAppearedInfo>emptyList())
+ .when(mTaskOrganizerController).registerTaskOrganizer(any());
+ } catch (RemoteException e) { }
+ mOrganizer = spy(new KidsModeTaskOrganizer(mTaskOrganizerController, mTestExecutor,
+ mHandler, mContext, mCompatUI, mSyncTransactionQueue, mDisplayController,
+ mDisplayInsetsController, Optional.empty(), mObserver));
+ mOrganizer.initialize(mStartingWindowController);
+ doReturn(mTransaction).when(mOrganizer).getWindowContainerTransaction();
+ doReturn(new InsetsState()).when(mDisplayController).getInsetsState(DEFAULT_DISPLAY);
+ }
+
+ @Test
+ public void testKidsModeOn() {
+ doReturn(true).when(mObserver).isEnabled();
+
+ mOrganizer.updateKidsModeState();
+
+ verify(mOrganizer, times(1)).enable();
+ verify(mOrganizer, times(1)).registerOrganizer();
+ verify(mOrganizer, times(1)).createRootTask(
+ eq(DEFAULT_DISPLAY), eq(WINDOWING_MODE_FULLSCREEN), eq(mOrganizer.mCookie));
+
+ final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
+ WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
+ mOrganizer.onTaskAppeared(rootTask, mLeash);
+
+ assertThat(mOrganizer.mLaunchRootLeash).isEqualTo(mLeash);
+ assertThat(mOrganizer.mLaunchRootTask).isEqualTo(rootTask);
+ }
+
+ @Test
+ public void testKidsModeOff() {
+ doReturn(true).when(mObserver).isEnabled();
+ mOrganizer.updateKidsModeState();
+ final ActivityManager.RunningTaskInfo rootTask = createTaskInfo(12,
+ WINDOWING_MODE_FULLSCREEN, mOrganizer.mCookie);
+ mOrganizer.onTaskAppeared(rootTask, mLeash);
+
+ doReturn(false).when(mObserver).isEnabled();
+ mOrganizer.updateKidsModeState();
+
+
+ verify(mOrganizer, times(1)).disable();
+ verify(mOrganizer, times(1)).unregisterOrganizer();
+ verify(mOrganizer, times(1)).deleteRootTask(rootTask.token);
+ assertThat(mOrganizer.mLaunchRootLeash).isNull();
+ assertThat(mOrganizer.mLaunchRootTask).isNull();
+ }
+
+ private ActivityManager.RunningTaskInfo createTaskInfo(
+ int taskId, int windowingMode, IBinder cookies) {
+ ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ taskInfo.taskId = taskId;
+ taskInfo.token = mToken;
+ taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+ final ArrayList<IBinder> launchCookies = new ArrayList<>();
+ if (cookies != null) {
+ launchCookies.add(cookies);
+ }
+ taskInfo.launchCookies = launchCookies;
+ return taskInfo;
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
new file mode 100644
index 0000000..e6ba70e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipKeepClearAlgorithmTest.kt
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.pip.tv
+
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.util.Size
+import android.view.Gravity
+import org.junit.runner.RunWith
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_BOTTOM
+import com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT
+import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement
+import org.junit.Before
+import org.junit.Test
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNull
+
+@RunWith(AndroidTestingRunner::class)
+class TvPipKeepClearAlgorithmTest {
+ private val DEFAULT_PIP_SIZE = Size(384, 216)
+ private val EXPANDED_WIDE_PIP_SIZE = Size(384*2, 216)
+ private val DASHBOARD_WIDTH = 484
+ private val BOTTOM_SHEET_HEIGHT = 524
+ private val STASH_OFFSET = 64
+ private val PADDING = 16
+ private val SCREEN_SIZE = Size(1920, 1080)
+ private val SCREEN_EDGE_INSET = 50
+
+ private lateinit var pipSize: Size
+ private lateinit var movementBounds: Rect
+ private lateinit var algorithm: TvPipKeepClearAlgorithm
+ private var currentTime = 0L
+ private var restrictedAreas = mutableSetOf<Rect>()
+ private var unrestrictedAreas = mutableSetOf<Rect>()
+ private var gravity: Int = 0
+
+ @Before
+ fun setup() {
+ movementBounds = Rect(0, 0, SCREEN_SIZE.width, SCREEN_SIZE.height)
+ movementBounds.inset(SCREEN_EDGE_INSET, SCREEN_EDGE_INSET)
+
+ restrictedAreas.clear()
+ unrestrictedAreas.clear()
+ currentTime = 0L
+ pipSize = DEFAULT_PIP_SIZE
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ algorithm = TvPipKeepClearAlgorithm({ currentTime })
+ algorithm.setScreenSize(SCREEN_SIZE)
+ algorithm.setMovementBounds(movementBounds)
+ algorithm.pipAreaPadding = PADDING
+ algorithm.stashOffset = STASH_OFFSET
+ algorithm.stashDuration = 5000L
+ algorithm.setGravity(gravity)
+ algorithm.maxRestrictedDistanceFraction = 0.3
+ }
+
+ @Test
+ fun testAnchorPosition_BottomRight() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopRight() {
+ gravity = Gravity.TOP or Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopLeft() {
+ gravity = Gravity.TOP or Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_BottomLeft() {
+ gravity = Gravity.BOTTOM or Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Right() {
+ gravity = Gravity.RIGHT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Left() {
+ gravity = Gravity.LEFT
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Top() {
+ gravity = Gravity.TOP
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_Bottom() {
+ gravity = Gravity.BOTTOM
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_TopCenterHorizontal() {
+ gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_BottomCenterHorizontal() {
+ gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_RightCenterVertical() {
+ gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
+ testAnchorPosition()
+ }
+
+ @Test
+ fun testAnchorPosition_LeftCenterVertical() {
+ gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
+ testAnchorPosition()
+ }
+
+ fun testAnchorPosition() {
+ val placement = getActualPlacement()
+
+ assertEquals(getExpectedAnchorBounds(), placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_KeepClearNotObstructing_StayAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.LEFT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = getExpectedAnchorBounds()
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedRightSidebar_PushedLeft() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(SCREEN_EDGE_INSET - sidebar.width() - PADDING, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorTopRight_UnrestrictedRightSidebar_PushedLeft() {
+ gravity = Gravity.TOP or Gravity.RIGHT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(SCREEN_EDGE_INSET - sidebar.width() - PADDING, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomLeft_UnrestrictedRightSidebar_StayAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.LEFT
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottom_UnrestrictedRightSidebar_StayAtAnchor() {
+ gravity = Gravity.BOTTOM
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun testExpanded_AnchorBottom_UnrestrictedRightSidebar_StayAtAnchor() {
+ pipSize = EXPANDED_WIDE_PIP_SIZE
+ gravity = Gravity.BOTTOM
+
+ val sidebar = makeSideBar(DASHBOARD_WIDTH, Gravity.RIGHT)
+ unrestrictedAreas.add(sidebar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0, 0)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_RestrictedSmallBottomBar_PushedUp() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(96)
+ restrictedAreas.add(bottomBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_RestrictedBottomSheet_StashDownAtAnchor() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ restrictedAreas.add(bottomBar)
+
+ val expectedBounds = getExpectedAnchorBounds()
+ expectedBounds.offsetTo(expectedBounds.left, SCREEN_SIZE.height - STASH_OFFSET)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_BOTTOM, placement.stashType)
+ assertEquals(getExpectedAnchorBounds(), placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_PushUp() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(0,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_RestrictedSidebar_StashAboveBottomSheet() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+ }
+
+ @Test
+ fun test_AnchorBottomRight_UnrestrictedBottomSheet_UnrestrictedSidebar_PushUpLeft() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ unrestrictedAreas.add(sideBar)
+
+ val expectedBounds = anchorBoundsOffsetBy(
+ SCREEN_EDGE_INSET - sideBar.width() - PADDING,
+ SCREEN_EDGE_INSET - bottomBar.height() - PADDING
+ )
+
+ val placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsBecomeUnobstructed_Unstashes() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += 1000
+
+ restrictedAreas.remove(sideBar)
+ placement = getActualPlacement()
+ assertEquals(expectedUnstashBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsStaysObstructed_UnstashesAfterTimeout() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += algorithm.stashDuration
+
+ placement = getActualPlacement()
+ assertEquals(expectedUnstashBounds, placement.bounds)
+ assertNotStashed(placement)
+ }
+
+ @Test
+ fun test_Stashed_UnstashBoundsObstructionChanges_UnstashTimeExtended() {
+ gravity = Gravity.BOTTOM or Gravity.RIGHT
+
+ val bottomBar = makeBottomBar(BOTTOM_SHEET_HEIGHT)
+ unrestrictedAreas.add(bottomBar)
+
+ val maxRestrictedHorizontalPush =
+ (algorithm.maxRestrictedDistanceFraction * SCREEN_SIZE.width).toInt()
+ val sideBar = makeSideBar(maxRestrictedHorizontalPush + 100, Gravity.RIGHT)
+ restrictedAreas.add(sideBar)
+
+ val expectedUnstashBounds =
+ anchorBoundsOffsetBy(0, SCREEN_EDGE_INSET - bottomBar.height() - PADDING)
+
+ val expectedBounds = Rect(expectedUnstashBounds)
+ expectedBounds.offsetTo(SCREEN_SIZE.width - STASH_OFFSET, expectedBounds.top)
+
+ var placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(algorithm.stashDuration, placement.unstashTime)
+
+ currentTime += 1000
+
+ val newObstruction = Rect(
+ 0,
+ expectedUnstashBounds.top,
+ expectedUnstashBounds.right,
+ expectedUnstashBounds.bottom
+ )
+ restrictedAreas.add(newObstruction)
+
+ placement = getActualPlacement()
+ assertEquals(expectedBounds, placement.bounds)
+ assertEquals(STASH_TYPE_RIGHT, placement.stashType)
+ assertEquals(expectedUnstashBounds, placement.unstashDestinationBounds)
+ assertEquals(currentTime + algorithm.stashDuration, placement.unstashTime)
+ }
+
+ private fun makeSideBar(width: Int, @Gravity.GravityFlags side: Int): Rect {
+ val sidebar = Rect(0, 0, width, SCREEN_SIZE.height)
+ if (side == Gravity.RIGHT) {
+ sidebar.offsetTo(SCREEN_SIZE.width - width, 0)
+ }
+ return sidebar
+ }
+
+ private fun makeBottomBar(height: Int): Rect {
+ return Rect(0, SCREEN_SIZE.height - height, SCREEN_SIZE.width, SCREEN_SIZE.height)
+ }
+
+ private fun getExpectedAnchorBounds(): Rect {
+ val expectedBounds = Rect()
+ Gravity.apply(gravity, pipSize.width, pipSize.height, movementBounds, expectedBounds)
+ return expectedBounds
+ }
+
+ private fun anchorBoundsOffsetBy(dx: Int, dy: Int): Rect {
+ val bounds = getExpectedAnchorBounds()
+ bounds.offset(dx, dy)
+ return bounds
+ }
+
+ private fun getActualPlacement(): Placement {
+ algorithm.setGravity(gravity)
+ return algorithm.calculatePipPosition(pipSize, restrictedAreas, unrestrictedAreas)
+ }
+
+ private fun assertNotStashed(actual: Placement) {
+ assertEquals(STASH_TYPE_NONE, actual.stashType)
+ assertNull(actual.unstashDestinationBounds)
+ assertEquals(0L, actual.unstashTime)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
index 13b726e..157c30b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageTaskListenerTests.java
@@ -62,7 +62,7 @@
@RunWith(AndroidJUnit4.class)
public final class StageTaskListenerTests extends ShellTestCase {
private static final boolean ENABLE_SHELL_TRANSITIONS =
- SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
@Mock
private ShellTaskOrganizer mTaskOrganizer;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 432196c..1a56b15 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6952,7 +6952,8 @@
for (Integer format : formatsList) {
int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
+ codecConfigList.add(
+ new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build());
}
}
return codecConfigList;
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 47e402f..d8995b4 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -1118,6 +1118,11 @@
private List<MediaRoute2Info> filterRoutesWithIndividualPreference(
List<MediaRoute2Info> routes, RouteDiscoveryPreference discoveryPreference) {
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
+ if (isSystemRouter()) {
+ // Individual discovery preferences do not apply for the system router.
+ filteredRoutes.addAll(routes);
+ return filteredRoutes;
+ }
for (MediaRoute2Info route : routes) {
if (!route.hasAnyFeatures(discoveryPreference.getPreferredFeatures())) {
continue;
diff --git a/media/java/android/media/tv/interactive/AppLinkInfo.java b/media/java/android/media/tv/interactive/AppLinkInfo.java
index cd201f7..0eb6fa8 100644
--- a/media/java/android/media/tv/interactive/AppLinkInfo.java
+++ b/media/java/android/media/tv/interactive/AppLinkInfo.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,8 +26,7 @@
* App link information used by TV interactive app to launch Android apps.
*/
public final class AppLinkInfo implements Parcelable {
- private @NonNull String mPackageName;
- private @NonNull String mClassName;
+ private @NonNull ComponentName mComponentName;
private @Nullable String mUriScheme;
private @Nullable String mUriHost;
private @Nullable String mUriPrefix;
@@ -41,12 +41,11 @@
@Nullable String uriScheme,
@Nullable String uriHost,
@Nullable String uriPrefix) {
- this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- this.mClassName = className;
+ NonNull.class, null, packageName);
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
+ NonNull.class, null, className);
+ this.mComponentName = new ComponentName(packageName, className);
this.mUriScheme = uriScheme;
this.mUriHost = uriHost;
this.mUriPrefix = uriPrefix;
@@ -57,7 +56,7 @@
*/
@NonNull
public String getPackageName() {
- return mPackageName;
+ return mComponentName.getPackageName();
}
/**
@@ -65,7 +64,7 @@
*/
@NonNull
public String getClassName() {
- return mClassName;
+ return mComponentName.getClassName();
}
/**
@@ -95,8 +94,8 @@
@Override
public String toString() {
return "AppLinkInfo { "
- + "packageName = " + mPackageName + ", "
- + "className = " + mClassName + ", "
+ + "packageName = " + mComponentName.getPackageName() + ", "
+ + "className = " + mComponentName.getClassName() + ", "
+ "uriScheme = " + mUriScheme + ", "
+ "uriHost = " + mUriHost + ", "
+ "uriPrefix = " + mUriPrefix
@@ -105,8 +104,8 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mPackageName);
- dest.writeString(mClassName);
+ dest.writeString(mComponentName.getPackageName());
+ dest.writeString(mComponentName.getClassName());
dest.writeString(mUriScheme);
dest.writeString(mUriHost);
dest.writeString(mUriPrefix);
@@ -124,12 +123,11 @@
String uriHost = in.readString();
String uriPrefix = in.readString();
- this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
- this.mClassName = className;
+ NonNull.class, null, packageName);
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mClassName);
+ NonNull.class, null, className);
+ this.mComponentName = new ComponentName(packageName, className);
this.mUriScheme = uriScheme;
this.mUriHost = uriHost;
this.mUriPrefix = uriPrefix;
@@ -174,28 +172,10 @@
}
/**
- * Sets package name of the App link.
- */
- @NonNull
- public Builder setPackageName(@NonNull String value) {
- mPackageName = value;
- return this;
- }
-
- /**
- * Sets app name of the App link.
- */
- @NonNull
- public Builder setClassName(@NonNull String value) {
- mClassName = value;
- return this;
- }
-
- /**
* Sets URI scheme of the App link.
*/
@NonNull
- public Builder setUriScheme(@Nullable String value) {
+ public Builder setUriScheme(@NonNull String value) {
mUriScheme = value;
return this;
}
@@ -204,7 +184,7 @@
* Sets URI host of the App link.
*/
@NonNull
- public Builder setUriHost(@Nullable String value) {
+ public Builder setUriHost(@NonNull String value) {
mUriHost = value;
return this;
}
@@ -213,7 +193,7 @@
* Sets URI prefix of the App link.
*/
@NonNull
- public Builder setUriPrefix(@Nullable String value) {
+ public Builder setUriPrefix(@NonNull String value) {
mUriPrefix = value;
return this;
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java b/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
index e1f535c..6103db0 100644
--- a/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppInfo.java
@@ -131,6 +131,10 @@
dest.writeInt(mTypes);
}
+ /**
+ * Returns a unique ID for this TV interactive app service. The ID is generated from the package
+ * and class name implementing the TV interactive app service.
+ */
@NonNull
public String getId() {
return mId;
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index f75aa56..b6db4cf 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -760,7 +760,12 @@
}
/**
- * Registers app link info.
+ * Registers an Android application link info record which can be used to launch the specific
+ * Android application by TV interactive App RTE.
+ *
+ * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+ * ID can be found in {@link TvInputInfo#getId()}.
+ * @param appLinkInfo The Android application link info record to be registered.
*/
public void registerAppLinkInfo(
@NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -772,7 +777,12 @@
}
/**
- * Unregisters app link info.
+ * Unregisters an Android application link info record which can be used to launch the specific
+ * Android application by TV interactive App RTE.
+ *
+ * @param tvIAppServiceId The ID of TV interactive service which the command to be sent to. The
+ * ID can be found in {@link TvInputInfo#getId()}.
+ * @param appLinkInfo The Android application link info record to be unregistered.
*/
public void unregisterAppLinkInfo(
@NonNull String tvIAppServiceId, @NonNull AppLinkInfo appLinkInfo) {
@@ -1813,8 +1823,8 @@
}
/**
- * This is called when {@link TvIAppService.Session#notifyTeletextAppStateChanged} is
- * called.
+ * This is called when {@link TvInteractiveAppService.Session#notifyTeletextAppStateChanged}
+ * is called.
*
* @param session A {@link TvInteractiveAppManager.Session} associated with this callback.
* @param state the current state.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 52b00b7..bb6edf5 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -19,6 +19,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SdkConstant;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
@@ -76,15 +77,14 @@
private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
- // TODO: cleanup and unhide APIs.
-
/**
* This is the interface name that a service implementing a TV Interactive App service should
* say that it supports -- that is, this is the action it uses for its intent filter. To be
* supported, the service must also require the
- * android.Manifest.permission#BIND_TV_INTERACTIVE_APP permission so that other applications
- * cannot abuse it.
+ * {@link android.Manifest.permission#BIND_TV_INTERACTIVE_APP} permission so that other
+ * applications cannot abuse it.
*/
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
"android.media.tv.interactive.TvInteractiveAppService";
@@ -244,13 +244,13 @@
public abstract void onPrepare(@TvInteractiveAppInfo.InteractiveAppType int type);
/**
- * Registers App link info.
+ * Called when a request to register an Android application link info record is received.
*/
public void onRegisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
}
/**
- * Unregisters App link info.
+ * Called when a request to unregister an Android application link info record is received.
*/
public void onUnregisterAppLinkInfo(@NonNull AppLinkInfo appLinkInfo) {
}
@@ -383,7 +383,7 @@
}
/**
- * Resets TvIAppService session.
+ * Resets TvInteractiveAppService session.
*/
public void onResetInteractiveApp() {
}
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 50a2083..3b70890 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -167,10 +167,10 @@
private Lnb() {}
- void setCallbackAndOwner(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
+ void setCallbackAndOwner(Tuner tuner, Executor executor, @Nullable LnbCallback callback) {
synchronized (mCallbackLock) {
if (callback != null && executor != null) {
- addCallback(callback, executor);
+ addCallback(executor, callback);
}
}
setOwner(tuner);
@@ -179,12 +179,12 @@
/**
* Adds LnbCallback
*
- * @param callback the callback to receive notifications from LNB.
* @param executor the executor on which callback will be invoked. Cannot be null.
+ * @param callback the callback to receive notifications from LNB.
*/
- public void addCallback(@NonNull LnbCallback callback, @NonNull Executor executor) {
- Objects.requireNonNull(callback, "callback must not be null");
+ public void addCallback(@NonNull Executor executor, @NonNull LnbCallback callback) {
Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(callback, "callback must not be null");
synchronized (mCallbackLock) {
mCallbackMap.put(callback, executor);
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 1e32cad..ef0270b 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -62,7 +62,9 @@
import android.os.Message;
import android.os.Process;
import android.util.Log;
+
import com.android.internal.util.FrameworkStatsLog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -2147,12 +2149,12 @@
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
if (mLnb != null) {
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
return mLnb;
}
if (checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB, mLnbLock)
&& mLnb != null) {
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
setLnb(mLnb);
return mLnb;
}
@@ -2186,7 +2188,7 @@
mLnbHandle = null;
}
mLnb = newLnb;
- mLnb.setCallbackAndOwner(executor, cb, this);
+ mLnb.setCallbackAndOwner(this, executor, cb);
setLnb(mLnb);
}
return mLnb;
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
new file mode 100644
index 0000000..125fee6
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_multiple_devices.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/transparent" />
+ <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"
+ android:bottomLeftRadius="16dp" android:bottomRightRadius="16dp"/>
+ <stroke
+ android:width="2dp"
+ android:color="@android:color/system_accent1_600" />
+</shape>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
new file mode 100644
index 0000000..7df92bb
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_negative_top.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="12dp" android:topRightRadius="12dp"
+ android:bottomLeftRadius="4dp" android:bottomRightRadius="4dp"/>
+</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
new file mode 100644
index 0000000..55e96f6
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/drawable/btn_positive_bottom.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@android:color/system_accent1_100"/>
+ <corners android:topLeftRadius="4dp" android:topRightRadius="4dp"
+ android:bottomLeftRadius="12dp" android:bottomRightRadius="12dp"/>
+</shape>
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
index f839b80..93a0cba 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_apps.xml
@@ -15,20 +15,12 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="108dp"
- android:height="108dp"
- android:viewportWidth="108"
- android:viewportHeight="108">
- <group android:scaleX="5.142857"
- android:scaleY="5.142857"
- android:translateY="2.5714285">
- <path
- android:pathData="M13.1235,1.01L5.1235,1C4.0235,1 3.1235,1.9 3.1235,3V17C3.1235,18.1 4.0235,19 5.1235,19H13.1235C14.2235,19 15.1235,18.1 15.1235,17V12.9765H13.1235V14H5.1235V6H13.1235V6.0034H15.1235V3C15.1235,1.9 14.2235,1.01 13.1235,1.01ZM13.1235,17H5.1235V16H13.1235V17ZM5.1235,4V3H13.1235V4H5.1235Z"
- android:fillColor="#202124"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M10.6984,6.4016V13.3136L12.3596,12.3628H17.8731V6.4016H10.6984ZM16.3731,7.9016H12.1984V10.8628H16.3731V7.9016Z"
- android:fillColor="#202124"
- android:fillType="evenOdd"/>
- </group>
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M6.2529,18.5H16.2529V17.5H18.2529V21.5C18.2529,22.6 17.3529,23.5 16.2529,23.5H6.2529C5.1529,23.5 4.2529,22.6 4.2529,21.5V3.5C4.2529,2.4 5.1529,1.51 6.2529,1.51L16.2529,1.5C17.3529,1.5 18.2529,2.4 18.2529,3.5V7.5H16.2529V6.5H6.2529V18.5ZM16.2529,3.5H6.2529V4.5H16.2529V3.5ZM6.2529,21.5V20.5H16.2529V21.5H6.2529ZM12.6553,9.4049C12.6553,8.8526 13.103,8.4049 13.6553,8.4049H20.5254C21.0776,8.4049 21.5254,8.8526 21.5254,9.4049V14.6055C21.5254,15.1578 21.0776,15.6055 20.5254,15.6055H14.355L12.6553,17.0871V9.4049Z"
+ android:fillColor="#3C4043"
+ android:fillType="evenOdd"/>
</vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 82fe72b..9e5b166 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -23,27 +23,27 @@
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
<TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingHorizontal="12dp"
+ style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
<TextView
- android:id="@+id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ android:id="@+id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp" />
<RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_list"
@@ -59,27 +59,31 @@
</RelativeLayout>
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="end">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="24dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
- android:id="@+id/btn_negative"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_no"
- android:textColor="?android:attr/textColorSecondary" />
+ android:id="@+id/btn_negative"
+ style="@style/NegativeButton"
+ android:text="@string/consent_no" />
<Button
- android:id="@+id/btn_positive"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_yes" />
+ android:id="@+id/btn_positive"
+ style="@style/PositiveButton"
+ android:text="@string/consent_yes" />
+
+ <Button
+ android:id="@+id/btn_negative_multiple_devices"
+ android:layout_marginLeft="170dp"
+ android:layout_marginBottom="10dp"
+ style="@style/NegativeButtonMultipleDevices"
+ android:textColor = "?android:textColorPrimary"
+ android:visibility="gone"
+ android:text="@string/consent_no" />
</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
index a1855fd..7c50814 100644
--- a/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/data_transfer_confirmation.xml
@@ -28,45 +28,40 @@
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
<TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingHorizontal="12dp"
- style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingHorizontal="12dp"
+ style="@*android:style/TextAppearance.Widget.Toolbar.Title"/>
<TextView
- android:id="@+id/summary"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginBottom="12dp"
- android:gravity="center"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ android:id="@+id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="12dp"
+ android:gravity="center"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp" />
<LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="end">
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="24dp">
<!-- Do NOT change the IDs of the buttons: they are referenced in CTS tests. -->
<Button
- android:id="@+id/btn_negative"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_no"
- android:textColor="?android:attr/textColorSecondary" />
+ android:id="@+id/btn_negative"
+ style="@style/NegativeButton"
+ android:text="@string/consent_no" />
<Button
- android:id="@+id/btn_positive"
- style="@android:style/Widget.Material.Button.Borderless.Colored"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/consent_yes" />
+ android:id="@+id/btn_positive"
+ style="@style/PositiveButton"
+ android:text="@string/consent_yes" />
</LinearLayout>
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
index 8fd1fb0..c177039 100644
--- a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -60,4 +60,4 @@
</LinearLayout>
-</LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index 153fc1f..b732b1b 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -25,16 +25,16 @@
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
<ImageView
- android:id="@android:id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_marginRight="12dp"/>
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_marginRight="12dp"/>
<TextView
- android:id="@android:id/text1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"/>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-night/themes.xml b/packages/CompanionDeviceManager/res/values-night/themes.xml
new file mode 100644
index 0000000..6eb16e7
--- /dev/null
+++ b/packages/CompanionDeviceManager/res/values-night/themes.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+
+<resources>
+
+ <style name="ChooserActivity"
+ parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
+ <item name="*android:windowFixedHeightMajor">100%</item>
+ <item name="*android:windowFixedHeightMinor">100%</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
+
+</resources>
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index c4ad432..55a1998 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -45,7 +45,7 @@
<string name="permission_apps_summary">Stream your phone\u2019s apps</string>
<!-- Confirmation for associating an application with a companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
- <string name="title_app_streaming">Allow <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to access this information for your phone</string>
+ <string name="title_app_streaming">Allow <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to access this information from your phone</string>
<!-- Description of the privileges the application will get if associated with the companion device of APP_STREAMING profile (type) [CHAR LIMIT=NONE] -->
<string name="summary_app_streaming" product="default">Let <strong><xliff:g id="app_name" example="Exo">%1$s</xliff:g></strong> to provide <strong><xliff:g id="device_name" example="Pixelbook Go">%2$s</xliff:g></strong> remote access to access to applications installed on this phone when connected.</string>
diff --git a/packages/CompanionDeviceManager/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index bba45e9..4a267db 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -35,4 +35,34 @@
<item name="android:background">@drawable/helper_ok_button</item>
</style>
+ <style name="NegativeButton"
+ parent="@android:style/Widget.Material.Button.Borderless.Colored">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:background">@drawable/btn_negative_top</item>
+ </style>
+
+ <style name="PositiveButton"
+ parent="@android:style/Widget.Material.Button.Borderless.Colored">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@android:color/system_neutral1_900</item>
+ <item name="android:layout_marginTop">4dp</item>
+ <item name="android:background">@drawable/btn_positive_bottom</item>
+ </style>
+
+ <style name="NegativeButtonMultipleDevices"
+ parent="@android:style/Widget.Material.Button.Colored">
+ <item name="android:layout_width">100dp</item>
+ <item name="android:layout_height">35dp</item>
+ <item name="android:layout_marginTop">20dp</item>
+ <item name="android:textAllCaps">false</item>
+ <item name="android:background">@drawable/btn_negative_multiple_devices</item>
+ </style>
+
</resources>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values/themes.xml b/packages/CompanionDeviceManager/res/values/themes.xml
index 7240432..e3fc67c 100644
--- a/packages/CompanionDeviceManager/res/values/themes.xml
+++ b/packages/CompanionDeviceManager/res/values/themes.xml
@@ -17,11 +17,10 @@
<resources>
<style name="ChooserActivity"
- parent="@android:style/Theme.DeviceDefault.Light.Dialog">
+ parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar">
<item name="*android:windowFixedHeightMajor">100%</item>
<item name="*android:windowFixedHeightMinor">100%</item>
<item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:forceDarkAllowed">true</item>
</style>
</resources>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 1b62691..0ab126a 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -118,8 +118,9 @@
// Present for self-managed association requests and "single-device" regular association
// regular.
private Button mButtonAllow;
- // Present for all associations.
private Button mButtonNotAllow;
+ // Present for multiple devices association requests only.
+ private Button mButtonNotAllowMultipleDevices;
private LinearLayout mAssociationConfirmationDialog;
private RelativeLayout mVendorHeader;
@@ -260,9 +261,12 @@
mButtonAllow = findViewById(R.id.btn_positive);
mButtonNotAllow = findViewById(R.id.btn_negative);
+ mButtonNotAllowMultipleDevices = findViewById(R.id.btn_negative_multiple_devices);
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
mButtonNotAllow.setOnClickListener(this::onNegativeButtonClick);
+ mButtonNotAllowMultipleDevices.setOnClickListener(this::onNegativeButtonClick);
+
mVendorHeaderButton.setOnClickListener(this::onShowHelperDialog);
if (mRequest.isSelfManaged()) {
@@ -490,6 +494,8 @@
// "Remove" consent button: users would need to click on the list item.
mButtonAllow.setVisibility(View.GONE);
+ mButtonNotAllow.setVisibility(View.GONE);
+ mButtonNotAllowMultipleDevices.setVisibility(View.VISIBLE);
}
private void onListItemClick(int position) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 72243f9..eba51c1 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -511,7 +511,6 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK,
android.Manifest.permission.MANAGE_ETHERNET_NETWORKS})
- @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
public void updateConfiguration(
@NonNull String iface,
@NonNull EthernetNetworkUpdateRequest request,
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
index a626971..43f4c40f 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java
@@ -24,36 +24,52 @@
import java.util.Objects;
-/** @hide */
+/**
+ * Represents a request to update an existing Ethernet interface.
+ *
+ * @see EthernetManager#updateConfiguration
+ *
+ * @hide
+ */
@SystemApi
public final class EthernetNetworkUpdateRequest implements Parcelable {
@NonNull
private final IpConfiguration mIpConfig;
- @NonNull
+ @Nullable
private final NetworkCapabilities mNetworkCapabilities;
+ /**
+ * @return the new {@link IpConfiguration}.
+ */
@NonNull
public IpConfiguration getIpConfiguration() {
return new IpConfiguration(mIpConfig);
}
- @NonNull
+ /**
+ * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}.
+ * When set to null, the existing NetworkCapabilities are not updated.
+ *
+ * @return the new {@link NetworkCapabilities} or null.
+ */
+ @Nullable
public NetworkCapabilities getNetworkCapabilities() {
- return new NetworkCapabilities(mNetworkCapabilities);
+ return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities);
}
private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig,
- @NonNull final NetworkCapabilities networkCapabilities) {
+ @Nullable final NetworkCapabilities networkCapabilities) {
Objects.requireNonNull(ipConfig);
- Objects.requireNonNull(networkCapabilities);
- mIpConfig = new IpConfiguration(ipConfig);
- mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
+ mIpConfig = ipConfig;
+ mNetworkCapabilities = networkCapabilities;
}
private EthernetNetworkUpdateRequest(@NonNull final Parcel source) {
Objects.requireNonNull(source);
- mIpConfig = IpConfiguration.CREATOR.createFromParcel(source);
- mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source);
+ mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(),
+ IpConfiguration.class);
+ mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(),
+ NetworkCapabilities.class);
}
/**
@@ -75,7 +91,8 @@
public Builder(@NonNull final EthernetNetworkUpdateRequest request) {
Objects.requireNonNull(request);
mBuilderIpConfig = new IpConfiguration(request.mIpConfig);
- mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities);
+ mBuilderNetworkCapabilities = null == request.mNetworkCapabilities
+ ? null : new NetworkCapabilities(request.mNetworkCapabilities);
}
/**
@@ -85,7 +102,6 @@
*/
@NonNull
public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) {
- Objects.requireNonNull(ipConfig);
mBuilderIpConfig = new IpConfiguration(ipConfig);
return this;
}
@@ -96,9 +112,8 @@
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) {
- Objects.requireNonNull(nc);
- mBuilderNetworkCapabilities = new NetworkCapabilities(nc);
+ public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) {
+ mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc);
return this;
}
@@ -135,8 +150,8 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- mIpConfig.writeToParcel(dest, flags);
- mNetworkCapabilities.writeToParcel(dest, flags);
+ dest.writeParcelable(mIpConfig, flags);
+ dest.writeParcelable(mNetworkCapabilities, flags);
}
@Override
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index b5e0539..1d22908 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -565,7 +565,7 @@
return new BpfMap<U32, U8>(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR,
U32.class, U8.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create uid counter set map: " + e);
+ Log.wtf(TAG, "Cannot open uid counter set map: " + e);
return null;
}
}
@@ -576,7 +576,7 @@
return new BpfMap<CookieTagMapKey, CookieTagMapValue>(COOKIE_TAG_MAP_PATH,
BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create cookie tag map: " + e);
+ Log.wtf(TAG, "Cannot open cookie tag map: " + e);
return null;
}
}
@@ -587,7 +587,7 @@
return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_A_PATH,
BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create stats map A: " + e);
+ Log.wtf(TAG, "Cannot open stats map A: " + e);
return null;
}
}
@@ -598,7 +598,7 @@
return new BpfMap<StatsMapKey, StatsMapValue>(STATS_MAP_B_PATH,
BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create stats map B: " + e);
+ Log.wtf(TAG, "Cannot open stats map B: " + e);
return null;
}
}
@@ -609,7 +609,7 @@
return new BpfMap<UidStatsMapKey, StatsMapValue>(APP_UID_STATS_MAP_PATH,
BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class);
} catch (ErrnoException e) {
- Log.wtf(TAG, "Cannot create app uid stats map: " + e);
+ Log.wtf(TAG, "Cannot open app uid stats map: " + e);
return null;
}
}
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index 44b3b4e..706aba3d 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -51,27 +51,34 @@
}
/**
- * Whether current activity is embedded in the Settings app or not.
+ * Whether the current activity is embedded in the Settings app or not.
+ *
+ * @param activity Activity that needs the check
*/
public static boolean isActivityEmbedded(Activity activity) {
return SplitController.getInstance().isActivityEmbedded(activity);
}
/**
- * Whether current activity is suggested to show back button or not.
+ * Whether the current activity should hide the navigate up button.
+ *
+ * @param activity Activity that needs the check
+ * @param isSecondLayerPage indicates if the activity(page) is shown in the 2nd layer of
+ * Settings app
*/
- public static boolean shouldHideBackButton(Activity activity, boolean isSecondaryLayerPage) {
+ public static boolean shouldHideNavigateUpButton(Activity activity, boolean isSecondLayerPage) {
if (!BuildCompat.isAtLeastT()) {
return false;
}
- if (!isSecondaryLayerPage) {
+ if (!isSecondLayerPage) {
return false;
}
- final String shouldHideBackButton = Settings.Global.getString(activity.getContentResolver(),
- "settings_hide_secondary_page_back_button_in_two_pane");
+ final String shouldHideNavigateUpButton =
+ Settings.Global.getString(activity.getContentResolver(),
+ "settings_hide_second_layer_page_navigate_up_button_in_two_pane");
- if (TextUtils.isEmpty(shouldHideBackButton)
- || TextUtils.equals("true", shouldHideBackButton)) {
+ if (TextUtils.isEmpty(shouldHideNavigateUpButton)
+ || Boolean.parseBoolean(shouldHideNavigateUpButton)) {
return isActivityEmbedded(activity);
}
return false;
diff --git a/packages/SettingsLib/res/values-v31/styles.xml b/packages/SettingsLib/res/values-v31/styles.xml
index 343de2c..0b703c9 100644
--- a/packages/SettingsLib/res/values-v31/styles.xml
+++ b/packages/SettingsLib/res/values-v31/styles.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
<resources>
- <style name="SettingsLibTabsTextAppearance" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+ <style name="SettingsLibTabsTextAppearance"
+ parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:textSize">16sp</item>
</style>
@@ -25,6 +26,7 @@
<item name="android:layout_height">48dp</item>
<item name="android:layout_marginStart">?android:attr/listPreferredItemPaddingStart</item>
<item name="android:layout_marginEnd">?android:attr/listPreferredItemPaddingEnd</item>
+ <item name="tabMaxWidth">0dp</item>
<item name="tabGravity">fill</item>
<item name="tabBackground">@drawable/settingslib_tabs_background</item>
<item name="tabIndicator">@drawable/settingslib_tabs_indicator_background</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index da0381b..042fef2 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1426,8 +1426,12 @@
<string name="user_switch_to_user">Switch to <xliff:g id="user_name" example="John Doe">%s</xliff:g></string>
<!-- Dialog message when creating a new user [CHAR LIMIT=NONE] -->
<string name="creating_new_user_dialog_message">Creating new user…</string>
+ <!-- Dialog message when creating a new guest [CHAR LIMIT=NONE] -->
+ <string name="creating_new_guest_dialog_message">Creating new guest…</string>
<!-- Text shown to notify that the creation of new user has failed. [CHAR LIMIT=40] -->
<string name="add_user_failed">Failed to create a new user</string>
+ <!-- Text shown to notify that the creation of new guest has failed. [CHAR LIMIT=40] -->
+ <string name="add_guest_failed">Failed to create a new guest</string>
<!-- Title for the preference to enter the nickname of the user to display in the user switcher [CHAR LIMIT=25]-->
<string name="user_nickname">Nickname</string>
@@ -1568,4 +1572,10 @@
<!-- Content description for a default user icon. [CHAR LIMIT=NONE] -->
<string name="default_user_icon_description">Default user icon</string>
+ <!-- Title for the 'physical keyboard' settings screen. [CHAR LIMIT=35] -->
+ <string name="physical_keyboard_title">Physical keyboard</string>
+ <!-- Title for the keyboard layout preference dialog. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_dialog_title">Choose keyboard layout</string>
+ <!-- Label of the default keyboard layout. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_default_label">Default</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 17db45d..e4efae2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -23,7 +23,6 @@
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.TypedArray;
-import android.os.Build;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -33,8 +32,6 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
-import com.android.internal.util.Preconditions;
-
/**
* Helper class for managing settings preferences that can be disabled
* by device admins via user restrictions.
@@ -42,8 +39,8 @@
public class RestrictedPreferenceHelper {
private final Context mContext;
private final Preference mPreference;
- final String packageName;
- final int uid;
+ String packageName;
+ int uid;
private boolean mDisabledByAdmin;
private EnforcedAdmin mEnforcedAdmin;
@@ -219,6 +216,11 @@
return mDisabledByAppOps;
}
+ public void updatePackageDetails(String packageName, int uid) {
+ this.packageName = packageName;
+ this.uid = uid;
+ }
+
private void updateDisabledState() {
if (!(mPreference instanceof RestrictedTopLevelPreference)) {
mPreference.setEnabled(!(mDisabledByAdmin || mDisabledByAppOps));
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index c607d74..091e322 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -18,8 +18,11 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.TypedValue;
@@ -28,6 +31,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
@@ -39,6 +43,7 @@
*/
public class RestrictedSwitchPreference extends SwitchPreference {
RestrictedPreferenceHelper mHelper;
+ AppOpsManager mAppOpsManager;
boolean mUseAdditionalSummary = false;
CharSequence mRestrictedSwitchSummary;
private int mIconSize;
@@ -90,6 +95,11 @@
this(context, null);
}
+ @VisibleForTesting
+ public void setAppOps(AppOpsManager appOps) {
+ mAppOpsManager = appOps;
+ }
+
public void setIconSize(int iconSize) {
mIconSize = iconSize;
}
@@ -97,6 +107,12 @@
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
+ final View switchView = holder.findViewById(android.R.id.switch_widget);
+ if (switchView != null) {
+ final View rootView = switchView.getRootView();
+ rootView.setFilterTouchesWhenObscured(true);
+ }
+
mHelper.onBindViewHolder(holder);
CharSequence switchSummary;
@@ -164,11 +180,18 @@
@Override
public void setEnabled(boolean enabled) {
+ boolean changed = false;
if (enabled && isDisabledByAdmin()) {
mHelper.setDisabledByAdmin(null);
- return;
+ changed = true;
}
- super.setEnabled(enabled);
+ if (enabled && isDisabledByAppOps()) {
+ mHelper.setDisabledByAppOps(false);
+ changed = true;
+ }
+ if (!changed) {
+ super.setEnabled(enabled);
+ }
}
public void setDisabledByAdmin(EnforcedAdmin admin) {
@@ -180,4 +203,38 @@
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
+
+ private void setDisabledByAppOps(boolean disabled) {
+ if (mHelper.setDisabledByAppOps(disabled)) {
+ notifyChanged();
+ }
+ }
+
+ public boolean isDisabledByAppOps() {
+ return mHelper.isDisabledByAppOps();
+ }
+
+ public int getUid() {
+ return mHelper != null ? mHelper.uid : Process.INVALID_UID;
+ }
+
+ public String getPackageName() {
+ return mHelper != null ? mHelper.packageName : null;
+ }
+
+ public void updateState(@NonNull String packageName, int uid, boolean isEnabled) {
+ mHelper.updatePackageDetails(packageName, uid);
+ if (mAppOpsManager == null) {
+ mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
+ }
+ final int mode = mAppOpsManager.noteOpNoThrow(
+ AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS,
+ uid, packageName);
+ final boolean appOpsAllowed = mode == AppOpsManager.MODE_ALLOWED;
+ if (appOpsAllowed || isEnabled) {
+ setEnabled(true);
+ } else {
+ setDisabledByAppOps(true);
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 1c9d9cf..3d91c5a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -285,6 +285,12 @@
public void disconnect() {
synchronized (mProfileLock) {
+ if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ for (CachedBluetoothDevice member : getMemberDevice()) {
+ Log.d(TAG, "Disconnect the member(" + member.getAddress() + ")");
+ member.disconnect();
+ }
+ }
mDevice.disconnect();
}
// Disconnect PBAP server in case its connected
@@ -399,6 +405,12 @@
}
mDevice.connect();
+ if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ for (CachedBluetoothDevice member : getMemberDevice()) {
+ Log.d(TAG, "connect the member(" + member.getAddress() + ")");
+ member.connect();
+ }
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index fcb56d2..01d0cc4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -248,9 +248,6 @@
}
public @WhenToDream int getWhenToDreamSetting() {
- if (!isEnabled()) {
- return NEVER;
- }
return isActivatedOnDock() && isActivatedOnSleep() ? EITHER
: isActivatedOnDock() ? WHILE_DOCKED
: isActivatedOnSleep() ? WHILE_CHARGING
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
index 075635c..dd86bec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
@@ -31,11 +31,15 @@
public class UserCreatingDialog extends AlertDialog {
public UserCreatingDialog(Context context) {
+ this(context, false);
+ }
+
+ public UserCreatingDialog(Context context, boolean isGuest) {
// hardcoding theme to be consistent with UserSwitchingDialog's theme
// todo replace both to adapt to the device's theme
super(context, com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert);
- inflateContent();
+ inflateContent(isGuest);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
@@ -44,12 +48,14 @@
getWindow().setAttributes(attrs);
}
- private void inflateContent() {
+ private void inflateContent(boolean isGuest) {
// using the same design as UserSwitchingDialog
setCancelable(false);
View view = LayoutInflater.from(getContext())
.inflate(R.layout.user_creation_progress_dialog, null);
- String message = getContext().getString(R.string.creating_new_user_dialog_message);
+ String message = getContext().getString(isGuest
+ ? R.string.creating_new_guest_dialog_message
+ : R.string.creating_new_user_dialog_message);
view.setAccessibilityPaneTitle(message);
((TextView) view.findViewById(R.id.message)).setText(message);
setView(view);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 4ab6542..9ef6bdf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -43,6 +43,31 @@
private static final int INVALID_RSSI = -127;
/**
+ * The intent action shows Wi-Fi dialog to connect Wi-Fi network.
+ * <p>
+ * Input: The calling package should put the chosen
+ * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into
+ * the {@link #EXTRA_CHOSEN_WIFI_ENTRY_KEY}.
+ * <p>
+ * Output: Nothing.
+ */
+ @VisibleForTesting
+ static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
+
+ /**
+ * Specify a key that indicates the WifiEntry to be configured.
+ */
+ @VisibleForTesting
+ static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
+
+ /**
+ * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to.
+ * {@code true} means a chosen WifiEntry request to connect to.
+ */
+ @VisibleForTesting
+ static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
+
+ /**
* The intent action shows network details settings to allow configuration of Wi-Fi.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -325,6 +350,19 @@
}
/**
+ * Returns the Intent for Wi-Fi dialog.
+ *
+ * @param key The Wi-Fi entry key
+ * @param connectForCaller True if a chosen WifiEntry request to connect to
+ */
+ public static Intent getWifiDialogIntent(String key, boolean connectForCaller) {
+ final Intent intent = new Intent(ACTION_WIFI_DIALOG);
+ intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key);
+ intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller);
+ return intent;
+ }
+
+ /**
* Returns the Intent for Wi-Fi network details settings.
*
* @param key The Wi-Fi entry key
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
index 9ebdba3..d988111 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
@@ -89,6 +89,10 @@
@After
public void tearDown() {
+ String[] entries = mImagesDir.list();
+ for (String entry : entries) {
+ new File(mImagesDir, entry).delete();
+ }
mImagesDir.delete();
}
@@ -150,23 +154,6 @@
}
@Test
- public void takePhotoIsNotFollowedByCropIntentWhenCropNotSupported() throws IOException {
- when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
-
- File file = new File(mImagesDir, "file.txt");
- saveBitmapToFile(file);
-
- Intent intent = new Intent();
- intent.setData(Uri.parse(
- "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
- mController.onActivityResult(
- REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
-
- verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
- verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
- }
-
- @Test
public void choosePhotoIsFollowedByCrop() throws IOException {
new File(mImagesDir, "file.txt").createNewFile();
@@ -250,7 +237,8 @@
public void internalCropUsedIfNoSystemCropperFound() throws IOException {
when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
- new File(mImagesDir, "file.txt").createNewFile();
+ File file = new File(mImagesDir, "file.txt");
+ saveBitmapToFile(file);
Intent intent = new Intent();
intent.setData(Uri.parse(
@@ -258,10 +246,6 @@
mController.onActivityResult(
REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
- Intent startIntent = verifyStartSystemActivityForResult(
- "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
- assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
-
verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
index e7b3fe9..6956105 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java
@@ -156,6 +156,27 @@
}
@Test
+ public void getWifiDialogIntent_returnsCorrectValues() {
+ String key = "test_key";
+
+ // Test that connectForCaller is true.
+ Intent intent = WifiUtils.getWifiDialogIntent(key, true /* connectForCaller */);
+
+ assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DIALOG);
+ assertThat(intent.getStringExtra(WifiUtils.EXTRA_CHOSEN_WIFI_ENTRY_KEY)).isEqualTo(key);
+ assertThat(intent.getBooleanExtra(WifiUtils.EXTRA_CONNECT_FOR_CALLER, true))
+ .isEqualTo(true /* connectForCaller */);
+
+ // Test that connectForCaller is false.
+ intent = WifiUtils.getWifiDialogIntent(key, false /* connectForCaller */);
+
+ assertThat(intent.getAction()).isEqualTo(WifiUtils.ACTION_WIFI_DIALOG);
+ assertThat(intent.getStringExtra(WifiUtils.EXTRA_CHOSEN_WIFI_ENTRY_KEY)).isEqualTo(key);
+ assertThat(intent.getBooleanExtra(WifiUtils.EXTRA_CONNECT_FOR_CALLER, true))
+ .isEqualTo(false /* connectForCaller */);
+ }
+
+ @Test
public void getWifiDetailsSettingsIntent_returnsCorrectValues() {
final String key = "test_key";
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index fa3360c..cbd71c0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -328,7 +328,5 @@
return true;
});
VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.FAST_PAIR_SCAN_ENABLED, BOOLEAN_VALIDATOR);
-
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 1c5bf81..3c29a80 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2252,12 +2252,14 @@
Settings.Secure.MULTI_PRESS_TIMEOUT,
SecureSettingsProto.MULTI_PRESS_TIMEOUT);
+ final long navBar = p.start(SecureSettingsProto.NAV_BAR);
dumpSetting(s, p,
Settings.Secure.NAV_BAR_FORCE_VISIBLE,
SecureSettingsProto.NavBar.NAV_BAR_FORCE_VISIBLE);
dumpSetting(s, p,
Settings.Secure.NAV_BAR_KIDS_MODE,
SecureSettingsProto.NavBar.NAV_BAR_KIDS_MODE);
+ p.end(navBar);
dumpSetting(s, p,
Settings.Secure.NAVIGATION_MODE,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7f8b2f5..e24b2d6 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -794,7 +794,7 @@
android:noHistory="true"
android:showForAllUsers="true"
android:finishOnTaskLaunch="true"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
@@ -805,7 +805,7 @@
android:showForAllUsers="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
- android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+ android:configChanges="screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
diff --git a/packages/SystemUI/animation/res/values/ids.xml b/packages/SystemUI/animation/res/values/ids.xml
index ef60a24..4e9a4be 100644
--- a/packages/SystemUI/animation/res/values/ids.xml
+++ b/packages/SystemUI/animation/res/values/ids.xml
@@ -15,5 +15,14 @@
limitations under the License.
-->
<resources>
+ <!-- DialogLaunchAnimator -->
<item type="id" name="launch_animation_running"/>
+
+ <!-- ViewBoundsAnimator -->
+ <item type="id" name="tag_animator"/>
+ <item type="id" name="tag_layout_listener"/>
+ <item type="id" name="tag_override_bottom"/>
+ <item type="id" name="tag_override_left"/>
+ <item type="id" name="tag_override_right"/>
+ <item type="id" name="tag_override_top"/>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt
new file mode 100644
index 0000000..5593fdf
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewBoundAnimator.kt
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2022 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.animation
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ObjectAnimator
+import android.animation.PropertyValuesHolder
+import android.util.IntProperty
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.Interpolator
+
+/**
+ * A class that allows changes in bounds within a view hierarchy to animate seamlessly between the
+ * start and end state.
+ */
+class ViewBoundAnimator {
+ // TODO(b/221418522): make this private once it can't be passed as an arg anymore.
+ enum class Bound(val label: String, val overrideTag: Int) {
+ LEFT("left", R.id.tag_override_left) {
+ override fun setValue(view: View, value: Int) {
+ view.left = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.left
+ }
+ },
+ TOP("top", R.id.tag_override_top) {
+ override fun setValue(view: View, value: Int) {
+ view.top = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.top
+ }
+ },
+ RIGHT("right", R.id.tag_override_right) {
+ override fun setValue(view: View, value: Int) {
+ view.right = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.right
+ }
+ },
+ BOTTOM("bottom", R.id.tag_override_bottom) {
+ override fun setValue(view: View, value: Int) {
+ view.bottom = value
+ }
+
+ override fun getValue(view: View): Int {
+ return view.bottom
+ }
+ };
+
+ abstract fun setValue(view: View, value: Int)
+ abstract fun getValue(view: View): Int
+ }
+
+ companion object {
+ /** Default values for the animation. These can all be overridden at call time. */
+ private const val DEFAULT_DURATION = 500L
+ private val DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED
+ private val DEFAULT_BOUNDS = setOf(Bound.LEFT, Bound.TOP, Bound.RIGHT, Bound.BOTTOM)
+
+ /** The properties used to animate the view bounds. */
+ private val PROPERTIES = mapOf(
+ Bound.LEFT to createViewProperty(Bound.LEFT),
+ Bound.TOP to createViewProperty(Bound.TOP),
+ Bound.RIGHT to createViewProperty(Bound.RIGHT),
+ Bound.BOTTOM to createViewProperty(Bound.BOTTOM)
+ )
+
+ private fun createViewProperty(bound: Bound): IntProperty<View> {
+ return object : IntProperty<View>(bound.label) {
+ override fun setValue(view: View, value: Int) {
+ setBound(view, bound, value)
+ }
+
+ override fun get(view: View): Int {
+ return getBound(view, bound) ?: bound.getValue(view)
+ }
+ }
+ }
+
+ /**
+ * Instruct the animator to watch for changes to the layout of [rootView] and its children
+ * and animate them. The animation can be limited to a subset of [bounds]. It uses the
+ * given [interpolator] and [duration].
+ *
+ * If a new layout change happens while an animation is already in progress, the animation
+ * is updated to continue from the current values to the new end state.
+ *
+ * The animator continues to respond to layout changes until [stopAnimating] is called.
+ *
+ * Successive calls to this method override the previous settings ([interpolator] and
+ * [duration]). The changes take effect on the next animation.
+ *
+ * TODO(b/221418522): remove the ability to select which bounds to animate and always
+ * animate all of them.
+ */
+ @JvmOverloads
+ fun animate(
+ rootView: View,
+ bounds: Set<Bound> = DEFAULT_BOUNDS,
+ interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION
+ ) {
+ animate(rootView, bounds, interpolator, duration, false /* ephemeral */)
+ }
+
+ /**
+ * Like [animate], but only takes effect on the next layout update, then unregisters itself
+ * once the first animation is complete.
+ *
+ * TODO(b/221418522): remove the ability to select which bounds to animate and always
+ * animate all of them.
+ */
+ @JvmOverloads
+ fun animateNextUpdate(
+ rootView: View,
+ bounds: Set<Bound> = DEFAULT_BOUNDS,
+ interpolator: Interpolator = DEFAULT_INTERPOLATOR,
+ duration: Long = DEFAULT_DURATION
+ ) {
+ animate(rootView, bounds, interpolator, duration, true /* ephemeral */)
+ }
+
+ private fun animate(
+ rootView: View,
+ bounds: Set<Bound>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ) {
+ val listener = createListener(bounds, interpolator, duration, ephemeral)
+ recursivelyAddListener(rootView, listener)
+ }
+
+ /**
+ * Instruct the animator to stop watching for changes to the layout of [rootView] and its
+ * children.
+ *
+ * Any animations already in progress continue until their natural conclusion.
+ */
+ fun stopAnimating(rootView: View) {
+ val listener = rootView.getTag(R.id.tag_layout_listener)
+ if (listener != null && listener is View.OnLayoutChangeListener) {
+ rootView.setTag(R.id.tag_layout_listener, null /* tag */)
+ rootView.removeOnLayoutChangeListener(listener)
+ }
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ stopAnimating(rootView.getChildAt(i))
+ }
+ }
+ }
+
+ private fun createListener(
+ bounds: Set<Bound>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ): View.OnLayoutChangeListener {
+ return object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ view: View?,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ if (view == null) return
+
+ val startLeft = getBound(view, Bound.LEFT) ?: oldLeft
+ val startTop = getBound(view, Bound.TOP) ?: oldTop
+ val startRight = getBound(view, Bound.RIGHT) ?: oldRight
+ val startBottom = getBound(view, Bound.BOTTOM) ?: oldBottom
+
+ (view.getTag(R.id.tag_animator) as? ObjectAnimator)?.cancel()
+
+ if (view.visibility == View.GONE || view.visibility == View.INVISIBLE) {
+ setBound(view, Bound.LEFT, left)
+ setBound(view, Bound.TOP, top)
+ setBound(view, Bound.RIGHT, right)
+ setBound(view, Bound.BOTTOM, bottom)
+ return
+ }
+
+ val startValues = mapOf(
+ Bound.LEFT to startLeft,
+ Bound.TOP to startTop,
+ Bound.RIGHT to startRight,
+ Bound.BOTTOM to startBottom
+ )
+ val endValues = mapOf(
+ Bound.LEFT to left,
+ Bound.TOP to top,
+ Bound.RIGHT to right,
+ Bound.BOTTOM to bottom
+ )
+
+ val boundsToAnimate = bounds.toMutableSet()
+ if (left == startLeft) boundsToAnimate.remove(Bound.LEFT)
+ if (top == startTop) boundsToAnimate.remove(Bound.TOP)
+ if (right == startRight) boundsToAnimate.remove(Bound.RIGHT)
+ if (bottom == startBottom) boundsToAnimate.remove(Bound.BOTTOM)
+
+ if (boundsToAnimate.isNotEmpty()) {
+ startAnimation(
+ view,
+ boundsToAnimate,
+ startValues,
+ endValues,
+ interpolator,
+ duration,
+ ephemeral
+ )
+ }
+ }
+ }
+ }
+
+ private fun recursivelyAddListener(view: View, listener: View.OnLayoutChangeListener) {
+ // Make sure that only one listener is active at a time.
+ val oldListener = view.getTag(R.id.tag_layout_listener)
+ if (oldListener != null && oldListener is View.OnLayoutChangeListener) {
+ view.removeOnLayoutChangeListener(oldListener)
+ }
+
+ view.addOnLayoutChangeListener(listener)
+ view.setTag(R.id.tag_layout_listener, listener)
+ if (view is ViewGroup) {
+ for (i in 0 until view.childCount) {
+ recursivelyAddListener(view.getChildAt(i), listener)
+ }
+ }
+ }
+
+ private fun getBound(view: View, bound: Bound): Int? {
+ return view.getTag(bound.overrideTag) as? Int
+ }
+
+ private fun setBound(view: View, bound: Bound, value: Int) {
+ view.setTag(bound.overrideTag, value)
+ bound.setValue(view, value)
+ }
+
+ /**
+ * Initiates the animation of a single bound by creating the animator, registering it with
+ * the [view], and starting it. If [ephemeral], the layout change listener is unregistered
+ * at the end of the animation, so no more animations happen.
+ */
+ private fun startAnimation(
+ view: View,
+ bounds: Set<Bound>,
+ startValues: Map<Bound, Int>,
+ endValues: Map<Bound, Int>,
+ interpolator: Interpolator,
+ duration: Long,
+ ephemeral: Boolean
+ ) {
+ val propertyValuesHolders = buildList {
+ bounds.forEach { bound ->
+ add(
+ PropertyValuesHolder.ofInt(
+ PROPERTIES[bound],
+ startValues.getValue(bound),
+ endValues.getValue(bound)
+ )
+ )
+ }
+ }.toTypedArray()
+
+ val animator = ObjectAnimator.ofPropertyValuesHolder(view, *propertyValuesHolders)
+ animator.interpolator = interpolator
+ animator.duration = duration
+ animator.addListener(object : AnimatorListenerAdapter() {
+ var cancelled = false
+
+ override fun onAnimationEnd(animation: Animator) {
+ view.setTag(R.id.tag_animator, null /* tag */)
+ bounds.forEach { view.setTag(it.overrideTag, null /* tag */) }
+
+ // When an animation is cancelled, a new one might be taking over. We shouldn't
+ // unregister the listener yet.
+ if (ephemeral && !cancelled) {
+ val listener = view.getTag(R.id.tag_layout_listener)
+ if (listener != null && listener is View.OnLayoutChangeListener) {
+ view.setTag(R.id.tag_layout_listener, null /* tag */)
+ view.removeOnLayoutChangeListener(listener)
+ }
+ }
+ }
+
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true
+ }
+ })
+
+ bounds.forEach { bound -> setBound(view, bound, startValues.getValue(bound)) }
+
+ view.setTag(R.id.tag_animator, animator)
+ animator.start()
+ }
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
index b96c07e..0764273 100644
--- a/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
+++ b/packages/SystemUI/res-keyguard/drawable/kg_emergency_button_background.xml
@@ -15,10 +15,11 @@
~ limitations under the License.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:color="?attr/wallpaperTextColorSecondary">
<item android:id="@android:id/background">
<shape android:shape="rectangle">
- <solid android:color="?android:attr/colorAccent"/>
+ <solid android:color="?androidprv:attr/colorAccentTertiary"/>
<corners android:radius="24dp"/>
</shape>
</item>
diff --git a/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml b/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml
new file mode 100644
index 0000000..9e61236
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/media_squiggly_progress.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 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.
+ -->
+<com.android.systemui.media.SquigglyProgress />
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 6375698..625ffd3 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -17,13 +17,14 @@
*/
-->
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<!-- Keyguard PIN pad styles -->
<style name="Keyguard.TextView" parent="@android:style/Widget.DeviceDefault.TextView">
<item name="android:textSize">@dimen/kg_status_line_font_size</item>
</style>
<style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
<item name="android:textSize">14dp</item>
<item name="android:background">@drawable/kg_emergency_button_background</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index c58c001..2782300 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -26,7 +26,7 @@
android:layout_width="match_parent"
android:layout_gravity="bottom"
android:src="@drawable/overlay_actions_background_protection"/>
- <com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+ <com.android.systemui.screenshot.DraggableConstraintLayout
android:id="@+id/clipboard_ui"
android:theme="@style/FloatingOverlay"
android:layout_width="match_parent"
@@ -146,5 +146,5 @@
android:layout_margin="@dimen/overlay_dismiss_button_margin"
android:src="@drawable/overlay_cancel"/>
</FrameLayout>
- </com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+ </com.android.systemui.screenshot.DraggableConstraintLayout>
</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 978998d..f030f31 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -44,6 +44,7 @@
android:background="@drawable/qs_media_scrim"
/>
+ <!-- Guideline for output switcher -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_vertical_guideline"
android:layout_width="wrap_content"
@@ -51,6 +52,14 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6" />
+ <!-- Guideline for action buttons (collapsed view only) -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/action_button_guideline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_guideline" />
+
<!-- App icon -->
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
@@ -118,15 +127,7 @@
android:singleLine="true"
android:textSize="16sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:layout_marginStart="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- app:layout_constraintTop_toBottomOf="@id/icon"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<!-- Artist name -->
<TextView
@@ -136,15 +137,7 @@
style="@style/MediaPlayer.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- android:layout_marginTop="1dp"
- app:layout_constraintTop_toBottomOf="@id/header_title"
- app:layout_constraintStart_toStartOf="@id/header_title"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<ImageButton
android:id="@+id/actionPlayPause"
@@ -153,9 +146,33 @@
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
- android:layout_marginTop="0dp"
- android:layout_marginBottom="0dp" />
+ />
+ <!-- See comment in media_session_collapsed.xml for how these barriers are used -->
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:barrierDirection="start"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ />
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier_end"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+
+ <!-- Button visibility will be controlled in code -->
<ImageButton
android:id="@+id/actionPrev"
style="@style/MediaPlayer.SessionAction"
@@ -163,10 +180,9 @@
android:layout_height="48dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="0dp"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ />
<!-- Seek Bar -->
<!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
@@ -174,12 +190,12 @@
android:id="@+id/media_progress_bar"
style="@style/MediaPlayer.ProgressBar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
android:paddingBottom="12dp"
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
android:splitTrack="false"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp" />
@@ -191,29 +207,58 @@
android:layout_height="48dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" />
<ImageButton
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
- android:layout_marginTop="0dp" />
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"/>
<ImageButton
- android:id="@+id/actionEnd"
+ android:id="@+id/action1"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="4dp"
- android:layout_marginBottom="0dp"
- android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action2"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action3"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action4"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
<!-- Long press menu -->
<TextView
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index 813bb60..8de8084 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -14,25 +14,25 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<androidx.constraintlayout.widget.ConstraintLayout
+<com.android.systemui.screenshot.DraggableConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
- android:id="@+id/screenshot_actions_container_background"
+ android:id="@+id/actions_container_background"
android:visibility="gone"
android:layout_height="0dp"
android:layout_width="0dp"
android:elevation="1dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/screenshot_actions_container"
+ app:layout_constraintBottom_toBottomOf="@+id/actions_container"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@+id/screenshot_actions_container"
- app:layout_constraintEnd_toEndOf="@+id/screenshot_actions_container"/>
+ app:layout_constraintTop_toTopOf="@+id/actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
<HorizontalScrollView
- android:id="@+id/screenshot_actions_container"
+ android:id="@+id/actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
@@ -130,4 +130,4 @@
app:layout_constraintStart_toStartOf="@id/screenshot_preview"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
android:elevation="@dimen/overlay_preview_elevation"/>
-</androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.systemui.screenshot.DraggableConstraintLayout>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3c2ac09..c56ba7b 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -22,6 +22,8 @@
<dimen name="ambient_indication_margin_bottom">115dp</dimen>
<dimen name="lock_icon_margin_bottom">60dp</dimen>
+ <dimen name="qs_media_session_height_expanded">172dp</dimen>
+
<!-- margin from keyguard status bar to clock. For split shade it should be
keyguard_split_shade_top_margin - status_bar_header_height_keyguard = 8dp -->
<dimen name="keyguard_clock_top_margin">8dp</dimen>
@@ -76,5 +78,5 @@
whether the progress is > 0, therefore this value is not very important. -->
<dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
- <dimen name="notification_panel_margin_horizontal">12dp</dimen>
+ <dimen name="notification_panel_margin_horizontal">24dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
index c990605..f5c0509 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
<resources>
- <dimen name="notification_panel_margin_horizontal">60dp</dimen>
+ <dimen name="notification_panel_margin_horizontal">48dp</dimen>
<dimen name="status_view_margin_horizontal">62dp</dimen>
<dimen name="keyguard_clock_top_margin">40dp</dimen>
<dimen name="keyguard_status_view_bottom_margin">40dp</dimen>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 1391461..f267088 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -23,7 +23,7 @@
<dimen name="keyguard_split_shade_top_margin">72dp</dimen>
- <dimen name="notification_panel_margin_horizontal">24dp</dimen>
-
<dimen name="split_shade_header_height">56dp</dimen>
+
+ <dimen name="qs_media_session_height_expanded">184dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index e5f502f..44f8f3a 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -21,8 +21,11 @@
for different hardware and product builds. -->
<resources>
<dimen name="status_view_margin_horizontal">124dp</dimen>
- <dimen name="notification_panel_margin_horizontal">120dp</dimen>
<dimen name="keyguard_clock_top_margin">80dp</dimen>
<dimen name="keyguard_status_view_bottom_margin">80dp</dimen>
<dimen name="bouncer_user_switcher_y_trans">90dp</dimen>
+
+ <dimen name="notification_panel_margin_horizontal">96dp</dimen>
+ <dimen name="notification_side_paddings">40dp</dimen>
+ <dimen name="notification_section_divider_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5ca7285..52ec516 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -139,7 +139,7 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
- <!-- Side padding on the lockscreen on the side of notifications -->
+ <!-- Side padding on the side of notifications -->
<dimen name="notification_side_paddings">16dp</dimen>
<!-- padding between the heads up and the statusbar -->
@@ -979,6 +979,11 @@
<dimen name="qs_media_session_disabled_seekbar_vertical_padding">16dp</dimen>
<dimen name="qs_media_session_height_expanded">184dp</dimen>
<dimen name="qs_media_session_height_collapsed">128dp</dimen>
+ <dimen name="qs_media_seekbar_progress_wavelength">20dp</dimen>
+ <dimen name="qs_media_seekbar_progress_amplitude">1.5dp</dimen>
+ <dimen name="qs_media_seekbar_progress_phase">8dp</dimen>
+ <dimen name="qs_media_seekbar_progress_stroke_width">2dp</dimen>
+ <dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
@@ -1362,9 +1367,6 @@
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
<dimen name="dream_overlay_status_bar_icon_size">
@*android:dimen/status_bar_system_icon_size</dimen>
- <!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
- shade. -->
- <dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
<dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
<dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index f2eaa75..3ae21e0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -590,6 +590,7 @@
<style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
<item name="android:thumbTint">?android:attr/textColorPrimary</item>
+ <item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
<item name="android:progressTint">?android:attr/textColorPrimary</item>
<item name="android:progressBackgroundTint">?android:attr/textColorTertiary</item>
<item name="android:clickable">true</item>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index c6e18a6..f00e031 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -19,6 +19,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<Constraint
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintStart_toEndOf="@id/action_button_guideline" />
+
+ <Constraint
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="@dimen/qs_media_session_height_collapsed"
@@ -28,33 +35,73 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constraintStart_toEndOf="@id/actionEnd"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toBottomOf="parent" />
+ app:layout_constraintStart_toEndOf="@id/media_action_barrier_end" />
+ <!--
+ There will only be 3 action buttons shown at most in this layout (controlled in code).
+ Play/Pause should always be at the end, but the other buttons should remain in the same order
+ when in RTL.
+ This is accomplished by setting two barriers at the start and end of the small buttons,
+ anchored to a guideline set at 3x button width from the end. The text and play/pause button are
+ positioned relative to the barriers, and the small buttons use right/left constraints to stay
+ in the correct order inside the barriers.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toEndOf="@id/header_artist"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintLeft_toRightOf="@id/media_action_barrier" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
@@ -62,29 +109,70 @@
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action1"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
-</ConstraintSet>
\ No newline at end of file
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintRight_toLeftOf="@id/media_action_barrier_end" />
+</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 18ec7aa..10da704 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -28,57 +28,118 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginBottom="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+ app:layout_constraintBottom_toBottomOf="@id/header_artist" />
+ <!--
+ The bottom row of action buttons should remain in the same order when RTL, so their constraints
+ are set with right/left instead of start/end.
+ The chain is set to "spread" so that the progress bar can be weighted to fill any empty space.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_chainStyle="spread" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_weight="1" />
<Constraint
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action1"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
-</ConstraintSet>
\ No newline at end of file
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+</ConstraintSet>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
deleted file mode 100644
index 325bcfc..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 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.shared.recents.utilities;
-
-import android.graphics.Bitmap;
-import android.graphics.ColorSpace;
-import android.graphics.ParcelableColorSpace;
-import android.hardware.HardwareBuffer;
-import android.os.Bundle;
-
-import java.util.Objects;
-
-/**
- * Utils for working with Bitmaps.
- */
-public final class BitmapUtil {
- private static final String KEY_BUFFER = "bitmap_util_buffer";
- private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
-
- private BitmapUtil(){ }
-
- /**
- * Creates a Bundle that represents the given Bitmap.
- * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
- * copies when passing across processes, only pass to processes you trust.
- *
- * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
- * returned Bundle should be treated as a standalone object.
- *
- * @param bitmap to convert to bundle
- * @return a Bundle representing the bitmap, should only be parsed by
- * {@link #bundleToHardwareBitmap(Bundle)}
- */
- public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
- if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
- throw new IllegalArgumentException(
- "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
- }
-
- // Bitmap assumes SRGB for null color space
- ParcelableColorSpace colorSpace =
- bitmap.getColorSpace() == null
- ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
- : new ParcelableColorSpace(bitmap.getColorSpace());
-
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
- bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
-
- return bundle;
- }
-
- /**
- * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
- *
- * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
- * Bitmap on to any other source.
- *
- * @param bundle containing the bitmap
- * @return a hardware Bitmap
- */
- public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
- if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
- throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
- }
-
- HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
- ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
-
- return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),
- colorSpace.getColorSpace());
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
index 7b67917..8491f83 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/util/ScopedUnfoldTransitionProgressProvider.kt
@@ -28,7 +28,7 @@
* If the transition has already started by the moment when the clients are ready to play the
* transition then it will report transition started callback and current animation progress.
*/
-class ScopedUnfoldTransitionProgressProvider
+open class ScopedUnfoldTransitionProgressProvider
@JvmOverloads
constructor(source: UnfoldTransitionProgressProvider? = null) :
UnfoldTransitionProgressProvider, TransitionProgressListener {
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index ffd1546..458d22e 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -96,7 +96,7 @@
**/
public void reloadColors() {
int color = Utils.getColorAttrDefaultColor(getContext(),
- android.R.attr.textColorPrimaryInverse);
+ com.android.internal.R.attr.textColorOnAccent);
setTextColor(color);
setBackground(getContext()
.getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 7f456db..eb418ff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -194,9 +194,12 @@
mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
}
mView.resetPasswordText(true /* animate */, false /* announce deletion if no match */);
+ startErrorAnimation();
}
}
+ protected void startErrorAnimation() { /* no-op */ }
+
protected void verifyPasswordAndUnlock() {
if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 1efda7e..77044ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -188,14 +188,13 @@
enableClipping(false);
setTranslationY(0);
- AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
- mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator(),
- getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR));
DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
? mDisappearAnimationUtilsLocked
: mDisappearAnimationUtils;
- disappearAnimationUtils.startAnimation2d(mViews,
- () -> {
+ disappearAnimationUtils.createAnimation(
+ this, 0, 200, mDisappearYTranslation, false,
+ mDisappearAnimationUtils.getInterpolator(), () -> {
+ getAnimationListener(InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR);
enableClipping(true);
if (finishRunnable != null) {
finishRunnable.run();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4723af2..c46e33d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -24,6 +24,9 @@
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -32,6 +35,10 @@
import com.android.internal.widget.LockscreenCredential;
import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A Pin based Keyguard input view
@@ -188,4 +195,48 @@
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
}
+
+ /**
+ * Begins an error animation for this view.
+ **/
+ public void startErrorAnimation() {
+ AnimatorSet animatorSet = new AnimatorSet();
+ List<Animator> animators = new ArrayList();
+ List<View> buttons = new ArrayList<>();
+ for (int i = 1; i <= 9; i++) {
+ buttons.add(mButtons[i]);
+ }
+ buttons.add(mDeleteButton);
+ buttons.add(mButtons[0]);
+ buttons.add(mOkButton);
+
+ int delay = 0;
+ for (int i = 0; i < buttons.size(); i++) {
+ final View button = buttons.get(i);
+ AnimatorSet animateWrapper = new AnimatorSet();
+ animateWrapper.setStartDelay(delay);
+
+ ValueAnimator scaleDownAnimator = ValueAnimator.ofFloat(1f, 0.8f);
+ scaleDownAnimator.setInterpolator(Interpolators.STANDARD);
+ scaleDownAnimator.addUpdateListener(valueAnimator -> {
+ button.setScaleX((float) valueAnimator.getAnimatedValue());
+ button.setScaleY((float) valueAnimator.getAnimatedValue());
+ });
+ scaleDownAnimator.setDuration(50);
+
+ ValueAnimator scaleUpAnimator = ValueAnimator.ofFloat(0.8f, 1f);
+ scaleUpAnimator.setInterpolator(Interpolators.STANDARD);
+ scaleUpAnimator.addUpdateListener(valueAnimator -> {
+ button.setScaleX((float) valueAnimator.getAnimatedValue());
+ button.setScaleY((float) valueAnimator.getAnimatedValue());
+ });
+ scaleUpAnimator.setDuration(617);
+
+ animateWrapper.playSequentially(scaleDownAnimator, scaleUpAnimator);
+ animators.add(animateWrapper);
+ delay += 33;
+ }
+ animatorSet.playTogether(animators);
+ animatorSet.start();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index a9c03d1a..cc7e4f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -134,4 +134,10 @@
mView.setPasswordEntryEnabled(true);
mMessageAreaController.setMessage(R.string.keyguard_enter_your_pin);
}
+
+ @Override
+ protected void startErrorAnimation() {
+ super.startErrorAnimation();
+ mView.startErrorAnimation();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 31f466f..087817f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -113,6 +113,22 @@
}
}
+ /** Sets a translationY value on every child view except for the media view. */
+ public void setChildrenTranslationYExcludingMediaView(float translationY) {
+ setChildrenTranslationYExcluding(translationY, Set.of(mMediaHostContainer));
+ }
+
+ /** Sets a translationY value on every view except for the views in the provided set. */
+ private void setChildrenTranslationYExcluding(float translationY, Set<View> excludedViews) {
+ for (int i = 0; i < mStatusViewContainer.getChildCount(); i++) {
+ final View child = mStatusViewContainer.getChildAt(i);
+
+ if (!excludedViews.contains(child)) {
+ child.setTranslationY(translationY);
+ }
+ }
+ }
+
public float getChildrenAlphaExcludingSmartSpace() {
return mChildrenAlphaExcludingSmartSpace;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index af3da9f..14c9cb2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -137,6 +137,13 @@
}
/**
+ * Sets a translationY on the views on the keyguard, except on the media view.
+ */
+ public void setTranslationYExcludingMedia(float translationY) {
+ mView.setChildrenTranslationYExcludingMediaView(translationY);
+ }
+
+ /**
* Set keyguard status view alpha.
*/
public void setAlpha(float alpha) {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index 00470c0..f925eaa 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -73,12 +73,14 @@
ValueAnimator expandBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
mNormalColor, mHighlightColor);
expandBackgroundColorAnimator.setDuration(EXPAND_COLOR_ANIMATION_MS);
+ expandBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
expandBackgroundColorAnimator.addUpdateListener(
animator -> mBackground.setColor((int) animator.getAnimatedValue()));
ValueAnimator expandTextColorAnimator =
ValueAnimator.ofObject(new ArgbEvaluator(),
textColorPrimary, textColorPrimaryInverse);
+ expandTextColorAnimator.setInterpolator(Interpolators.LINEAR);
expandTextColorAnimator.setDuration(EXPAND_COLOR_ANIMATION_MS);
expandTextColorAnimator.addUpdateListener(valueAnimator -> {
if (digitTextView != null) {
@@ -98,6 +100,7 @@
anim -> mBackground.setCornerRadius((float) anim.getAnimatedValue()));
ValueAnimator contractBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
mHighlightColor, mNormalColor);
+ contractBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
contractBackgroundColorAnimator.setStartDelay(CONTRACT_ANIMATION_DELAY_MS);
contractBackgroundColorAnimator.setDuration(CONTRACT_ANIMATION_MS);
contractBackgroundColorAnimator.addUpdateListener(
@@ -106,6 +109,7 @@
ValueAnimator contractTextColorAnimator =
ValueAnimator.ofObject(new ArgbEvaluator(), textColorPrimaryInverse,
textColorPrimary);
+ contractTextColorAnimator.setInterpolator(Interpolators.LINEAR);
contractTextColorAnimator.setStartDelay(CONTRACT_ANIMATION_DELAY_MS);
contractTextColorAnimator.setDuration(CONTRACT_ANIMATION_MS);
contractTextColorAnimator.addUpdateListener(valueAnimator -> {
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index e0d0fc2..7b98f27 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -19,6 +19,8 @@
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.VectorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -37,8 +39,14 @@
public NumPadButton(Context context, AttributeSet attrs) {
super(context, attrs);
- mAnimator = new NumPadAnimator(context, getBackground().mutate(),
- attrs.getStyleAttribute());
+ Drawable background = getBackground();
+ if (background instanceof GradientDrawable) {
+ mAnimator = new NumPadAnimator(context, background.mutate(),
+ attrs.getStyleAttribute());
+ } else {
+ mAnimator = null;
+ }
+
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 88a0bce..5cab547 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -18,6 +18,8 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -129,8 +131,13 @@
setContentDescription(mDigitText.getText().toString());
- mAnimator = new NumPadAnimator(context, getBackground().mutate(),
- R.style.NumPadKey, mDigitText);
+ Drawable background = getBackground();
+ if (background instanceof GradientDrawable) {
+ mAnimator = new NumPadAnimator(context, background.mutate(),
+ R.style.NumPadKey, mDigitText);
+ } else {
+ mAnimator = null;
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 3a6165c..031e378 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -27,6 +27,7 @@
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -105,6 +106,10 @@
mBootCompleteCache = mSysUIComponent.provideBootCacheImpl();
log.traceEnd();
+ // Enable Looper trace points.
+ // This allows us to see Handler callbacks on traces.
+ Looper.getMainLooper().setTraceTag(Trace.TRACE_TAG_APP);
+
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
new file mode 100644
index 0000000..6615f6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
@@ -0,0 +1,132 @@
+package com.android.systemui.broadcast
+
+import android.annotation.AnyThread
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.wakelock.WakeLock
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/**
+ * SystemUI master Broadcast sender
+ *
+ * This class dispatches broadcasts on background thread to avoid synchronous call to binder. Use
+ * this class instead of calling [Context.sendBroadcast] directly.
+ */
+@SysUISingleton
+class BroadcastSender @Inject constructor(
+ private val context: Context,
+ private val wakeLockBuilder: WakeLock.Builder,
+ @Background private val bgExecutor: Executor
+) {
+
+ private val WAKE_LOCK_TAG = "SysUI:BroadcastSender"
+ private val WAKE_LOCK_SEND_REASON = "sendInBackground"
+
+ /**
+ * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcast(intent: Intent) {
+ sendInBackground {
+ context.sendBroadcast(intent)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcast(intent: Intent, receiverPermission: String?) {
+ sendInBackground {
+ context.sendBroadcast(intent, receiverPermission)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(
+ intent: Intent,
+ userHandle: UserHandle,
+ receiverPermission: String?,
+ options: Bundle?
+ ) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options)
+ }
+ }
+
+ /**
+ * Sends broadcast via [Context.sendBroadcastAsUser] on background thread to avoid blocking
+ * synchronous binder call.
+ */
+ @AnyThread
+ fun sendBroadcastAsUser(
+ intent: Intent,
+ userHandle: UserHandle,
+ receiverPermission: String?,
+ appOp: Int
+ ) {
+ sendInBackground {
+ context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp)
+ }
+ }
+
+ /**
+ * Sends [Intent.ACTION_CLOSE_SYSTEM_DIALOGS] broadcast to the system.
+ */
+ @AnyThread
+ fun closeSystemDialogs() {
+ sendInBackground {
+ context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ }
+ }
+
+ /**
+ * Dispatches parameter on background executor while holding a wakelock.
+ */
+ private fun sendInBackground(callable: () -> Unit) {
+ val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG)
+ .setMaxTimeout(5000)
+ .build()
+ broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON)
+ bgExecutor.execute {
+ try {
+ callable.invoke()
+ } finally {
+ broadcastWakelock.release(WAKE_LOCK_SEND_REASON)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 56e4d7e..0f937d1 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -73,6 +73,7 @@
import com.android.internal.policy.PhoneWindow;
import com.android.systemui.R;
+import com.android.systemui.screenshot.DraggableConstraintLayout;
import com.android.systemui.screenshot.FloatingWindowUtil;
import com.android.systemui.screenshot.OverlayActionChip;
import com.android.systemui.screenshot.TimeoutHandler;
@@ -166,8 +167,28 @@
mRemoteCopyChip = requireNonNull(mView.findViewById(R.id.remote_copy_chip));
mDismissButton = requireNonNull(mView.findViewById(R.id.dismiss_button));
- mView.setOnDismissEndCallback(this::hideImmediate);
- mView.setOnInteractionCallback(mTimeoutHandler::resetTimeout);
+ mView.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
+ @Override
+ public void onInteraction() {
+ mTimeoutHandler.resetTimeout();
+ }
+
+ @Override
+ public void onSwipeDismissInitiated(Animator animator) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mContainer.animate().alpha(0).start();
+ }
+ });
+ }
+
+ @Override
+ public void onDismissComplete() {
+ hideImmediate();
+ }
+ });
mDismissButton.setOnClickListener(view -> animateOut());
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
deleted file mode 100644
index 57dc162..0000000
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DraggableConstraintLayout.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2021 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.clipboardoverlay;
-
-import android.animation.Animator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-
-import androidx.constraintlayout.widget.ConstraintLayout;
-
-import com.android.systemui.R;
-import com.android.systemui.screenshot.SwipeDismissHandler;
-
-import java.util.function.Consumer;
-
-/**
- * ConstraintLayout that is draggable when touched in a specific region
- */
-public class DraggableConstraintLayout extends ConstraintLayout
- implements ViewTreeObserver.OnComputeInternalInsetsListener {
- private final SwipeDismissHandler mSwipeDismissHandler;
- private final GestureDetector mSwipeDetector;
- private Consumer<Animator> mOnDismissInitiated;
- private Runnable mOnDismissComplete;
- private Runnable mOnInteraction;
-
- public DraggableConstraintLayout(Context context) {
- this(context, null);
- }
-
- public DraggableConstraintLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DraggableConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- mSwipeDismissHandler = new SwipeDismissHandler(mContext, this,
- new SwipeDismissHandler.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- if (mOnInteraction != null) {
- mOnInteraction.run();
- }
- }
-
- @Override
- public void onSwipeDismissInitiated(Animator animator) {
- if (mOnDismissInitiated != null) {
- mOnDismissInitiated.accept(animator);
- }
- }
-
- @Override
- public void onDismissComplete() {
- if (mOnDismissComplete != null) {
- mOnDismissComplete.run();
- }
- }
- });
- setOnTouchListener(mSwipeDismissHandler);
-
- mSwipeDetector = new GestureDetector(mContext,
- new GestureDetector.SimpleOnGestureListener() {
- final Rect mActionsRect = new Rect();
-
- @Override
- public boolean onScroll(
- MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
- View actionsContainer = findViewById(R.id.actions_container);
- actionsContainer.getBoundsOnScreen(mActionsRect);
- // return true if we aren't in the actions bar, or if we are but it isn't
- // scrollable in the direction of movement
- return !mActionsRect.contains((int) ev2.getRawX(), (int) ev2.getRawY())
- || !actionsContainer.canScrollHorizontally((int) distanceX);
- }
- });
- mSwipeDetector.setIsLongpressEnabled(false);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSwipeDismissHandler.onTouch(this, ev);
- }
-
- return mSwipeDetector.onTouchEvent(ev);
- }
-
- /**
- * Dismiss the view, with animation controlled by SwipeDismissHandler
- */
- public void dismiss() {
- mSwipeDismissHandler.dismiss();
- }
-
- /**
- * Set the callback to be run after view is dismissed (before animation; receives animator as
- * input)
- */
- public void setOnDismissStartCallback(Consumer<Animator> callback) {
- mOnDismissInitiated = callback;
- }
-
- /**
- * Set the callback to be run after view is dismissed
- */
- public void setOnDismissEndCallback(Runnable callback) {
- mOnDismissComplete = callback;
- }
-
- /**
- * Set the callback to be run when the view is interacted with (e.g. tapped)
- */
- public void setOnInteractionCallback(Runnable callback) {
- mOnInteraction = callback;
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- getViewTreeObserver().addOnComputeInternalInsetsListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
- }
-
- @Override
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- // Only child views are touchable.
- Region r = new Region();
- Rect rect = new Rect();
- for (int i = 0; i < getChildCount(); i++) {
- getChildAt(i).getGlobalVisibleRect(rect);
- r.op(rect, Region.Op.UNION);
- }
- inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- inoutInfo.touchableRegion.set(r);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 40662536..f9115b2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -17,10 +17,13 @@
package com.android.systemui.controls.management
import android.content.ComponentName
+import android.content.res.Configuration
+import android.content.res.Resources
import android.graphics.Rect
import android.os.Bundle
import android.service.controls.Control
import android.service.controls.DeviceTypes
+import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -32,7 +35,6 @@
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
-import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlInterface
@@ -56,11 +58,32 @@
const val TYPE_ZONE = 0
const val TYPE_CONTROL = 1
const val TYPE_DIVIDER = 2
- }
- val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
- override fun getSpanSize(position: Int): Int {
- return if (getItemViewType(position) != TYPE_CONTROL) 2 else 1
+ /**
+ * For low-dp width screens that also employ an increased font scale, adjust the
+ * number of columns. This helps prevent text truncation on these devices.
+ *
+ */
+ @JvmStatic
+ fun findMaxColumns(res: Resources): Int {
+ var maxColumns = res.getInteger(R.integer.controls_max_columns)
+ val maxColumnsAdjustWidth =
+ res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
+
+ val outValue = TypedValue()
+ res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
+ val maxColumnsAdjustFontScale = outValue.getFloat()
+
+ val config = res.configuration
+ val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
+ if (isPortrait &&
+ config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
+ config.screenWidthDp <= maxColumnsAdjustWidth &&
+ config.fontScale >= maxColumnsAdjustFontScale) {
+ maxColumns--
+ }
+
+ return maxColumns
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index 6f94943..f611c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -195,10 +195,11 @@
val margin = resources
.getDimensionPixelSize(R.dimen.controls_card_margin)
val itemDecorator = MarginItemDecorator(margin, margin)
+ val spanCount = ControlAdapter.findMaxColumns(resources)
recyclerView.apply {
this.adapter = adapter
- layoutManager = object : GridLayoutManager(recyclerView.context, 2) {
+ layoutManager = object : GridLayoutManager(recyclerView.context, spanCount) {
// This will remove from the announcement the row corresponding to the divider,
// as it's not something that should be announced.
@@ -210,7 +211,12 @@
return if (initial > 0) initial - 1 else initial
}
}.apply {
- spanSizeLookup = adapter.spanSizeLookup
+ spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+ override fun getSpanSize(position: Int): Int {
+ return if (adapter?.getItemViewType(position)
+ != ControlAdapter.TYPE_CONTROL) spanCount else 1
+ }
+ }
}
addItemDecoration(itemDecorator)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index cb67454..747bcbe 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -60,11 +60,17 @@
val margin = itemView.context.resources
.getDimensionPixelSize(R.dimen.controls_card_margin)
val itemDecorator = MarginItemDecorator(margin, margin)
+ val spanCount = ControlAdapter.findMaxColumns(itemView.resources)
recyclerView.apply {
this.adapter = controlAdapter
- layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
- spanSizeLookup = controlAdapter.spanSizeLookup
+ layoutManager = GridLayoutManager(recyclerView.context, spanCount).apply {
+ spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
+ override fun getSpanSize(position: Int): Int {
+ return if (adapter?.getItemViewType(position)
+ != ControlAdapter.TYPE_CONTROL) spanCount else 1
+ }
+ }
}
addItemDecoration(itemDecorator)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 5c1d8c3..e53f267 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -16,11 +16,11 @@
package com.android.systemui.controls.ui
+import android.annotation.AnyThread
import android.annotation.MainThread
import android.app.Dialog
import android.app.PendingIntent
import android.content.Context
-import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.database.ContentObserver
@@ -35,6 +35,7 @@
import android.util.Log
import android.view.HapticFeedbackConstants
import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -53,6 +54,7 @@
private val bgExecutor: DelayableExecutor,
@Main private val uiExecutor: DelayableExecutor,
private val activityStarter: ActivityStarter,
+ private val broadcastSender: BroadcastSender,
private val keyguardStateController: KeyguardStateController,
private val taskViewFactory: Optional<TaskViewFactory>,
private val controlsMetricsLogger: ControlsMetricsLogger,
@@ -199,11 +201,12 @@
false
}
+ @AnyThread
@VisibleForTesting
fun bouncerOrRun(action: Action, authRequired: Boolean) {
if (keyguardStateController.isShowing() && authRequired) {
if (isLocked) {
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ broadcastSender.closeSystemDialogs()
// pending actions will only run after the control state has been refreshed
pendingAction = action
@@ -233,7 +236,10 @@
// make sure the intent is valid before attempting to open the dialog
if (activities.isNotEmpty() && taskViewFactory.isPresent) {
taskViewFactory.get().create(context, uiExecutor, {
- dialog = DetailDialog(activityContext, it, pendingIntent, cvh).also {
+ dialog = DetailDialog(
+ activityContext, broadcastSender,
+ it, pendingIntent, cvh
+ ).also {
it.setOnDismissListener { _ -> dialog = null }
it.show()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 59c291c..1268250 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -25,12 +25,10 @@
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
-import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.util.Log
-import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.view.View
@@ -51,6 +49,7 @@
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.management.ControlAdapter
import com.android.systemui.controls.management.ControlsEditingActivity
import com.android.systemui.controls.management.ControlsFavoritingActivity
import com.android.systemui.controls.management.ControlsListingController
@@ -386,7 +385,7 @@
visibility = View.VISIBLE
}
- val maxColumns = findMaxColumns()
+ val maxColumns = ControlAdapter.findMaxColumns(activityContext.resources)
val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
var lastRow: ViewGroup = createRow(inflater, listView)
@@ -432,32 +431,6 @@
}
}
- /**
- * For low-dp width screens that also employ an increased font scale, adjust the
- * number of columns. This helps prevent text truncation on these devices.
- */
- private fun findMaxColumns(): Int {
- val res = activityContext.resources
- var maxColumns = res.getInteger(R.integer.controls_max_columns)
- val maxColumnsAdjustWidth =
- res.getInteger(R.integer.controls_max_columns_adjust_below_width_dp)
-
- val outValue = TypedValue()
- res.getValue(R.dimen.controls_max_columns_adjust_above_font_scale, outValue, true)
- val maxColumnsAdjustFontScale = outValue.getFloat()
-
- val config = res.configuration
- val isPortrait = config.orientation == Configuration.ORIENTATION_PORTRAIT
- if (isPortrait &&
- config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED &&
- config.screenWidthDp <= maxColumnsAdjustWidth &&
- config.fontScale >= maxColumnsAdjustFontScale) {
- maxColumns--
- }
-
- return maxColumns
- }
-
override fun getPreferredStructure(structures: List<StructureInfo>): StructureInfo {
if (structures.isEmpty()) return EMPTY_STRUCTURE
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index dc3d1b5..80589a2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -33,6 +33,7 @@
import android.widget.ImageView
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastSender
import com.android.wm.shell.TaskView
/**
@@ -42,6 +43,7 @@
*/
class DetailDialog(
val activityContext: Context,
+ val broadcastSender: BroadcastSender,
val taskView: TaskView,
val pendingIntent: PendingIntent,
val cvh: ControlViewHolder
@@ -147,7 +149,7 @@
// startActivity() below is called.
removeDetailTask()
dismiss()
- context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
+ broadcastSender.closeSystemDialogs()
pendingIntent.send()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 69f15e6..995df19 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -23,8 +23,6 @@
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
@@ -39,9 +37,6 @@
*/
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
- // The height of the area at the top of the dream overlay to allow dragging down the
- // notifications shade.
- private final int mDreamOverlayNotificationsDragAreaHeight;
private final DreamOverlayStatusBarViewController mStatusBarViewController;
private final ComplicationHostViewController mComplicationHostViewController;
@@ -79,9 +74,6 @@
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
- mDreamOverlayNotificationsDragAreaHeight =
- mView.getResources().getDimensionPixelSize(
- R.dimen.dream_overlay_notifications_drag_area_height);
mComplicationHostViewController = complicationHostViewController;
final View view = mComplicationHostViewController.getView();
@@ -117,11 +109,6 @@
return mView;
}
- @VisibleForTesting
- int getDreamOverlayNotificationsDragAreaHeight() {
- return mDreamOverlayNotificationsDragAreaHeight;
- }
-
private void updateBurnInOffsets() {
int burnInOffset = mMaxBurnInOffset;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index bf689e3..2db3de1 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -16,6 +16,7 @@
package com.android.systemui.flags;
+import com.android.internal.annotations.Keep;
import com.android.systemui.R;
import java.lang.reflect.Field;
@@ -154,8 +155,9 @@
new BooleanFlag(1000, true);
// 1100 - windowing
+ @Keep
public static final SysPropBooleanFlag WM_ENABLE_SHELL_TRANSITIONS =
- new SysPropBooleanFlag(1100, "persist.debug.shell_transit", false);
+ new SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false);
// Pay no attention to the reflection behind the curtain.
// ========================== Curtain ==========================
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 831a606..510d15b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -54,6 +54,7 @@
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.GhostedViewLaunchAnimatorController;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.monet.ColorScheme;
@@ -104,10 +105,18 @@
R.id.action4
};
+ // Buttons to show in small player when using semantic actions
+ private static final List<Integer> SEMANTIC_ACTION_IDS = List.of(
+ R.id.actionPlayPause,
+ R.id.actionPrev,
+ R.id.actionNext
+ );
+
private final SeekBarViewModel mSeekBarViewModel;
private SeekBarObserver mSeekBarObserver;
protected final Executor mBackgroundExecutor;
private final ActivityStarter mActivityStarter;
+ private final BroadcastSender mBroadcastSender;
private Context mContext;
private MediaViewHolder mMediaViewHolder;
@@ -142,14 +151,16 @@
*/
@Inject
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
- ActivityStarter activityStarter, MediaViewController mediaViewController,
- SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
+ ActivityStarter activityStarter, BroadcastSender broadcastSender,
+ MediaViewController mediaViewController, SeekBarViewModel seekBarViewModel,
+ Lazy<MediaDataManager> lazyMediaDataManager,
MediaOutputDialogFactory mediaOutputDialogFactory,
MediaCarouselController mediaCarouselController,
FalsingManager falsingManager, MediaFlags mediaFlags, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
+ mBroadcastSender = broadcastSender;
mSeekBarViewModel = seekBarViewModel;
mMediaViewController = mediaViewController;
mMediaDataManagerLazy = lazyMediaDataManager;
@@ -501,11 +512,11 @@
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
- actionIcons.add(semanticActions.getStartCustom());
+ actionIcons.add(semanticActions.getCustom0());
actionIcons.add(semanticActions.getPrevOrCustom());
actionIcons.add(semanticActions.getPlayOrPause());
actionIcons.add(semanticActions.getNextOrCustom());
- actionIcons.add(semanticActions.getEndCustom());
+ actionIcons.add(semanticActions.getCustom1());
actionsWhenCollapsed = new ArrayList<Integer>();
actionsWhenCollapsed.add(1);
@@ -562,6 +573,9 @@
/** Bind elements specific to PlayerSessionViewHolder */
private void bindSessionPlayer(@NonNull MediaData data, String key) {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
// Default colors
int surfaceColor = mBackgroundColor;
int accentPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
@@ -575,25 +589,6 @@
int textTertiary = com.android.settingslib.Utils.getColorAttr(mContext,
com.android.internal.R.attr.textColorTertiary).getDefaultColor();
- // App icon - use launcher icon
- ImageView appIconView = mMediaViewHolder.getAppIcon();
- appIconView.clearColorFilter();
- try {
- Drawable icon = mContext.getPackageManager().getApplicationIcon(
- data.getPackageName());
- appIconView.setImageDrawable(icon);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
- // Fall back to notification icon
- if (data.getAppIcon() != null) {
- appIconView.setImageIcon(data.getAppIcon());
- } else {
- appIconView.setImageResource(R.drawable.ic_music_note);
- }
- int color = mContext.getColor(R.color.material_dynamic_secondary10);
- appIconView.setColorFilter(color);
- }
-
// Album art
ColorScheme colorScheme = null;
ImageView albumView = mMediaViewHolder.getAlbumView();
@@ -640,6 +635,25 @@
ColorStateList.valueOf(surfaceColor));
mMediaViewHolder.getPlayer().setBackgroundTintList(bgColorList);
+ // App icon - use notification icon
+ ImageView appIconView = mMediaViewHolder.getAppIcon();
+ appIconView.clearColorFilter();
+ if (data.getAppIcon() != null && !data.getResumption()) {
+ appIconView.setImageIcon(data.getAppIcon());
+ appIconView.setColorFilter(accentPrimary);
+ } else {
+ // Resume players use launcher icon
+ appIconView.setColorFilter(getGrayscaleFilter());
+ try {
+ Drawable icon = mContext.getPackageManager().getApplicationIcon(
+ data.getPackageName());
+ appIconView.setImageDrawable(icon);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Cannot find icon for package " + data.getPackageName(), e);
+ appIconView.setImageResource(R.drawable.ic_music_note);
+ }
+ }
+
// Metadata text
mMediaViewHolder.getTitleText().setTextColor(textPrimary);
mMediaViewHolder.getArtistText().setTextColor(textSecondary);
@@ -660,26 +674,68 @@
// Media action buttons
MediaButton semanticActions = data.getSemanticActions();
+ PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ ImageButton[] genericButtons = new ImageButton[]{
+ sessionHolder.getAction0(),
+ sessionHolder.getAction1(),
+ sessionHolder.getAction2(),
+ sessionHolder.getAction3(),
+ sessionHolder.getAction4()};
+
+ ImageButton[] semanticButtons = new ImageButton[]{
+ sessionHolder.getActionPlayPause(),
+ sessionHolder.getActionNext(),
+ sessionHolder.getActionPrev()};
+
if (semanticActions != null) {
- PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ // Hide all the generic buttons
+ for (ImageButton b: genericButtons) {
+ setVisibleAndAlpha(collapsedSet, b.getId(), false);
+ setVisibleAndAlpha(expandedSet, b.getId(), false);
+ }
// Play/pause button has a background
sessionHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
setSemanticButton(sessionHolder.getActionPlayPause(), semanticActions.getPlayOrPause(),
- ColorStateList.valueOf(textPrimaryInverse));
+ ColorStateList.valueOf(textPrimaryInverse), collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionNext(), semanticActions.getNextOrCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionPrev(), semanticActions.getPrevOrCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionStart(), semanticActions.getStartCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionEnd(), semanticActions.getEndCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
+ setSemanticButton(sessionHolder.getAction0(), semanticActions.getCustom0(),
+ textColorList, collapsedSet, expandedSet, false);
+ setSemanticButton(sessionHolder.getAction1(), semanticActions.getCustom1(),
+ textColorList, collapsedSet, expandedSet, false);
} else {
- Log.w(TAG, "Using semantic player, but did not get buttons");
+ // Hide all the semantic buttons
+ for (int id : SEMANTIC_ACTION_IDS) {
+ setVisibleAndAlpha(collapsedSet, id, false);
+ setVisibleAndAlpha(expandedSet, id, false);
+ }
+
+ // Set all the generic buttons
+ List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
+ List<MediaAction> actions = data.getActions();
+ int i = 0;
+ for (; i < actions.size(); i++) {
+ boolean showInCompact = actionsWhenCollapsed.contains(i);
+ setSemanticButton(genericButtons[i], actions.get(i), textColorList, collapsedSet,
+ expandedSet, showInCompact);
+ }
+ for (; i < 5; i++) {
+ // Hide any unused buttons
+ setSemanticButton(genericButtons[i], null, textColorList, collapsedSet,
+ expandedSet, false);
+ }
}
+ // If disabled, set progress bar to INVISIBLE instead of GONE so layout weights still work
+ boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
+ expandedSet.setVisibility(R.id.media_progress_bar,
+ seekbarEnabled ? ConstraintSet.VISIBLE : ConstraintSet.INVISIBLE);
+ expandedSet.setAlpha(R.id.media_progress_bar, seekbarEnabled ? 1.0f : 0.0f);
+
// Long press buttons
mMediaViewHolder.getLongPressText().setTextColor(textColorList);
mMediaViewHolder.getSettingsText().setTextColor(textColorList);
@@ -688,11 +744,11 @@
mMediaViewHolder.getCancelText().setBackgroundTintList(accentColorList);
mMediaViewHolder.getDismissText().setTextColor(textColorList);
mMediaViewHolder.getDismissText().setBackgroundTintList(accentColorList);
-
}
private void setSemanticButton(final ImageButton button, MediaAction mediaAction,
- ColorStateList fgColor) {
+ ColorStateList fgColor, ConstraintSet collapsedSet, ConstraintSet expandedSet,
+ boolean showInCompact) {
button.setImageTintList(fgColor);
if (mediaAction != null) {
button.setImageIcon(mediaAction.getIcon());
@@ -716,6 +772,9 @@
button.setContentDescription(null);
button.setEnabled(false);
}
+
+ setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
+ setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
}
@Nullable
@@ -899,7 +958,7 @@
// Dismiss the card Smartspace data through Smartspace trampoline activity.
mContext.startActivity(dismissIntent);
} else {
- mContext.sendBroadcast(dismissIntent);
+ mBroadcastSender.sendBroadcast(dismissIntent);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 500e82e..4cf6291 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -149,11 +149,11 @@
/**
* First custom action space
*/
- var startCustom: MediaAction? = null,
+ var custom0: MediaAction? = null,
/**
- * Last custom action space
+ * Second custom action space
*/
- var endCustom: MediaAction? = null
+ var custom1: MediaAction? = null
)
/** State of a media action. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index ae5c1f2..de44a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -21,6 +21,7 @@
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
@@ -56,6 +57,7 @@
class MediaDataFilter @Inject constructor(
private val context: Context,
private val broadcastDispatcher: BroadcastDispatcher,
+ private val broadcastSender: BroadcastSender,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor,
private val systemClock: SystemClock
@@ -249,7 +251,7 @@
// Dismiss the card Smartspace data through Smartspace trampoline activity.
context.startActivity(dismissIntent)
} else {
- context.sendBroadcast(dismissIntent)
+ broadcastSender.sendBroadcast(dismissIntent)
}
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index fab06c2..9e14fe9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -752,8 +752,8 @@
null
}
- actions.startCustom = customActions[customIdx++]
- actions.endCustom = customActions[customIdx++]
+ actions.custom0 = customActions[customIdx++]
+ actions.custom1 = customActions[customIdx++]
}
return actions
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 18b6699..7a4dee2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -292,6 +292,18 @@
}
/**
+ * Returns the amount of translationY of the media container, during the current guided
+ * transformation, if running. If there is no guided transformation running, it will return 0.
+ */
+ fun getGuidedTransformationTranslationY(): Int {
+ if (!isCurrentlyInGuidedTransformation()) {
+ return -1
+ }
+ val startHost = getHost(previousLocation) ?: return 0
+ return targetBounds.top - startHost.currentBounds.top
+ }
+
+ /**
* Is the shade currently collapsing from the expanded qs? If we're on the lockscreen and in qs,
* we wouldn't want to transition in that case.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 77873e8..3860409 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -54,7 +54,7 @@
private int mUid;
private IMediaProjectionManager mService;
- private SystemUIDialog mDialog;
+ private AlertDialog mDialog;
@Override
public void onCreate(Bundle icicle) {
@@ -141,13 +141,18 @@
dialogTitle = getString(R.string.media_projection_dialog_title, appName);
}
- mDialog = new SystemUIDialog(this);
- mDialog.setTitle(dialogTitle);
- mDialog.setIcon(R.drawable.ic_media_projection_permission);
- mDialog.setMessage(dialogText);
- mDialog.setPositiveButton(R.string.media_projection_action_text, this);
- mDialog.setNeutralButton(android.R.string.cancel, this);
- mDialog.setOnCancelListener(this);
+ mDialog = new AlertDialog.Builder(this, R.style.Theme_SystemUI_Dialog)
+ .setTitle(dialogTitle)
+ .setIcon(R.drawable.ic_media_projection_permission)
+ .setMessage(dialogText)
+ .setPositiveButton(R.string.media_projection_action_text, this)
+ .setNeutralButton(android.R.string.cancel, this)
+ .setOnCancelListener(this)
+ .create();
+
+ SystemUIDialog.registerDismissListener(mDialog);
+ SystemUIDialog.applyFlags(mDialog);
+ SystemUIDialog.setDialogSize(mDialog);
mDialog.create();
mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
@@ -186,7 +191,7 @@
private Intent getMediaProjectionIntent(int uid, String packageName)
throws RemoteException {
IMediaProjection projection = mService.createProjection(uid, packageName,
- MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
+ MediaProjectionManager.TYPE_SCREEN_CAPTURE, false /* permanentGrant */);
Intent intent = new Intent();
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION, projection.asBinder());
return intent;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index e57b247..5f60696 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -60,12 +60,24 @@
val settings = itemView.requireViewById<View>(R.id.settings)
val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+ // Action Buttons
+ val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
+ val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
+ val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
+ val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
+ val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
it.registerLightSource(cancel)
it.registerLightSource(dismiss)
it.registerLightSource(settings)
+ it.registerLightSource(action0)
+ it.registerLightSource(action1)
+ it.registerLightSource(action2)
+ it.registerLightSource(action3)
+ it.registerLightSource(action4)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
index 87d2cff..6928ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
@@ -31,16 +31,12 @@
val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
- val actionStart = itemView.requireViewById<ImageButton>(R.id.actionStart)
- val actionEnd = itemView.requireViewById<ImageButton>(R.id.actionEnd)
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(actionPlayPause)
it.registerLightSource(actionNext)
it.registerLightSource(actionPrev)
- it.registerLightSource(actionStart)
- it.registerLightSource(actionEnd)
}
}
@@ -49,8 +45,11 @@
R.id.actionPlayPause -> actionPlayPause
R.id.actionNext -> actionNext
R.id.actionPrev -> actionPrev
- R.id.actionStart -> actionStart
- R.id.actionEnd -> actionEnd
+ R.id.action0 -> action0
+ R.id.action1 -> action1
+ R.id.action2 -> action2
+ R.id.action3 -> action3
+ R.id.action4 -> action4
else -> {
throw IllegalArgumentException()
}
@@ -90,8 +89,11 @@
R.id.actionPlayPause,
R.id.actionNext,
R.id.actionPrev,
- R.id.actionStart,
- R.id.actionEnd,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
R.id.icon
)
val gutsIds = setOf(
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 20b2d4a..dd3fa89 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -33,23 +33,6 @@
override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
- // Action Buttons
- val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
- val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
- val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
- val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
- val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
-
- init {
- (player.background as IlluminationDrawable).let {
- it.registerLightSource(action0)
- it.registerLightSource(action1)
- it.registerLightSource(action2)
- it.registerLightSource(action3)
- it.registerLightSource(action4)
- }
- }
-
override fun getAction(id: Int): ImageButton {
return when (id) {
R.id.action0 -> action0
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index cf997055..57701ab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -50,25 +50,46 @@
.getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_vertical_padding)
}
+ init {
+ val seekBarProgressWavelength = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_wavelength).toFloat()
+ val seekBarProgressAmplitude = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_amplitude).toFloat()
+ val seekBarProgressPhase = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_phase).toFloat()
+ val seekBarProgressStrokeWidth = holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_stroke_width).toFloat()
+ val progressDrawable = holder.seekBar.progressDrawable as? SquigglyProgress
+ progressDrawable?.let {
+ it.waveLength = seekBarProgressWavelength
+ it.lineAmplitude = seekBarProgressAmplitude
+ it.phaseSpeed = seekBarProgressPhase
+ it.strokeWidth = seekBarProgressStrokeWidth
+ }
+ }
+
/** Updates seek bar views when the data model changes. */
@UiThread
override fun onChanged(data: SeekBarViewModel.Progress) {
+ val progressDrawable = holder.seekBar.progressDrawable as? SquigglyProgress
if (!data.enabled) {
if (holder.seekBar.maxHeight != seekBarDisabledHeight) {
holder.seekBar.maxHeight = seekBarDisabledHeight
setVerticalPadding(seekBarDisabledVerticalPadding)
}
- holder.seekBar.setEnabled(false)
- holder.seekBar.getThumb().setAlpha(0)
- holder.seekBar.setProgress(0)
- holder.elapsedTimeView?.setText("")
- holder.totalTimeView?.setText("")
+ holder.seekBar.isEnabled = false
+ progressDrawable?.animate = false
+ holder.seekBar.thumb.alpha = 0
+ holder.seekBar.progress = 0
+ holder.elapsedTimeView?.text = ""
+ holder.totalTimeView?.text = ""
holder.seekBar.contentDescription = ""
return
}
- holder.seekBar.getThumb().setAlpha(if (data.seekAvailable) 255 else 0)
- holder.seekBar.setEnabled(data.seekAvailable)
+ holder.seekBar.thumb.alpha = if (data.seekAvailable) 255 else 0
+ holder.seekBar.isEnabled = data.seekAvailable
+ progressDrawable?.animate = data.playing
if (holder.seekBar.maxHeight != seekBarEnabledMaxHeight) {
holder.seekBar.maxHeight = seekBarEnabledMaxHeight
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 9cf9c48..49cd161 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -31,6 +31,7 @@
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.util.concurrency.RepeatableExecutor
import javax.inject.Inject
@@ -73,7 +74,7 @@
class SeekBarViewModel @Inject constructor(
@Background private val bgExecutor: RepeatableExecutor
) {
- private var _data = Progress(false, false, null, 0)
+ private var _data = Progress(false, false, false, null, 0)
set(value) {
field = value
_progress.postValue(value)
@@ -131,6 +132,8 @@
lateinit var logSmartspaceClick: () -> Unit
+ fun getEnabled() = _data.enabled
+
/**
* Event indicating that the user has started interacting with the seek bar.
*/
@@ -192,10 +195,12 @@
val seekAvailable = ((playbackState?.actions ?: 0L) and PlaybackState.ACTION_SEEK_TO) != 0L
val position = playbackState?.position?.toInt()
val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() ?: 0
+ val playing = NotificationMediaManager
+ .isPlayingState(playbackState?.state ?: PlaybackState.STATE_NONE)
val enabled = if (playbackState == null ||
playbackState?.getState() == PlaybackState.STATE_NONE ||
(duration <= 0)) false else true
- _data = Progress(enabled, seekAvailable, position, duration)
+ _data = Progress(enabled, seekAvailable, playing, position, duration)
checkIfPollingNeeded()
}
@@ -412,6 +417,7 @@
data class Progress(
val enabled: Boolean,
val seekAvailable: Boolean,
+ val playing: Boolean,
val elapsedTime: Int?,
val duration: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
new file mode 100644
index 0000000..f1058e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
@@ -0,0 +1,184 @@
+package com.android.systemui.media
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.ColorFilter
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.PixelFormat
+import android.graphics.drawable.Drawable
+import android.os.SystemClock
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.animation.Interpolators
+import kotlin.math.abs
+import kotlin.math.cos
+
+private const val TAG = "Squiggly"
+
+private const val TWO_PI = (Math.PI * 2f).toFloat()
+@VisibleForTesting
+internal const val DISABLED_ALPHA = 77
+
+class SquigglyProgress : Drawable() {
+
+ private val wavePaint = Paint()
+ private val linePaint = Paint()
+ private val path = Path()
+ private var heightFraction = 0f
+ private var heightAnimator: ValueAnimator? = null
+ private var phaseOffset = 0f
+ private var lastFrameTime = -1L
+
+ // Horizontal length of the sine wave
+ var waveLength = 0f
+ // Height of each peak of the sine wave
+ var lineAmplitude = 0f
+ // Line speed in px per second
+ var phaseSpeed = 0f
+ // Progress stroke width, both for wave and solid line
+ var strokeWidth = 0f
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ wavePaint.strokeWidth = value
+ linePaint.strokeWidth = value
+ }
+
+ init {
+ wavePaint.strokeCap = Paint.Cap.ROUND
+ linePaint.strokeCap = Paint.Cap.ROUND
+ linePaint.style = Paint.Style.STROKE
+ wavePaint.style = Paint.Style.STROKE
+ linePaint.alpha = DISABLED_ALPHA
+ }
+
+ var animate: Boolean = false
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ if (field) {
+ lastFrameTime = SystemClock.uptimeMillis()
+ }
+ heightAnimator?.cancel()
+ heightAnimator = ValueAnimator.ofFloat(heightFraction, if (animate) 1f else 0f).apply {
+ if (animate) {
+ startDelay = 60
+ duration = 800
+ interpolator = Interpolators.EMPHASIZED_DECELERATE
+ } else {
+ duration = 550
+ interpolator = Interpolators.STANDARD_DECELERATE
+ }
+ addUpdateListener {
+ heightFraction = it.animatedValue as Float
+ invalidateSelf()
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ heightAnimator = null
+ }
+ })
+ start()
+ }
+ }
+
+ override fun draw(canvas: Canvas) {
+ if (animate) {
+ invalidateSelf()
+ val now = SystemClock.uptimeMillis()
+ phaseOffset -= (now - lastFrameTime) / 1000f * phaseSpeed
+ phaseOffset %= waveLength
+ lastFrameTime = now
+ }
+
+ val totalProgressPx = (bounds.width() * (level / 10_000f))
+ canvas.save()
+ canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
+ // Clip drawing, so we stop at the thumb
+ canvas.clipRect(
+ 0f,
+ -lineAmplitude - strokeWidth,
+ totalProgressPx,
+ lineAmplitude + strokeWidth)
+
+ // The squiggly line
+ val start = phaseOffset
+ var currentX = start
+ var waveSign = 1f
+ path.rewind()
+ path.moveTo(start, lineAmplitude * heightFraction)
+ while (currentX < totalProgressPx) {
+ val nextX = currentX + waveLength / 2f
+ val nextWaveSign = waveSign * -1
+ path.cubicTo(
+ currentX + waveLength / 4f, lineAmplitude * waveSign * heightFraction,
+ nextX - waveLength / 4f, lineAmplitude * nextWaveSign * heightFraction,
+ nextX, lineAmplitude * nextWaveSign * heightFraction)
+ currentX = nextX
+ waveSign = nextWaveSign
+ }
+ wavePaint.style = Paint.Style.STROKE
+ canvas.drawPath(path, wavePaint)
+ canvas.restore()
+
+ // Draw round line cap at the beginning of the wave
+ val startAmp = cos(abs(phaseOffset) / waveLength * TWO_PI)
+ val p = Paint()
+ p.color = Color.WHITE
+ canvas.drawPoint(
+ bounds.left.toFloat(),
+ bounds.centerY() + startAmp * lineAmplitude * heightFraction,
+ wavePaint)
+
+ // Draw continuous line, to the right of the thumb
+ canvas.drawLine(
+ bounds.left.toFloat() + totalProgressPx,
+ bounds.centerY().toFloat(),
+ bounds.width().toFloat(),
+ bounds.centerY().toFloat(),
+ linePaint)
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.TRANSLUCENT
+ }
+
+ override fun setColorFilter(colorFilter: ColorFilter?) {
+ wavePaint.colorFilter = colorFilter
+ linePaint.colorFilter = colorFilter
+ }
+
+ override fun setAlpha(alpha: Int) {
+ wavePaint.alpha = alpha
+ linePaint.alpha = (DISABLED_ALPHA * (alpha / 255f)).toInt()
+ }
+
+ override fun getAlpha(): Int {
+ return wavePaint.alpha
+ }
+
+ override fun setTint(tintColor: Int) {
+ wavePaint.color = tintColor
+ linePaint.color = tintColor
+ }
+
+ override fun onLevelChange(level: Int): Boolean {
+ return animate
+ }
+
+ override fun setTintList(tint: ColorStateList?) {
+ if (tint == null) {
+ return
+ }
+ wavePaint.color = tint.defaultColor
+ linePaint.color = tint.defaultColor
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 355c69f..a8141c0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -21,7 +21,6 @@
import android.app.WallpaperColors;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -55,6 +54,7 @@
import androidx.recyclerview.widget.RecyclerView;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.statusbar.phone.SystemUIDialog;
/**
@@ -71,6 +71,7 @@
final Context mContext;
final MediaOutputController mMediaOutputController;
+ final BroadcastSender mBroadcastSender;
@VisibleForTesting
View mDialogView;
@@ -98,11 +99,13 @@
}
};
- public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
+ public MediaOutputBaseDialog(Context context, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
mContext = getContext();
+ mBroadcastSender = broadcastSender;
mMediaOutputController = mediaOutputController;
mLayoutManager = new LinearLayoutManager(mContext);
mListMaxHeight = context.getResources().getDimensionPixelSize(
@@ -152,7 +155,7 @@
dismiss();
});
mAppButton.setOnClickListener(v -> {
- mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mBroadcastSender.closeSystemDialogs();
if (mMediaOutputController.getAppLaunchIntent() != null) {
mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 0c202e0..0b6c68d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -53,7 +53,6 @@
import androidx.mediarouter.media.MediaRouter;
import androidx.mediarouter.media.MediaRouterParams;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -70,7 +69,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
-import com.android.systemui.statusbar.phone.ShadeController;
import java.util.ArrayList;
import java.util.Collection;
@@ -95,12 +93,9 @@
private final String mPackageName;
private final Context mContext;
private final MediaSessionManager mMediaSessionManager;
- private final LocalBluetoothManager mLocalBluetoothManager;
- private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
- private final boolean mAboveStatusbar;
private final CommonNotifCollection mNotifCollection;
@VisibleForTesting
final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -114,7 +109,6 @@
LocalMediaManager mLocalMediaManager;
private MediaOutputMetricLogger mMetricLogger;
- private UiEventLogger mUiEventLogger;
private int mColorActiveItem;
private int mColorInactiveItem;
@@ -124,23 +118,19 @@
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
- boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
- lbm, ShadeController shadeController, ActivityStarter starter,
- CommonNotifCollection notifCollection, UiEventLogger uiEventLogger,
+ MediaSessionManager mediaSessionManager, LocalBluetoothManager
+ lbm, ActivityStarter starter,
+ CommonNotifCollection notifCollection,
DialogLaunchAnimator dialogLaunchAnimator,
Optional<NearbyMediaDevicesManager> nearbyMediaDevicesManagerOptional) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
- mLocalBluetoothManager = lbm;
- mShadeController = shadeController;
mActivityStarter = starter;
- mAboveStatusbar = aboveStatusbar;
mNotifCollection = notifCollection;
InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
- mUiEventLogger = uiEventLogger;
mDialogLaunchAnimator = dialogLaunchAnimator;
mNearbyMediaDevicesManager = nearbyMediaDevicesManagerOptional.orElse(null);
mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
@@ -630,18 +620,6 @@
mActivityStarter.startActivity(launchIntent, true, controller);
}
- void launchMediaOutputGroupDialog(View mediaOutputDialog) {
- // We show the output group dialog from the output dialog.
- MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
- mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
- mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
- Optional.of(mNearbyMediaDevicesManager));
-
- MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
- controller);
- mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
- }
-
boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
final List<String> features = device.getFeatures();
return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 7696a1f..7834ec0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
/**
@@ -37,9 +38,9 @@
public class MediaOutputDialog extends MediaOutputBaseDialog {
final UiEventLogger mUiEventLogger;
- MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, UiEventLogger uiEventLogger) {
- super(context, mediaOutputController);
+ MediaOutputDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController, UiEventLogger uiEventLogger) {
+ super(context, broadcastSender, mediaOutputController);
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index a7e5480..0d7d60a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -22,10 +22,10 @@
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.nearby.NearbyMediaDevicesManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
-import com.android.systemui.statusbar.phone.ShadeController
import java.util.Optional
import javax.inject.Inject
@@ -36,8 +36,8 @@
private val context: Context,
private val mediaSessionManager: MediaSessionManager,
private val lbm: LocalBluetoothManager?,
- private val shadeController: ShadeController,
private val starter: ActivityStarter,
+ private val broadcastSender: BroadcastSender,
private val notifCollection: CommonNotifCollection,
private val uiEventLogger: UiEventLogger,
private val dialogLaunchAnimator: DialogLaunchAnimator,
@@ -52,10 +52,11 @@
// Dismiss the previous dialog, if any.
mediaOutputDialog?.dismiss()
- val controller = MediaOutputController(context, packageName, aboveStatusBar,
- mediaSessionManager, lbm, shadeController, starter, notifCollection,
- uiEventLogger, dialogLaunchAnimator, nearbyMediaDevicesManagerOptional)
- val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
+ val controller = MediaOutputController(context, packageName,
+ mediaSessionManager, lbm, starter, notifCollection,
+ dialogLaunchAnimator, nearbyMediaDevicesManagerOptional)
+ val dialog =
+ MediaOutputDialog(context, aboveStatusBar, broadcastSender, controller, uiEventLogger)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index f1c6601..bb3f969 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -25,6 +25,7 @@
import androidx.core.graphics.drawable.IconCompat;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
/**
* Dialog for media output group.
@@ -32,9 +33,9 @@
// TODO(b/203073091): Remove this class once group logic been implemented.
public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
- MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController) {
- super(context, mediaOutputController);
+ MediaOutputGroupDialog(Context context, boolean aboveStatusbar, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
+ super(context, broadcastSender, mediaOutputController);
mMediaOutputController.resetGroupMediaDevices();
mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index b4e20fd..2ac34b2 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -60,6 +60,7 @@
import com.android.settingslib.utils.PowerUtil;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -160,17 +161,20 @@
@VisibleForTesting SystemUIDialog mUsbHighTempDialog;
private BatteryStateSnapshot mCurrentBatterySnapshot;
private ActivityStarter mActivityStarter;
+ private final BroadcastSender mBroadcastSender;
/**
*/
@Inject
- public PowerNotificationWarnings(Context context, ActivityStarter activityStarter) {
+ public PowerNotificationWarnings(Context context, ActivityStarter activityStarter,
+ BroadcastSender broadcastSender) {
mContext = context;
mNoMan = mContext.getSystemService(NotificationManager.class);
mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mKeyguard = mContext.getSystemService(KeyguardManager.class);
mReceiver.init();
mActivityStarter = activityStarter;
+ mBroadcastSender = broadcastSender;
mUseSevereDialog = mContext.getResources().getBoolean(R.bool.config_severe_battery_dialog);
}
@@ -258,7 +262,7 @@
protected void showWarningNotification() {
if (showSevereLowBatteryDialog()) {
- mContext.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG)
+ mBroadcastSender.sendBroadcast(new Intent(ACTION_ENABLE_SEVERE_BATTERY_DIALOG)
.setPackage(mContext.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND));
@@ -716,9 +720,9 @@
mSaverConfirmation.dismiss();
}
// Also close the notification shade, if it's open.
- mContext.sendBroadcast(
+ mBroadcastSender.sendBroadcast(
new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
- .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
+ .setFlags(Intent.FLAG_RECEIVER_FOREGROUND));
final Uri uri = Uri.parse(getURL());
Context context = widget.getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index e1d2070..8bad2de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -47,9 +47,6 @@
public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> {
private static final String TAG = "InternetAdapter";
- private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
- private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
- private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
private final InternetDialogController mInternetDialogController;
@Nullable
@@ -169,11 +166,10 @@
}
mWifiListLayout.setOnClickListener(v -> {
if (wifiEntry.shouldEditBeforeConnect()) {
- final Intent intent = new Intent(ACTION_WIFI_DIALOG);
+ final Intent intent = WifiUtils.getWifiDialogIntent(wifiEntry.getKey(),
+ true /* connectForCaller */);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey());
- intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false);
mContext.startActivity(intent);
}
mInternetDialogController.connect(wifiEntry);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index b3bc3be..b322cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -112,7 +112,6 @@
"android.settings.NETWORK_PROVIDER_SETTINGS";
private static final String ACTION_WIFI_SCANNING_SETTINGS =
"android.settings.WIFI_SCANNING_SETTINGS";
- private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT);
public static final int NO_CELL_DATA_TYPE_ICON = 0;
private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off;
@@ -853,8 +852,8 @@
}
if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
- final Intent intent = new Intent("com.android.settings.WIFI_DIALOG")
- .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey());
+ final Intent intent = WifiUtils.getWifiDialogIntent(mWifiEntry.getKey(),
+ true /* connectForCaller */);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mActivityStarter.startActivity(intent, false /* dismissShade */);
} else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
new file mode 100644
index 0000000..0b98767
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DraggableConstraintLayout.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2021 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.screenshot;
+
+import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
+import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.systemui.R;
+
+/**
+ * ConstraintLayout that is draggable when touched in a specific region
+ */
+public class DraggableConstraintLayout extends ConstraintLayout
+ implements ViewTreeObserver.OnComputeInternalInsetsListener {
+
+ private final SwipeDismissHandler mSwipeDismissHandler;
+ private final GestureDetector mSwipeDetector;
+ private View mActionsContainer;
+ private SwipeDismissCallbacks mCallbacks;
+
+ /**
+ * Stores the callbacks when the view is interacted with or dismissed.
+ */
+ public interface SwipeDismissCallbacks {
+ /**
+ * Run when the view is interacted with (touched)
+ */
+ default void onInteraction() {
+
+ }
+
+ /**
+ * Run when the view is dismissed (the distance threshold is met), pre-dismissal animation
+ */
+ default void onSwipeDismissInitiated(Animator animator) {
+
+ }
+
+ /**
+ * Run when the view is dismissed (the distance threshold is met), post-dismissal animation
+ */
+ default void onDismissComplete() {
+
+ }
+ }
+
+ public DraggableConstraintLayout(Context context) {
+ this(context, null);
+ }
+
+ public DraggableConstraintLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DraggableConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mSwipeDismissHandler = new SwipeDismissHandler(mContext, this);
+ setOnTouchListener(mSwipeDismissHandler);
+
+ mSwipeDetector = new GestureDetector(mContext,
+ new GestureDetector.SimpleOnGestureListener() {
+ final Rect mActionsRect = new Rect();
+
+ @Override
+ public boolean onScroll(
+ MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
+ mActionsContainer.getBoundsOnScreen(mActionsRect);
+ // return true if we aren't in the actions bar, or if we are but it isn't
+ // scrollable in the direction of movement
+ return !mActionsRect.contains((int) ev2.getRawX(), (int) ev2.getRawY())
+ || !mActionsContainer.canScrollHorizontally((int) distanceX);
+ }
+ });
+ mSwipeDetector.setIsLongpressEnabled(false);
+ }
+
+ public void setCallbacks(SwipeDismissCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override // View
+ protected void onFinishInflate() {
+ mActionsContainer = findViewById(R.id.actions_container_background);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mSwipeDismissHandler.onTouch(this, ev);
+ }
+ return mSwipeDetector.onTouchEvent(ev);
+ }
+
+ public int getVisibleRight() {
+ return mActionsContainer.getRight();
+ }
+
+ /**
+ * Cancel current dismissal animation, if any
+ */
+ public void cancelDismissal() {
+ mSwipeDismissHandler.cancel();
+ }
+
+ /**
+ * Return whether the view is currently dismissing
+ */
+ public boolean isDismissing() {
+ return mSwipeDismissHandler.isDismissing();
+ }
+
+ /**
+ * Dismiss the view, with animation controlled by SwipeDismissHandler
+ */
+ public void dismiss() {
+ mSwipeDismissHandler.dismiss();
+ }
+
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+ }
+
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+ // Only child views are touchable.
+ Region r = new Region();
+ Rect rect = new Rect();
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).getGlobalVisibleRect(rect);
+ r.op(rect, Region.Op.UNION);
+ }
+ inoutInfo.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ inoutInfo.touchableRegion.set(r);
+ }
+
+ /**
+ * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not
+ * met
+ */
+ private class SwipeDismissHandler implements OnTouchListener {
+ private static final String TAG = "SwipeDismissHandler";
+
+ // distance needed to register a dismissal
+ private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
+
+ private final DraggableConstraintLayout mView;
+ private final GestureDetector mGestureDetector;
+ private final DisplayMetrics mDisplayMetrics;
+ private ValueAnimator mDismissAnimation;
+
+ private float mStartX;
+ // Keeps track of the most recent direction (between the last two move events).
+ // -1 for left; +1 for right.
+ private int mDirectionX;
+ private float mPreviousX;
+
+ SwipeDismissHandler(Context context, DraggableConstraintLayout view) {
+ mView = view;
+ GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
+ mGestureDetector = new GestureDetector(context, gestureListener);
+ mDisplayMetrics = new DisplayMetrics();
+ context.getDisplay().getRealMetrics(mDisplayMetrics);
+ mCallbacks = new SwipeDismissCallbacks() {
+ }; // default to unimplemented callbacks
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ boolean gestureResult = mGestureDetector.onTouchEvent(event);
+ mCallbacks.onInteraction();
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mStartX = event.getRawX();
+ mPreviousX = mStartX;
+ return true;
+ } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
+ return true;
+ }
+ if (isPastDismissThreshold()) {
+ dismiss();
+ } else {
+ // if we've moved, but not past the threshold, start the return animation
+ if (DEBUG_DISMISS) {
+ Log.d(TAG, "swipe gesture abandoned");
+ }
+ createSwipeReturnAnimation().start();
+ }
+ return true;
+ }
+ return gestureResult;
+ }
+
+ class SwipeDismissGestureListener extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onScroll(
+ MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
+ mView.setTranslationX(ev2.getRawX() - mStartX);
+ mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
+ mPreviousX = ev2.getRawX();
+ return true;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
+ float velocityY) {
+ if (mView.getTranslationX() * velocityX > 0
+ && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
+ ValueAnimator dismissAnimator =
+ createSwipeDismissAnimation(velocityX / (float) 1000);
+ mCallbacks.onSwipeDismissInitiated(dismissAnimator);
+ dismiss(dismissAnimator);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private boolean isPastDismissThreshold() {
+ float translationX = mView.getTranslationX();
+ // Determines whether the absolute translation from the start is in the same direction
+ // as the current movement. For example, if the user moves most of the way to the right,
+ // but then starts dragging back left, we do not dismiss even though the absolute
+ // distance is greater than the threshold.
+ if (translationX * mDirectionX > 0) {
+ return Math.abs(translationX) >= FloatingWindowUtil.dpToPx(mDisplayMetrics,
+ DISMISS_DISTANCE_THRESHOLD_DP);
+ }
+ return false;
+ }
+
+ boolean isDismissing() {
+ return (mDismissAnimation != null && mDismissAnimation.isRunning());
+ }
+
+ void cancel() {
+ if (isDismissing()) {
+ if (DEBUG_ANIM) {
+ Log.d(TAG, "cancelling dismiss animation");
+ }
+ mDismissAnimation.cancel();
+ }
+ }
+
+ void dismiss() {
+ ValueAnimator anim = createSwipeDismissAnimation(3);
+ mCallbacks.onSwipeDismissInitiated(anim);
+ dismiss(anim);
+ }
+
+ private void dismiss(ValueAnimator animator) {
+ mDismissAnimation = animator;
+ mDismissAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (!mCancelled) {
+ mCallbacks.onDismissComplete();
+ }
+ }
+ });
+ mDismissAnimation.start();
+ }
+
+ private ValueAnimator createSwipeDismissAnimation(float velocity) {
+ // velocity is measured in pixels per millisecond
+ velocity = Math.min(3, Math.max(1, velocity));
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ float startX = mView.getTranslationX();
+ // make sure the UI gets all the way off the screen in the direction of movement
+ // (the actions container background is guaranteed to be both the leftmost and
+ // rightmost UI element in LTR and RTL)
+ float finalX;
+ int layoutDir =
+ mView.getContext().getResources().getConfiguration().getLayoutDirection();
+ if (startX > 0 || (startX == 0 && layoutDir == LAYOUT_DIRECTION_RTL)) {
+ finalX = mDisplayMetrics.widthPixels;
+ } else {
+ finalX = -1 * mActionsContainer.getRight();
+ }
+ float distance = Math.abs(finalX - startX);
+
+ anim.addUpdateListener(animation -> {
+ float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
+ mView.setTranslationX(translation);
+ mView.setAlpha(1 - animation.getAnimatedFraction());
+ });
+ anim.setDuration((long) (distance / Math.abs(velocity)));
+ return anim;
+ }
+
+ private ValueAnimator createSwipeReturnAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ float startX = mView.getTranslationX();
+ float finalX = 0;
+
+ anim.addUpdateListener(animation -> {
+ float translation = MathUtils.lerp(
+ startX, finalX, animation.getAnimatedFraction());
+ mView.setTranslationX(translation);
+ });
+
+ return anim;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 50765f2..009d4b9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -88,10 +88,12 @@
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.R;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
+import com.android.systemui.util.Assert;
import com.google.common.util.concurrent.ListenableFuture;
@@ -247,6 +249,7 @@
private final ImageExporter mImageExporter;
private final Executor mMainExecutor;
private final ExecutorService mBgExecutor;
+ private final BroadcastSender mBroadcastSender;
private final WindowManager mWindowManager;
private final WindowManager.LayoutParams mWindowLayoutParams;
@@ -271,7 +274,6 @@
private String mPackageName = "";
private BroadcastReceiver mCopyBroadcastReceiver;
-
/** Tracks config changes that require re-creating UI */
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
ActivityInfo.CONFIG_ORIENTATION
@@ -293,7 +295,8 @@
ScrollCaptureController scrollCaptureController,
LongScreenshotData longScreenshotHolder,
ActivityManager activityManager,
- TimeoutHandler timeoutHandler) {
+ TimeoutHandler timeoutHandler,
+ BroadcastSender broadcastSender) {
mScreenshotSmartActions = screenshotSmartActions;
mNotificationsController = screenshotNotificationsController;
mScrollCaptureClient = scrollCaptureClient;
@@ -304,6 +307,7 @@
mLongScreenshotHolder = longScreenshotHolder;
mIsLowRamDevice = activityManager.isLowRamDevice();
mBgExecutor = Executors.newSingleThreadExecutor();
+ mBroadcastSender = broadcastSender;
mScreenshotHandler = timeoutHandler;
mScreenshotHandler.setDefaultTimeoutMillis(SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS);
@@ -355,8 +359,10 @@
ClipboardOverlayController.SELF_PERMISSION, null, Context.RECEIVER_NOT_EXPORTED);
}
+ @MainThread
void takeScreenshotFullscreen(ComponentName topComponent, Consumer<Uri> finisher,
RequestCallback requestCallback) {
+ Assert.isMainThread();
mCurrentRequestCallback = requestCallback;
DisplayMetrics displayMetrics = new DisplayMetrics();
getDefaultDisplay().getRealMetrics(displayMetrics);
@@ -365,11 +371,12 @@
new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels));
}
+ @MainThread
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
Consumer<Uri> finisher, RequestCallback requestCallback) {
// TODO: use task Id, userId, topComponent for smart handler
-
+ Assert.isMainThread();
if (screenshot == null) {
Log.e(TAG, "Got null bitmap from screenshot message");
mNotificationsController.notifyScreenshotError(
@@ -392,8 +399,10 @@
/**
* Displays a screenshot selector
*/
+ @MainThread
void takeScreenshotPartial(ComponentName topComponent,
final Consumer<Uri> finisher, RequestCallback requestCallback) {
+ Assert.isMainThread();
mScreenshotView.reset();
mCurrentRequestCallback = requestCallback;
@@ -517,7 +526,7 @@
saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true);
- mContext.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
+ mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
ClipboardOverlayController.SELF_PERMISSION);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 6d729b9..6af6e36 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -141,7 +141,7 @@
private ScreenshotSelectorView mScreenshotSelectorView;
private ImageView mScrollingScrim;
- private View mScreenshotStatic;
+ private DraggableConstraintLayout mScreenshotStatic;
private ImageView mScreenshotPreview;
private View mScreenshotPreviewBorder;
private ImageView mScrollablePreview;
@@ -159,7 +159,6 @@
private UiEventLogger mUiEventLogger;
private ScreenshotViewCallback mCallbacks;
private boolean mPendingSharedTransition;
- private SwipeDismissHandler mSwipeDismissHandler;
private InputMonitorCompat mInputMonitor;
private InputChannelCompat.InputEventReceiver mInputEventReceiver;
private boolean mShowScrollablePreview;
@@ -332,19 +331,6 @@
}
}
- @Override // ViewGroup
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // scrolling scrim should not be swipeable; return early if we're on the scrim
- if (!getSwipeRegion().contains((int) ev.getRawX(), (int) ev.getRawY())) {
- return false;
- }
- // always pass through the down event so the swipe handler knows the initial state
- if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mSwipeDismissHandler.onTouch(this, ev);
- }
- return mSwipeDetector.onTouchEvent(ev);
- }
-
@Override // View
protected void onFinishInflate() {
mScrollingScrim = requireNonNull(findViewById(R.id.screenshot_scrolling_scrim));
@@ -356,8 +342,8 @@
mScreenshotPreview.setClipToOutline(true);
mActionsContainerBackground = requireNonNull(findViewById(
- R.id.screenshot_actions_container_background));
- mActionsContainer = requireNonNull(findViewById(R.id.screenshot_actions_container));
+ R.id.actions_container_background));
+ mActionsContainer = requireNonNull(findViewById(R.id.actions_container));
mActionsView = requireNonNull(findViewById(R.id.screenshot_actions));
mBackgroundProtection = requireNonNull(
findViewById(R.id.screenshot_actions_background));
@@ -395,35 +381,34 @@
setFocusableInTouchMode(true);
requestFocus();
- mSwipeDismissHandler = new SwipeDismissHandler(mContext, mScreenshotStatic,
- new SwipeDismissHandler.SwipeDismissCallbacks() {
- @Override
- public void onInteraction() {
- mCallbacks.onUserInteraction();
- }
+ mScreenshotStatic.setCallbacks(new DraggableConstraintLayout.SwipeDismissCallbacks() {
+ @Override
+ public void onInteraction() {
+ mCallbacks.onUserInteraction();
+ }
+ @Override
+ public void onSwipeDismissInitiated(Animator animator) {
+ if (DEBUG_DISMISS) {
+ Log.d(ScreenshotView.TAG, "dismiss triggered via swipe gesture");
+ }
+ mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
+ mPackageName);
+ animator.addListener(new AnimatorListenerAdapter() {
@Override
- public void onSwipeDismissInitiated(Animator anim) {
- if (DEBUG_DISMISS) {
- Log.d(ScreenshotView.TAG, "dismiss triggered via swipe gesture");
- }
- mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
- mPackageName);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- mBackgroundProtection.animate()
- .alpha(0).setDuration(anim.getDuration()).start();
- }
- });
- }
-
- @Override
- public void onDismissComplete() {
- mCallbacks.onDismiss();
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mBackgroundProtection.animate()
+ .alpha(0).setDuration(animation.getDuration()).start();
}
});
+ }
+
+ @Override
+ public void onDismissComplete() {
+ mCallbacks.onDismiss();
+ }
+ });
}
View getScreenshotPreview() {
@@ -648,8 +633,6 @@
requestLayout();
createScreenshotActionsShadeAnimation().start();
-
- setOnTouchListener(mSwipeDismissHandler);
}
});
@@ -958,7 +941,7 @@
}
boolean isDismissing() {
- return mSwipeDismissHandler.isDismissing();
+ return mScreenshotStatic.isDismissing();
}
boolean isPendingSharedTransition() {
@@ -966,15 +949,14 @@
}
void animateDismissal() {
- mSwipeDismissHandler.dismiss();
+ mScreenshotStatic.dismiss();
}
void reset() {
if (DEBUG_UI) {
Log.d(TAG, "reset screenshot view");
}
-
- mSwipeDismissHandler.cancel();
+ mScreenshotStatic.cancelDismissal();
if (DEBUG_WINDOW) {
Log.d(TAG, "removing OnComputeInternalInsetsListener");
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java b/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
deleted file mode 100644
index 24b1249..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SwipeDismissHandler.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2021 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.screenshot;
-
-import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM;
-import static com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * Allows a view to be swipe-dismissed, or returned to its location if distance threshold is not met
- */
-public class SwipeDismissHandler implements View.OnTouchListener {
- private static final String TAG = "SwipeDismissHandler";
-
- // distance needed to register a dismissal
- private static final float DISMISS_DISTANCE_THRESHOLD_DP = 20;
-
- /**
- * Stores the callbacks when the view is interacted with or dismissed.
- */
- public interface SwipeDismissCallbacks {
- /**
- * Run when the view is interacted with (touched)
- */
- void onInteraction();
-
- /**
- * Run when the view is dismissed (the distance threshold is met), pre-dismissal animation
- */
- void onSwipeDismissInitiated(Animator animator);
-
- /**
- * Run when the view is dismissed (the distance threshold is met), post-dismissal animation
- */
- void onDismissComplete();
- }
-
- private final View mView;
- private final SwipeDismissCallbacks mCallbacks;
- private final GestureDetector mGestureDetector;
- private DisplayMetrics mDisplayMetrics;
- private ValueAnimator mDismissAnimation;
-
-
- private float mStartX;
- // Keeps track of the most recent direction (between the last two move events).
- // -1 for left; +1 for right.
- private int mDirectionX;
- private float mPreviousX;
-
- public SwipeDismissHandler(Context context, View view, SwipeDismissCallbacks callbacks) {
- mView = view;
- mCallbacks = callbacks;
- GestureDetector.OnGestureListener gestureListener = new SwipeDismissGestureListener();
- mGestureDetector = new GestureDetector(context, gestureListener);
- mDisplayMetrics = new DisplayMetrics();
- context.getDisplay().getRealMetrics(mDisplayMetrics);
- }
-
- @Override
- public boolean onTouch(View view, MotionEvent event) {
- boolean gestureResult = mGestureDetector.onTouchEvent(event);
- mCallbacks.onInteraction();
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mStartX = event.getRawX();
- mPreviousX = mStartX;
- return true;
- } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
- if (mDismissAnimation != null && mDismissAnimation.isRunning()) {
- return true;
- }
- if (isPastDismissThreshold()) {
- ValueAnimator dismissAnimator = createSwipeDismissAnimation(1);
- mCallbacks.onSwipeDismissInitiated(dismissAnimator);
- dismiss(dismissAnimator);
- } else {
- // if we've moved, but not past the threshold, start the return animation
- if (DEBUG_DISMISS) {
- Log.d(TAG, "swipe gesture abandoned");
- }
- createSwipeReturnAnimation().start();
- }
- return true;
- }
- return gestureResult;
- }
-
- class SwipeDismissGestureListener extends GestureDetector.SimpleOnGestureListener {
- @Override
- public boolean onScroll(
- MotionEvent ev1, MotionEvent ev2, float distanceX, float distanceY) {
- mView.setTranslationX(ev2.getRawX() - mStartX);
- mDirectionX = (ev2.getRawX() < mPreviousX) ? -1 : 1;
- mPreviousX = ev2.getRawX();
- return true;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- if (mView.getTranslationX() * velocityX > 0
- && (mDismissAnimation == null || !mDismissAnimation.isRunning())) {
- ValueAnimator dismissAnimator =
- createSwipeDismissAnimation(velocityX / (float) 1000);
- mCallbacks.onSwipeDismissInitiated(dismissAnimator);
- dismiss(dismissAnimator);
- return true;
- }
- return false;
- }
- }
-
- private boolean isPastDismissThreshold() {
- float translationX = mView.getTranslationX();
- // Determines whether the absolute translation from the start is in the same direction
- // as the current movement. For example, if the user moves most of the way to the right,
- // but then starts dragging back left, we do not dismiss even though the absolute
- // distance is greater than the threshold.
- if (translationX * mDirectionX > 0) {
- return Math.abs(translationX) >= FloatingWindowUtil.dpToPx(mDisplayMetrics,
- DISMISS_DISTANCE_THRESHOLD_DP);
- }
- return false;
- }
-
- /**
- * Return whether the view is currently being dismissed
- */
- public boolean isDismissing() {
- return (mDismissAnimation != null && mDismissAnimation.isRunning());
- }
-
- /**
- * Cancel the currently-running dismissal animation, if any.
- */
- public void cancel() {
- if (isDismissing()) {
- if (DEBUG_ANIM) {
- Log.d(TAG, "cancelling dismiss animation");
- }
- mDismissAnimation.cancel();
- }
- }
-
- /**
- * Start dismissal animation (will run onDismiss callback when animation complete)
- */
- public void dismiss() {
- dismiss(createSwipeDismissAnimation(1));
- }
-
- private void dismiss(ValueAnimator animator) {
- mDismissAnimation = animator;
- mDismissAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (!mCancelled) {
- mCallbacks.onDismissComplete();
- }
- }
- });
- mDismissAnimation.start();
- }
-
- private ValueAnimator createSwipeDismissAnimation(float velocity) {
- // velocity is measured in pixels per millisecond
- velocity = Math.min(3, Math.max(1, velocity));
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- float startX = mView.getTranslationX();
- // make sure the UI gets all the way off the screen in the direction of movement
- // (the actions container background is guaranteed to be both the leftmost and
- // rightmost UI element in LTR and RTL)
- float finalX;
- int layoutDir = mView.getContext().getResources().getConfiguration().getLayoutDirection();
- if (startX > 0 || (startX == 0 && layoutDir == View.LAYOUT_DIRECTION_RTL)) {
- finalX = mDisplayMetrics.widthPixels;
- } else {
- finalX = -1 * mView.getRight();
- }
- float distance = Math.abs(finalX - startX);
-
- anim.addUpdateListener(animation -> {
- float translation = MathUtils.lerp(startX, finalX, animation.getAnimatedFraction());
- mView.setTranslationX(translation);
- mView.setAlpha(1 - animation.getAnimatedFraction());
- });
- anim.setDuration((long) (distance / Math.abs(velocity)));
- return anim;
- }
-
- private ValueAnimator createSwipeReturnAnimation() {
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- float startX = mView.getTranslationX();
- float finalX = 0;
-
- anim.addUpdateListener(animation -> {
- float translation = MathUtils.lerp(
- startX, finalX, animation.getAnimatedFraction());
- mView.setTranslationX(translation);
- });
-
- return anim;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 98e6bd1..924351d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -51,7 +51,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.R;
-import com.android.systemui.shared.recents.utilities.BitmapUtil;
import java.util.function.Consumer;
@@ -208,7 +207,7 @@
if (DEBUG_SERVICE) {
Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
}
- Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ Bitmap screenshot = ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap(
screenshotRequest.getBitmapBundle());
Rect screenBounds = screenshotRequest.getBoundsInScreen();
Insets insets = screenshotRequest.getInsets();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 1ab0345..ab4d0dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -406,6 +406,7 @@
mediaHierarchyManager.setTransitionToFullShadeAmount(field)
transitionToShadeAmountCommon(field)
+ transitionToShadeAmountKeyguard(field)
}
}
}
@@ -420,11 +421,6 @@
val scrimProgress = MathUtils.saturate(dragDownAmount / scrimTransitionDistance)
scrimController.setTransitionToFullShadeProgress(scrimProgress)
- // Fade out all content only visible on the lockscreen
- val npvcProgress =
- MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
- notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - npvcProgress)
-
if (depthControllerTransitionDistance > 0) {
val depthProgress =
MathUtils.saturate(dragDownAmount / depthControllerTransitionDistance)
@@ -438,6 +434,22 @@
centralSurfaces.setTransitionToFullShadeProgress(statusBarProgress)
}
+ private fun transitionToShadeAmountKeyguard(dragDownAmount: Float) {
+ // Fade out all content only visible on the lockscreen
+ val keyguardAlphaProgress =
+ MathUtils.saturate(dragDownAmount / npvcKeyguardContentAlphaTransitionDistance)
+ val keyguardAlpha = 1f - keyguardAlphaProgress
+ val keyguardTranslationY = if (useSplitShade) {
+ // On split-shade, the translationY of the keyguard should stay in sync with the
+ // translation of media.
+ mediaHierarchyManager.getGuidedTransformationTranslationY()
+ } else {
+ 0
+ }
+ notificationPanelController
+ .setKeyguardTransitionProgress(keyguardAlpha, keyguardTranslationY)
+ }
+
private fun setDragDownAmountAnimated(
target: Float,
delay: Long = 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 267ee6d..a0388de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -259,6 +259,7 @@
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
keyguardAnimator = null
+ wakeAndUnlockBlurRadius = 0f
scheduleUpdate()
}
})
@@ -439,7 +440,7 @@
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
it.println("shadeExpansion: $shadeExpansion")
- it.println("shouldApplyShaeBlur: ${shouldApplyShadeBlur()}")
+ it.println("shouldApplyShadeBlur: ${shouldApplyShadeBlur()}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 369ef34..2baa079 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -230,7 +230,13 @@
mPipelineState.requireState(STATE_IDLE);
mNotifSections.clear();
+ NotifSectioner lastSection = null;
for (NotifSectioner sectioner : sectioners) {
+ if (lastSection != null && lastSection.getBucket() > sectioner.getBucket()) {
+ throw new IllegalArgumentException("setSectioners with non contiguous sections "
+ + lastSection.getName() + " - " + lastSection.getBucket() + " & "
+ + sectioner.getName() + " - " + sectioner.getBucket());
+ }
final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
final NotifComparator sectionComparator = section.getComparator();
mNotifSections.add(section);
@@ -238,6 +244,7 @@
if (sectionComparator != null) {
sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
}
+ lastSection = sectioner;
}
mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index 22300d8..1237c70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -16,36 +16,16 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.app.Notification.VISIBILITY_SECRET;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
-
-import androidx.annotation.MainThread;
-
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import javax.inject.Inject;
@@ -56,171 +36,48 @@
@CoordinatorScope
public class KeyguardCoordinator implements Coordinator {
private static final String TAG = "KeyguardCoordinator";
-
- private final Context mContext;
- private final Handler mMainHandler;
- private final KeyguardStateController mKeyguardStateController;
- private final NotificationLockscreenUserManager mLockscreenUserManager;
- private final BroadcastDispatcher mBroadcastDispatcher;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final HighPriorityProvider mHighPriorityProvider;
private final SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
-
- private boolean mHideSilentNotificationsOnLockscreen;
+ private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@Inject
public KeyguardCoordinator(
- Context context,
- @MainThread Handler mainThreadHandler,
- KeyguardStateController keyguardStateController,
- NotificationLockscreenUserManager lockscreenUserManager,
- BroadcastDispatcher broadcastDispatcher,
StatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
HighPriorityProvider highPriorityProvider,
- SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider) {
- mContext = context;
- mMainHandler = mainThreadHandler;
- mKeyguardStateController = keyguardStateController;
- mLockscreenUserManager = lockscreenUserManager;
- mBroadcastDispatcher = broadcastDispatcher;
+ SectionHeaderVisibilityProvider sectionHeaderVisibilityProvider,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mHighPriorityProvider = highPriorityProvider;
mSectionHeaderVisibilityProvider = sectionHeaderVisibilityProvider;
+ mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
}
@Override
public void attach(NotifPipeline pipeline) {
- readShowSilentNotificationSetting();
setupInvalidateNotifListCallbacks();
// Filter at the "finalize" stage so that views remain bound by PreparationCoordinator
pipeline.addFinalizeFilter(mNotifFilter);
-
+ mKeyguardNotificationVisibilityProvider
+ .addOnStateChangedListener(this::invalidateListFromFilter);
updateSectionHeadersVisibility();
}
private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- final StatusBarNotification sbn = entry.getSbn();
-
- // FILTER OUT the notification when the keyguard is showing and...
- if (mKeyguardStateController.isShowing()) {
- // ... user settings or the device policy manager doesn't allow lockscreen
- // notifications;
- if (!mLockscreenUserManager.shouldShowLockscreenNotifications()) {
- return true;
- }
-
- final int currUserId = mLockscreenUserManager.getCurrentUserId();
- final int notifUserId = (sbn.getUser().getIdentifier() == UserHandle.USER_ALL)
- ? currUserId : sbn.getUser().getIdentifier();
-
- // ... user is in lockdown
- if (mKeyguardUpdateMonitor.isUserInLockdown(currUserId)
- || mKeyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
- return true;
- }
-
- // ... device is in public mode and the user's settings doesn't allow
- // notifications to show in public mode
- if (mLockscreenUserManager.isLockscreenPublicMode(currUserId)
- || mLockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
- if (entry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET) {
- return true;
- }
-
- if (!mLockscreenUserManager.userAllowsNotificationsInPublic(currUserId)
- || !mLockscreenUserManager.userAllowsNotificationsInPublic(
- notifUserId)) {
- return true;
- }
- }
-
- // ... neither this notification nor its group have high enough priority
- // to be shown on the lockscreen
- if (entry.getParent() != null) {
- final GroupEntry parent = entry.getParent();
- if (priorityExceedsLockscreenShowingThreshold(parent)) {
- return false;
- }
- }
- return !priorityExceedsLockscreenShowingThreshold(entry);
- }
- return false;
+ return mKeyguardNotificationVisibilityProvider.hideNotification(entry);
}
};
- private boolean priorityExceedsLockscreenShowingThreshold(ListEntry entry) {
- if (entry == null) {
- return false;
- }
- if (mHideSilentNotificationsOnLockscreen) {
- return mHighPriorityProvider.isHighPriority(entry);
- } else {
- return entry.getRepresentativeEntry() != null
- && !entry.getRepresentativeEntry().getRanking().isAmbient();
- }
- }
-
// TODO(b/206118999): merge this class with SensitiveContentCoordinator which also depends on
// these same updates
private void setupInvalidateNotifListCallbacks() {
- // register onKeyguardShowing callback
- mKeyguardStateController.addCallback(mKeyguardCallback);
- mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
- // register lockscreen settings changed callbacks:
- final ContentObserver settingsObserver = new ContentObserver(mMainHandler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (uri.equals(Settings.Secure.getUriFor(
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS))) {
- readShowSilentNotificationSetting();
- }
-
- if (mKeyguardStateController.isShowing()) {
- invalidateListFromFilter("Settings " + uri + " changed");
- }
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
- false,
- settingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- settingsObserver,
- UserHandle.USER_ALL);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
- false,
- settingsObserver);
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
- false,
- settingsObserver,
- UserHandle.USER_ALL);
-
- // register (maybe) public mode changed callbacks:
- mStatusBarStateController.addCallback(mStatusBarStateListener);
- mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mKeyguardStateController.isShowing()) {
- // maybe public mode changed
- invalidateListFromFilter(intent.getAction());
- }
- }}, new IntentFilter(Intent.ACTION_USER_SWITCHED));
}
private void invalidateListFromFilter(String reason) {
@@ -228,49 +85,10 @@
mNotifFilter.invalidateList();
}
- private void readShowSilentNotificationSetting() {
- mHideSilentNotificationsOnLockscreen =
- Settings.Secure.getInt(
- mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
- 1) == 0;
- }
-
private void updateSectionHeadersVisibility() {
boolean onKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
boolean neverShowSections = mSectionHeaderVisibilityProvider.getNeverShowSectionHeaders();
boolean showSections = !onKeyguard && !neverShowSections;
mSectionHeaderVisibilityProvider.setSectionHeadersVisible(showSections);
}
-
- private final KeyguardStateController.Callback mKeyguardCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onUnlockedChanged() {
- invalidateListFromFilter("onUnlockedChanged");
- }
-
- @Override
- public void onKeyguardShowingChanged() {
- invalidateListFromFilter("onKeyguardShowingChanged");
- }
- };
-
- private final StatusBarStateController.StateListener mStatusBarStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- // maybe public mode changed
- invalidateListFromFilter("onStatusBarStateChanged");
- }
- };
-
- private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
- @Override
- public void onStrongAuthStateChanged(int userId) {
- // maybe lockdown mode changed
- invalidateListFromFilter("onStrongAuthStateChanged");
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
index c35b77c..6db544c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -57,6 +57,7 @@
var currentSection: NotifSection? = null
val prevSections = mutableSetOf<NotifSection?>()
+ var lastSection: NotifSection? = null
val showHeaders = sectionHeaderVisibilityProvider.sectionHeadersVisible
val sectionOrder = mutableListOf<NotifSection?>()
val sectionHeaders = mutableMapOf<NotifSection?, NodeController?>()
@@ -65,6 +66,14 @@
for (entry in notifList) {
val section = entry.section!!
+ lastSection?.let {
+ if (it.bucket > section.bucket) {
+ throw IllegalStateException("buildNodeSpec with non contiguous section " +
+ "buckets ${it.sectioner.name} - ${it.bucket} & " +
+ "${it.sectioner.name} - ${it.bucket}")
+ }
+ }
+ lastSection = section
if (prevSections.contains(section)) {
throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
new file mode 100644
index 0000000..70c9a16
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -0,0 +1,186 @@
+package com.android.systemui.statusbar.notification.interruption
+
+import android.app.Notification
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.CoreStartable
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.ListenerSet
+import java.util.function.Consumer
+import javax.inject.Inject
+
+/**
+ * Determines if notifications should be visible based on the state of the keyguard
+ */
+class KeyguardNotificationVisibilityProvider @Inject constructor(
+ context: Context,
+ @Main private val handler: Handler,
+ private val keyguardStateController: KeyguardStateController,
+ private val lockscreenUserManager: NotificationLockscreenUserManager,
+ private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val highPriorityProvider: HighPriorityProvider,
+ private val statusBarStateController: StatusBarStateController,
+ private val broadcastDispatcher: BroadcastDispatcher
+) : CoreStartable(context) {
+ private val onStateChangedListeners = ListenerSet<Consumer<String>>()
+ private var hideSilentNotificationsOnLockscreen: Boolean = false
+
+ override fun start() {
+ readShowSilentNotificationSetting()
+ keyguardStateController.addCallback(object : KeyguardStateController.Callback {
+ override fun onUnlockedChanged() {
+ notifyStateChanged("onUnlockedChanged")
+ }
+
+ override fun onKeyguardShowingChanged() {
+ notifyStateChanged("onKeyguardShowingChanged")
+ }
+ })
+ keyguardUpdateMonitor.registerCallback(object : KeyguardUpdateMonitorCallback() {
+ override fun onStrongAuthStateChanged(userId: Int) {
+ notifyStateChanged("onStrongAuthStateChanged")
+ }
+ })
+
+ // register lockscreen settings changed callbacks:
+ val settingsObserver: ContentObserver = object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri) {
+ if (keyguardStateController.isShowing) {
+ notifyStateChanged("Settings $uri changed")
+ }
+ }
+ }
+
+ mContext.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS),
+ false,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ mContext.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ mContext.contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+ false,
+ settingsObserver)
+
+ mContext.contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS),
+ false,
+ settingsObserver,
+ UserHandle.USER_ALL)
+
+ // register (maybe) public mode changed callbacks:
+ statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
+ override fun onStateChanged(state: Int) {
+ notifyStateChanged("onStatusBarStateChanged")
+ }
+ })
+ broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (keyguardStateController.isShowing()) {
+ // maybe public mode changed
+ notifyStateChanged(intent.action)
+ }
+ }
+ }, IntentFilter(Intent.ACTION_USER_SWITCHED))
+ }
+
+ fun addOnStateChangedListener(listener: Consumer<String>) {
+ onStateChangedListeners.addIfAbsent(listener)
+ }
+
+ fun removeOnStateChangedListener(listener: Consumer<String>) {
+ onStateChangedListeners.remove(listener)
+ }
+
+ private fun notifyStateChanged(reason: String) {
+ onStateChangedListeners.forEach({ it.accept(reason) })
+ }
+
+ /**
+ * Determines if the given notification should be hidden based on the current keyguard state.
+ * If Listener#onKeyguardStateChanged is invoked, the results of this method may no longer
+ * be valid, and so should be re-queried
+ */
+ fun hideNotification(entry: NotificationEntry): Boolean {
+ val sbn = entry.sbn
+ // FILTER OUT the notification when the keyguard is showing and...
+ if (keyguardStateController.isShowing()) {
+ // ... user settings or the device policy manager doesn't allow lockscreen
+ // notifications;
+ if (!lockscreenUserManager.shouldShowLockscreenNotifications()) {
+ return true
+ }
+ val currUserId: Int = lockscreenUserManager.getCurrentUserId()
+ val notifUserId =
+ if (sbn.user.identifier == UserHandle.USER_ALL) currUserId
+ else sbn.user.identifier
+
+ // ... user is in lockdown
+ if (keyguardUpdateMonitor.isUserInLockdown(currUserId) ||
+ keyguardUpdateMonitor.isUserInLockdown(notifUserId)) {
+ return true
+ }
+
+ // ... device is in public mode and the user's settings doesn't allow
+ // notifications to show in public mode
+ if (lockscreenUserManager.isLockscreenPublicMode(currUserId) ||
+ lockscreenUserManager.isLockscreenPublicMode(notifUserId)) {
+ if (entry.ranking.lockscreenVisibilityOverride == Notification.VISIBILITY_SECRET) {
+ return true
+ }
+ if (!lockscreenUserManager.userAllowsNotificationsInPublic(currUserId) ||
+ !lockscreenUserManager.userAllowsNotificationsInPublic(
+ notifUserId)) {
+ return true
+ }
+ }
+
+ // ... neither this notification nor its group have high enough priority
+ // to be shown on the lockscreen
+ if (entry.parent != null) {
+ val parent = entry.parent
+ if (priorityExceedsLockscreenShowingThreshold(parent)) {
+ return false
+ }
+ }
+ return !priorityExceedsLockscreenShowingThreshold(entry)
+ }
+ return false
+ }
+
+ private fun priorityExceedsLockscreenShowingThreshold(entry: ListEntry?): Boolean =
+ when {
+ entry == null -> false
+ hideSilentNotificationsOnLockscreen -> highPriorityProvider.isHighPriority(entry)
+ else -> entry.representativeEntry?.ranking?.isAmbient == false
+ }
+
+ private fun readShowSilentNotificationSetting() {
+ hideSilentNotificationsOnLockscreen = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
+ 1) == 0
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index c991376..6c99e3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -211,6 +211,14 @@
"Pulsing: $str1"
})
}
+
+ fun keyguardHideNotification(key: String) {
+ hunBuffer.log(TAG, DEBUG, {
+ str1 = key
+ }, {
+ "Keyguard Hide Notification: $str1"
+ })
+ }
}
private const val TAG = "InterruptionStateProvider"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 7ed2699..c1771cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -36,6 +36,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -66,6 +67,8 @@
private final ContentObserver mHeadsUpObserver;
private final HeadsUpManager mHeadsUpManager;
private final NotificationInterruptLogger mLogger;
+ private final NotifPipelineFlags mFlags;
+ private final KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
@@ -81,7 +84,9 @@
StatusBarStateController statusBarStateController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- @Main Handler mainHandler) {
+ @Main Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
@@ -91,6 +96,8 @@
mStatusBarStateController = statusBarStateController;
mHeadsUpManager = headsUpManager;
mLogger = logger;
+ mFlags = flags;
+ mKeyguardNotificationVisibilityProvider = keyguardNotificationVisibilityProvider;
mHeadsUpObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -282,7 +289,7 @@
private boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mNotificationFilter.shouldFilterOut(entry)) {
+ if (!mFlags.isNewPipelineEnabled() && mNotificationFilter.shouldFilterOut(entry)) {
mLogger.logNoAlertingFilteredOut(sbn);
return false;
}
@@ -305,6 +312,11 @@
return false;
}
+ if (mKeyguardNotificationVisibilityProvider.hideNotification(entry)) {
+ mLogger.keyguardHideNotification(entry.getKey());
+ return false;
+ }
+
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7df8e7d..6bbecc8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1233,10 +1233,6 @@
mView.forceNoOverlappingRendering(force);
}
- public void setTranslationX(float translation) {
- mView.setTranslationX(translation);
- }
-
public void setExpandingVelocity(float velocity) {
mView.setExpandingVelocity(velocity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 84adc56..a7f950e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -663,7 +663,6 @@
protected final BatteryController mBatteryController;
protected boolean mPanelExpanded;
private UiModeManager mUiModeManager;
- protected boolean mIsKeyguard;
private LogMaker mStatusBarStateLog;
protected final NotificationIconAreaController mNotificationIconAreaController;
@Nullable private View mAmbientIndicationContainer;
@@ -1142,7 +1141,7 @@
}
if (leaveOpen) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
- if (mIsKeyguard) {
+ if (mKeyguardStateController.isShowing()) {
// When device state changes on keyguard we don't want to keep the state of
// the shade and instead we open clean state of keyguard with shade closed.
// Normally some parts of QS state (like expanded/collapsed) are persisted and
@@ -2890,7 +2889,9 @@
// late in the transition, so we also allow the device to start dozing once the screen has
// turned off fully.
boolean keyguardForDozing = mDozeServiceHost.getDozingRequested()
- && (!mDeviceInteractive || isGoingToSleep() && (isScreenFullyOff() || mIsKeyguard));
+ && (!mDeviceInteractive || (isGoingToSleep()
+ && (isScreenFullyOff()
+ || (mKeyguardStateController.isShowing() && !isOccluded()))));
boolean isWakingAndOccluded = isOccluded() && isWaking();
boolean shouldBeKeyguard = (mStatusBarStateController.isKeyguardRequested()
|| keyguardForDozing) && !wakeAndUnlocking && !isWakingAndOccluded;
@@ -2923,7 +2924,6 @@
public void showKeyguardImpl() {
Trace.beginSection("CentralSurfaces#showKeyguard");
- mIsKeyguard = true;
// In case we're locking while a smartspace transition is in progress, reset it.
mKeyguardUnlockAnimationController.resetSmartspaceTransition();
if (mKeyguardStateController.isLaunchTransitionFadingAway()) {
@@ -3044,7 +3044,6 @@
* @return true if we would like to stay in the shade, false if it should go away entirely
*/
public boolean hideKeyguardImpl(boolean forceStateChange) {
- mIsKeyguard = false;
Trace.beginSection("CentralSurfaces#hideKeyguard");
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
int previousState = mStatusBarStateController.getState();
@@ -3771,7 +3770,7 @@
});
} else if (mDozing && !unlocking) {
mScrimController.transitionTo(ScrimState.AOD);
- } else if (mIsKeyguard && !unlocking) {
+ } else if (mKeyguardStateController.isShowing() && !isOccluded() && !unlocking) {
mScrimController.transitionTo(ScrimState.KEYGUARD);
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index dc1af36..7f1611f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -555,6 +555,7 @@
mControlsButton.setImageResource(mControlsComponent.getTileImageId());
mControlsButton.setContentDescription(getContext()
.getString(mControlsComponent.getTileTitleId()));
+ updateAffordanceColors();
boolean hasFavorites = mControlsComponent.getControlsController()
.map(c -> c.getFavorites().size() > 0)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index cc8a703..cbdf5c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -18,13 +18,9 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.view.View.GONE;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static androidx.constraintlayout.widget.ConstraintSet.BOTTOM;
import static androidx.constraintlayout.widget.ConstraintSet.END;
import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
-import static androidx.constraintlayout.widget.ConstraintSet.START;
-import static androidx.constraintlayout.widget.ConstraintSet.TOP;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
@@ -620,6 +616,11 @@
*/
private float mKeyguardOnlyContentAlpha = 1.0f;
+ /**
+ * The translationY of the views which only show on the keyguard but in shade / shade locked.
+ */
+ private int mKeyguardOnlyTransitionTranslationY = 0;
+
private float mUdfpsMaxYBurnInOffset;
/**
@@ -1080,14 +1081,10 @@
public void updateResources() {
mQuickQsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mView.getContext());
- mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
mSplitShadeNotificationsScrimMarginBottom =
mResources.getDimensionPixelSize(
R.dimen.split_shade_notifications_scrim_margin_bottom);
- int panelMarginHorizontal = mResources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_horizontal);
-
final boolean newShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mResources);
final boolean splitNotificationShadeChanged =
@@ -1097,49 +1094,12 @@
if (mQs != null) {
mQs.setInSplitShade(mShouldUseSplitNotificationShade);
}
-
- int notificationsBottomMargin = mResources.getDimensionPixelSize(
- R.dimen.notification_panel_margin_bottom);
+ mSplitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(mView.getContext());
int topMargin = mShouldUseSplitNotificationShade ? mSplitShadeStatusBarHeight :
mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top);
mSplitShadeHeaderController.setSplitShadeMode(mShouldUseSplitNotificationShade);
-
- // To change the constraints at runtime, all children of the ConstraintLayout must have ids
- ensureAllViewsHaveIds(mNotificationContainerParent);
- ConstraintSet constraintSet = new ConstraintSet();
- constraintSet.clone(mNotificationContainerParent);
- int statusViewMarginHorizontal = mResources.getDimensionPixelSize(
- R.dimen.status_view_margin_horizontal);
- constraintSet.setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal);
- constraintSet.setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal);
- if (mShouldUseSplitNotificationShade) {
- // width = 0 to take up all available space within constraints
- constraintSet.connect(R.id.qs_frame, END, R.id.qs_edge_guideline, END);
- constraintSet.connect(
- R.id.notification_stack_scroller, START,
- R.id.qs_edge_guideline, START);
- constraintSet.constrainHeight(R.id.split_shade_status_bar, mSplitShadeStatusBarHeight);
- } else {
- constraintSet.connect(R.id.qs_frame, END, PARENT_ID, END);
- constraintSet.connect(R.id.notification_stack_scroller, START, PARENT_ID, START);
- if (mUseCombinedQSHeaders) {
- constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT);
- }
- }
- constraintSet.setMargin(R.id.notification_stack_scroller, START,
- mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal);
- constraintSet.setMargin(R.id.notification_stack_scroller, END, panelMarginHorizontal);
- constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
- constraintSet.setMargin(R.id.notification_stack_scroller, BOTTOM,
- notificationsBottomMargin);
- constraintSet.setMargin(R.id.qs_frame, START, panelMarginHorizontal);
- constraintSet.setMargin(R.id.qs_frame, END,
- mShouldUseSplitNotificationShade ? 0 : panelMarginHorizontal);
- constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
- constraintSet.applyTo(mNotificationContainerParent);
mAmbientState.setStackTopMargin(topMargin);
- mNotificationsQSContainerController.updateMargins();
- mNotificationsQSContainerController.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
+ mNotificationsQSContainerController.updateResources();
updateKeyguardStatusViewAlignment(/* animate= */false);
@@ -1150,15 +1110,6 @@
}
}
- private static void ensureAllViewsHaveIds(ViewGroup parentView) {
- for (int i = 0; i < parentView.getChildCount(); i++) {
- View childView = parentView.getChildAt(i);
- if (childView.getId() == View.NO_ID) {
- childView.setId(View.generateViewId());
- }
- }
- }
-
private View reInflateStub(int viewId, int stubId, int layoutId, boolean enabled) {
View view = mView.findViewById(viewId);
if (view != null) {
@@ -1629,6 +1580,8 @@
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
+ mKeyguardStatusViewController
+ .setTranslationYExcludingMedia(mKeyguardOnlyTransitionTranslationY);
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setAlpha(alpha);
}
@@ -2786,11 +2739,12 @@
}
/**
- * Set the alpha of the keyguard elements which only show on the lockscreen, but not in
- * shade locked / shade. This is used when dragging down to the full shade.
+ * Set the alpha and translationY of the keyguard elements which only show on the lockscreen,
+ * but not in shade locked / shade. This is used when dragging down to the full shade.
*/
- public void setKeyguardOnlyContentAlpha(float keyguardAlpha) {
+ public void setKeyguardTransitionProgress(float keyguardAlpha, int keyguardTranslationY) {
mKeyguardOnlyContentAlpha = Interpolators.ALPHA_IN.getInterpolation(keyguardAlpha);
+ mKeyguardOnlyTransitionTranslationY = keyguardTranslationY;
if (mBarState == KEYGUARD) {
// If the animator is running, it's already fading out the content and this is a reset
mBottomAreaShadeAlpha = mKeyguardOnlyContentAlpha;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index ebb09b1..7764d338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -1,6 +1,15 @@
package com.android.systemui.statusbar.phone
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowInsets
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
import com.android.systemui.R
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
@@ -10,6 +19,7 @@
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
import com.android.systemui.shared.system.QuickStepContract
+import com.android.systemui.util.Utils
import com.android.systemui.util.ViewController
import java.util.function.Consumer
import javax.inject.Inject
@@ -28,23 +38,20 @@
mView.invalidate()
}
}
- var splitShadeEnabled = false
- set(value) {
- if (field != value) {
- field = value
- // in case device configuration changed while showing QS details/customizer
- updateBottomSpacing()
- }
- }
-
+ private var splitShadeEnabled = false
private var isQSDetailShowing = false
private var isQSCustomizing = false
private var isQSCustomizerAnimating = false
+ private var splitShadeStatusBarHeight = 0
private var notificationsBottomMargin = 0
private var scrimShadeBottomMargin = 0
private var bottomStableInsets = 0
private var bottomCutoutInsets = 0
+ private var panelMarginHorizontal = 0
+ private var topMargin = 0
+
+ private val useCombinedQSHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
private var isGestureNavigation = true
private var taskbarVisible = false
@@ -68,7 +75,6 @@
}
public override fun onViewAttached() {
- updateMargins()
updateResources()
overviewProxyService.addCallback(taskbarVisibilityListener)
mView.setInsetsChangedListener(windowInsetsListener)
@@ -83,7 +89,27 @@
mView.setConfigurationChangedListener(null)
}
- private fun updateResources() {
+ fun updateResources() {
+ val newSplitShadeEnabled = Utils.shouldUseSplitNotificationShade(resources)
+ val splitShadeEnabledChanged = newSplitShadeEnabled != splitShadeEnabled
+ splitShadeEnabled = newSplitShadeEnabled
+ notificationsBottomMargin = resources.getDimensionPixelSize(
+ R.dimen.notification_panel_margin_bottom)
+ splitShadeStatusBarHeight = Utils.getSplitShadeStatusBarHeight(context)
+ panelMarginHorizontal = resources.getDimensionPixelSize(
+ R.dimen.notification_panel_margin_horizontal)
+ topMargin = if (splitShadeEnabled) {
+ splitShadeStatusBarHeight
+ } else {
+ resources.getDimensionPixelSize(R.dimen.notification_panel_margin_top)
+ }
+ updateConstraints()
+ if (splitShadeEnabledChanged) {
+ // Let's do it at the end when all margins/paddings were already applied.
+ // We need to updateBottomSpacing() in case device configuration changed while showing
+ // QS details/customizer
+ updateBottomSpacing()
+ }
val previousScrimShadeBottomMargin = scrimShadeBottomMargin
scrimShadeBottomMargin = resources.getDimensionPixelSize(
R.dimen.split_shade_notifications_scrim_margin_bottom
@@ -94,15 +120,6 @@
}
}
- /**
- * Update the notification bottom margin.
- *
- * Will not call updateBottomSpacing
- */
- fun updateMargins() {
- notificationsBottomMargin = mView.defaultNotificationsMarginBottom
- }
-
override fun setCustomizerAnimating(animating: Boolean) {
if (isQSCustomizerAnimating != animating) {
isQSCustomizerAnimating = animating
@@ -178,4 +195,66 @@
}
return containerPadding to stackScrollMargin
}
-}
\ No newline at end of file
+
+ fun updateConstraints() {
+ // To change the constraints at runtime, all children of the ConstraintLayout must have ids
+ ensureAllViewsHaveIds(mView)
+ val constraintSet = ConstraintSet()
+ constraintSet.clone(mView)
+ setKeyguardStatusViewConstraints(constraintSet)
+ setQsConstraints(constraintSet)
+ setNotificationsConstraints(constraintSet)
+ setSplitShadeStatusBarConstraints(constraintSet)
+ mView.applyConstraints(constraintSet)
+ }
+
+ private fun setSplitShadeStatusBarConstraints(constraintSet: ConstraintSet) {
+ if (splitShadeEnabled) {
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, splitShadeStatusBarHeight)
+ } else {
+ if (useCombinedQSHeaders) {
+ constraintSet.constrainHeight(R.id.split_shade_status_bar, WRAP_CONTENT)
+ }
+ }
+ }
+
+ private fun setNotificationsConstraints(constraintSet: ConstraintSet) {
+ val startConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
+ constraintSet.apply {
+ connect(R.id.notification_stack_scroller, START, startConstraintId, START)
+ setMargin(R.id.notification_stack_scroller, START,
+ if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.notification_stack_scroller, END, panelMarginHorizontal)
+ setMargin(R.id.notification_stack_scroller, TOP, topMargin)
+ setMargin(R.id.notification_stack_scroller, BOTTOM, notificationsBottomMargin)
+ }
+ }
+
+ private fun setQsConstraints(constraintSet: ConstraintSet) {
+ val endConstraintId = if (splitShadeEnabled) R.id.qs_edge_guideline else PARENT_ID
+ constraintSet.apply {
+ connect(R.id.qs_frame, END, endConstraintId, END)
+ setMargin(R.id.qs_frame, START, if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.qs_frame, END, if (splitShadeEnabled) 0 else panelMarginHorizontal)
+ setMargin(R.id.qs_frame, TOP, topMargin)
+ }
+ }
+
+ private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) {
+ val statusViewMarginHorizontal = resources.getDimensionPixelSize(
+ R.dimen.status_view_margin_horizontal)
+ constraintSet.apply {
+ setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal)
+ setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal)
+ }
+ }
+
+ private fun ensureAllViewsHaveIds(parentView: ViewGroup) {
+ for (i in 0 until parentView.childCount) {
+ val childView = parentView.getChildAt(i)
+ if (childView.id == View.NO_ID) {
+ childView.id = View.generateViewId()
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index c2b5f56..7caea06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -26,6 +26,7 @@
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.constraintlayout.widget.ConstraintSet;
import com.android.systemui.R;
import com.android.systemui.fragments.FragmentHostManager;
@@ -123,10 +124,6 @@
}
}
- public int getDefaultNotificationsMarginBottom() {
- return ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
- }
-
public void setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener) {
mInsetsChangedListener = onInsetsChangedListener;
}
@@ -197,4 +194,7 @@
}
}
+ public void applyConstraints(ConstraintSet constraintSet) {
+ constraintSet.applyTo(this);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index a3c795f..419661b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -773,7 +773,7 @@
}
if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
// We're unoccluding the keyguard and don't want to have a bright flash.
- mNotificationsAlpha = mScrimBehindAlphaKeyguard;
+ mNotificationsAlpha = ScrimState.KEYGUARD.getNotifAlpha();
mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index ad47e2b..01fe865 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.annotation.WorkerThread;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -219,6 +220,7 @@
new CameraManager.TorchCallback() {
@Override
+ @WorkerThread
public void onTorchModeUnavailable(String cameraId) {
if (TextUtils.equals(cameraId, mCameraId)) {
setCameraAvailable(false);
@@ -229,6 +231,7 @@
}
@Override
+ @WorkerThread
public void onTorchModeChanged(String cameraId, boolean enabled) {
if (TextUtils.equals(cameraId, mCameraId)) {
setCameraAvailable(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index fa26a35..763f041 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -67,6 +67,7 @@
import com.android.systemui.SystemUISecondaryUserService;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -122,6 +123,7 @@
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final BroadcastSender mBroadcastSender;
private final TelephonyListenerManager mTelephonyListenerManager;
private final InteractionJankMonitor mInteractionJankMonitor;
private final LatencyTracker mLatencyTracker;
@@ -165,6 +167,7 @@
@Main Handler handler,
ActivityStarter activityStarter,
BroadcastDispatcher broadcastDispatcher,
+ BroadcastSender broadcastSender,
UiEventLogger uiEventLogger,
FalsingManager falsingManager,
TelephonyListenerManager telephonyListenerManager,
@@ -179,6 +182,7 @@
mActivityManager = activityManager;
mUserTracker = userTracker;
mBroadcastDispatcher = broadcastDispatcher;
+ mBroadcastSender = broadcastSender;
mTelephonyListenerManager = telephonyListenerManager;
mUiEventLogger = uiEventLogger;
mFalsingManager = falsingManager;
@@ -1194,7 +1198,7 @@
}
// Use broadcast instead of ShadeController, as this dialog may have started in
// another process and normal dagger bindings are not available
- getContext().sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ mBroadcastSender.closeSystemDialogs();
getContext().startActivityAsUser(
CreateUserActivity.createIntentForStart(getContext()),
mUserTracker.getUserHandle());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 2fc9122..1753157 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -112,4 +112,13 @@
mKeyguardUpdateMonitorCallbackCaptor.getValue().onUserSwitchComplete(0);
verify(mKeyguardClockSwitchController).refreshFormat();
}
+
+ @Test
+ public void setTranslationYExcludingMedia_forwardsCallToView() {
+ float translationY = 123f;
+
+ mController.setTranslationYExcludingMedia(translationY);
+
+ verify(mKeyguardStatusView).setChildrenTranslationYExcludingMediaView(translationY);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
new file mode 100644
index 0000000..ce44f4d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
@@ -0,0 +1,55 @@
+package com.android.keyguard
+
+import android.test.suitebuilder.annotation.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.children
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class KeyguardStatusViewTest : SysuiTestCase() {
+
+ private lateinit var keyguardStatusView: KeyguardStatusView
+ private val mediaView: View
+ get() = keyguardStatusView.findViewById(R.id.status_view_media_container)
+ private val statusViewContainer: ViewGroup
+ get() = keyguardStatusView.findViewById(R.id.status_view_container)
+ private val childrenExcludingMedia
+ get() = statusViewContainer.children.filter { it != mediaView }
+
+ @Before
+ fun setUp() {
+ keyguardStatusView = LayoutInflater.from(context)
+ .inflate(R.layout.keyguard_status_view, /* root= */ null) as KeyguardStatusView
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_mediaViewIsNotTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ assertThat(mediaView.translationY).isEqualTo(0)
+ }
+
+ @Test
+ fun setChildrenTranslationYExcludingMediaView_childrenAreTranslated() {
+ val translationY = 1234f
+
+ keyguardStatusView.setChildrenTranslationYExcludingMediaView(translationY)
+
+ childrenExcludingMedia.forEach {
+ assertThat(it.translationY).isEqualTo(translationY)
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt
new file mode 100644
index 0000000..214fd4d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewBoundAnimatorTest.kt
@@ -0,0 +1,277 @@
+package com.android.systemui.animation
+
+import android.animation.ObjectAnimator
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertNotNull
+import junit.framework.Assert.assertNull
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ViewBoundAnimatorTest : SysuiTestCase() {
+ companion object {
+ private const val TEST_DURATION = 1000L
+ private val TEST_INTERPOLATOR = Interpolators.LINEAR
+ }
+
+ private lateinit var rootView: LinearLayout
+
+ @Before
+ fun setUp() {
+ rootView = LinearLayout(mContext)
+ }
+
+ @After
+ fun tearDown() {
+ ViewBoundAnimator.stopAnimating(rootView)
+ }
+
+ @Test
+ fun respectsAnimationParameters() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(
+ rootView, interpolator = TEST_INTERPOLATOR, duration = TEST_DURATION
+ )
+ rootView.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ val animator = rootView.getTag(R.id.tag_animator) as ObjectAnimator
+ assertEquals(animator.interpolator, TEST_INTERPOLATOR)
+ assertEquals(animator.duration, TEST_DURATION)
+ }
+
+ @Test
+ fun animatesFromStartToEnd() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ // The initial values should be those of the previous layout.
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ // The end values should be those of the latest layout.
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+ }
+
+ @Test
+ fun animatesSuccessiveLayoutChanges() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ // Change only top and right.
+ rootView.layout(0 /* l */, 20 /* t */, 60 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 60, b = 80)
+
+ // Change all bounds again.
+ rootView.layout(5 /* l */, 25 /* t */, 55 /* r */, 95 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 5, t = 25, r = 55, b = 95)
+ }
+
+ @Test
+ fun animatesFromPreviousAnimationProgress() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animateNextUpdate(rootView, interpolator = TEST_INTERPOLATOR)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ advanceAnimation(rootView, fraction = 0.5f)
+ checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+
+ // Change all bounds again.
+ rootView.layout(25 /* l */, 25 /* t */, 55 /* r */, 60 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 5, t = 15, r = 60, b = 65)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 25, t = 25, r = 55, b = 60)
+ }
+
+ @Test
+ fun animatesRootAndChildren() {
+ val firstChild = View(mContext)
+ rootView.addView(firstChild)
+ val secondChild = View(mContext)
+ rootView.addView(secondChild)
+ rootView.layout(0 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
+ firstChild.layout(0 /* l */, 0 /* t */, 100 /* r */, 100 /* b */)
+ secondChild.layout(100 /* l */, 0 /* t */, 150 /* r */, 100 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(10 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+ firstChild.layout(10 /* l */, 20 /* t */, 150 /* r */, 120 /* b */)
+ secondChild.layout(150 /* l */, 20 /* t */, 200 /* r */, 120 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ // The initial values should be those of the previous layout.
+ checkBounds(rootView, l = 0, t = 0, r = 150, b = 100)
+ checkBounds(firstChild, l = 0, t = 0, r = 100, b = 100)
+ checkBounds(secondChild, l = 100, t = 0, r = 150, b = 100)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ // The end values should be those of the latest layout.
+ checkBounds(rootView, l = 10, t = 20, r = 200, b = 120)
+ checkBounds(firstChild, l = 10, t = 20, r = 150, b = 120)
+ checkBounds(secondChild, l = 150, t = 20, r = 200, b = 120)
+ }
+
+ @Test
+ fun doesNotAnimateInvisibleViews() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // GONE.
+ rootView.visibility = View.GONE
+ rootView.layout(0 /* l */, 15 /* t */, 55 /* r */, 80 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 55, b = 80)
+
+ // INVISIBLE.
+ rootView.visibility = View.INVISIBLE
+ rootView.layout(0 /* l */, 20 /* t */, 0 /* r */, 20 /* b */)
+ }
+
+ @Test
+ fun doesNotAnimateUnchangingBounds() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // No bounds are changed.
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+
+ // Change only right and bottom.
+ rootView.layout(10 /* l */, 10 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 70, b = 80)
+ }
+
+ @Test
+ fun doesNotAnimateExcludedBounds() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(
+ rootView,
+ bounds = setOf(ViewBoundAnimator.Bound.LEFT, ViewBoundAnimator.Bound.TOP),
+ interpolator = TEST_INTERPOLATOR
+ )
+ // Change all bounds.
+ rootView.layout(0 /* l */, 20 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ advanceAnimation(rootView, 0.5f)
+ checkBounds(rootView, l = 5, t = 15, r = 70, b = 80)
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 20, r = 70, b = 80)
+ }
+
+ @Test
+ fun stopsAnimatingAfterSingleLayout() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animateNextUpdate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ // Change all bounds again.
+ rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+ }
+
+ @Test
+ fun stopsAnimatingWhenInstructed() {
+ rootView.layout(10 /* l */, 10 /* t */, 50 /* r */, 50 /* b */)
+
+ ViewBoundAnimator.animate(rootView)
+ // Change all bounds.
+ rootView.layout(0 /* l */, 15 /* t */, 70 /* r */, 80 /* b */)
+
+ assertNotNull(rootView.getTag(R.id.tag_animator))
+ endAnimation(rootView)
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 0, t = 15, r = 70, b = 80)
+
+ ViewBoundAnimator.stopAnimating(rootView)
+ // Change all bounds again.
+ rootView.layout(10 /* l */, 10 /* t */, 50/* r */, 50 /* b */)
+
+ assertNull(rootView.getTag(R.id.tag_animator))
+ checkBounds(rootView, l = 10, t = 10, r = 50, b = 50)
+ }
+
+ private fun checkBounds(v: View, l: Int, t: Int, r: Int, b: Int) {
+ assertEquals(l, v.left)
+ assertEquals(t, v.top)
+ assertEquals(r, v.right)
+ assertEquals(b, v.bottom)
+ }
+
+ private fun advanceAnimation(rootView: View, fraction: Float) {
+ (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.setCurrentFraction(fraction)
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ advanceAnimation(rootView.getChildAt(i), fraction)
+ }
+ }
+ }
+
+ private fun endAnimation(rootView: View) {
+ (rootView.getTag(R.id.tag_animator) as? ObjectAnimator)?.end()
+
+ if (rootView is ViewGroup) {
+ for (i in 0 until rootView.childCount) {
+ endAnimation(rootView.getChildAt(i))
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
new file mode 100644
index 0000000..fbd2c91
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 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.broadcast
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.systemui.util.wakelock.WakeLockFake
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class BroadcastSenderTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var mockContext: Context
+
+ private lateinit var broadcastSender: BroadcastSender
+ private lateinit var executor: FakeExecutor
+ private lateinit var wakeLock: WakeLockFake
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+ wakeLock = WakeLockFake()
+ val wakeLockBuilder = WakeLockFake.Builder(mContext)
+ wakeLockBuilder.setWakeLock(wakeLock)
+ broadcastSender = BroadcastSender(mockContext, wakeLockBuilder, executor)
+ }
+
+ @Test
+ fun sendBroadcast_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ broadcastSender.sendBroadcast(intent)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intent)
+ }
+ }
+
+ @Test
+ fun sendBroadcastWithPermission_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ broadcastSender.sendBroadcast(intent, permission)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intent, permission)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUser_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermission_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermissionAndOptions_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+ val options = Bundle()
+ options.putString("key", "value")
+
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission, options)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission, options)
+ }
+ }
+
+ @Test
+ fun sendBroadcastAsUserWithPermissionAndAppOp_dispatchesWithWakelock() {
+ val intent = Intent(Intent.ACTION_VIEW)
+ val permission = "Permission"
+
+ broadcastSender.sendBroadcastAsUser(intent, UserHandle.ALL, permission, 12)
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcastAsUser(intent, UserHandle.ALL, permission, 12)
+ }
+ }
+
+ @Test
+ fun sendCloseSystemDialogs_dispatchesWithWakelock() {
+ val intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+
+ broadcastSender.closeSystemDialogs()
+
+ runExecutorAssertingWakelock {
+ verify(mockContext).sendBroadcast(intentCaptor.capture())
+ assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ }
+ }
+
+ private fun runExecutorAssertingWakelock(verification: () -> Unit) {
+ assertThat(wakeLock.isHeld).isTrue()
+ executor.runAllReady()
+ verification.invoke()
+ assertThat(wakeLock.isHeld).isFalse()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index da25c62..49eaf823 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -23,6 +23,7 @@
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.controls.ControlsMetricsLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.VibratorHelper
@@ -62,6 +63,8 @@
@Mock
private lateinit var activityStarter: ActivityStarter
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var taskViewFactory: Optional<TaskViewFactory>
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private lateinit var cvh: ControlViewHolder
@@ -94,6 +97,7 @@
bgExecutor,
uiExecutor,
activityStarter,
+ broadcastSender,
keyguardStateController,
taskViewFactory,
metricsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
index 87b9172..0166fa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
@@ -21,6 +21,7 @@
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.wm.shell.TaskView
import org.junit.Before
import org.junit.Test
@@ -39,6 +40,8 @@
@Mock
private lateinit var taskView: TaskView
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var controlViewHolder: ControlViewHolder
@Mock
private lateinit var pendingIntent: PendingIntent
@@ -63,6 +66,7 @@
private fun createDialog(pendingIntent: PendingIntent): DetailDialog {
return DetailDialog(
mContext,
+ broadcastSender,
taskView,
pendingIntent,
controlViewHolder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index ff9e13a..dcbdea0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.dreams;
-import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@@ -30,7 +29,6 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dreams.complication.ComplicationHostViewController;
@@ -44,7 +42,6 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
- private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
private static final int MAX_BURN_IN_OFFSET = 20;
private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
private static final long MILLIS_UNTIL_FULL_JITTER = 240 * 1000;
@@ -76,9 +73,6 @@
public void setup() {
MockitoAnnotations.initMocks(this);
- when(mResources.getDimensionPixelSize(
- R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
- DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
@@ -100,13 +94,6 @@
}
@Test
- public void testSetsDreamOverlayNotificationsDragAreaHeight() {
- assertEquals(
- mController.getDreamOverlayNotificationsDragAreaHeight(),
- DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
- }
-
- @Test
public void testBurnInProtectionStartsWhenContentViewAttached() {
mController.onViewAttached();
verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 7d7ccb4..3657192 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -174,19 +174,19 @@
}
@Test
- public void testShouldShowComplicationsTrueByDefault() {
+ public void testShouldShowComplicationsFalseByDefault() {
mService.onBind(new Intent());
- assertThat(mService.shouldShowComplications()).isTrue();
+ assertThat(mService.shouldShowComplications()).isFalse();
}
@Test
public void testShouldShowComplicationsSetByIntentExtra() {
final Intent intent = new Intent();
- intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, false);
+ intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, true);
mService.onBind(intent);
- assertThat(mService.shouldShowComplications()).isFalse();
+ assertThat(mService.shouldShowComplications()).isTrue();
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 49da4bd..3ce9889 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -158,6 +158,7 @@
public void testComplicationFilteringWhenShouldShowComplications() {
final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor);
+ stateController.setShouldShowComplications(true);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
final Complication weatherComplication = Mockito.mock(Complication.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 708fc91..cb68d81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -40,6 +40,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -59,6 +60,7 @@
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -85,6 +87,7 @@
private lateinit var bgExecutor: FakeExecutor
@Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var broadcastSender: BroadcastSender
@Mock private lateinit var holder: PlayerViewHolder
@Mock private lateinit var sessionHolder: PlayerSessionViewHolder
@@ -119,8 +122,6 @@
private lateinit var actionPlayPause: ImageButton
private lateinit var actionNext: ImageButton
private lateinit var actionPrev: ImageButton
- private lateinit var actionStart: ImageButton
- private lateinit var actionEnd: ImageButton
@Mock private lateinit var longPressText: TextView
@Mock private lateinit var handler: Handler
private lateinit var settings: View
@@ -144,8 +145,8 @@
whenever(mediaViewController.expandedLayout).thenReturn(expandedSet)
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
- player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel, Lazy { mediaDataManager },
+ player = MediaControlPanel(context, bgExecutor, activityStarter, broadcastSender,
+ mediaViewController, seekBarViewModel, Lazy { mediaDataManager },
mediaOutputDialogFactory, mediaCarouselController, falsingManager, mediaFlags, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
@@ -168,6 +169,17 @@
cancelText = TextView(context)
dismiss = FrameLayout(context)
dismissText = TextView(context)
+
+ action0 = ImageButton(context).also { it.setId(R.id.action0) }
+ action1 = ImageButton(context).also { it.setId(R.id.action1) }
+ action2 = ImageButton(context).also { it.setId(R.id.action2) }
+ action3 = ImageButton(context).also { it.setId(R.id.action3) }
+ action4 = ImageButton(context).also { it.setId(R.id.action4) }
+
+ actionPlayPause = ImageButton(context).also { it.setId(R.id.actionPlayPause) }
+ actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) }
+ actionNext = ImageButton(context).also { it.setId(R.id.actionNext) }
+
initPlayerHolderMocks()
initSessionHolderMocks()
@@ -208,90 +220,64 @@
whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
- /** Mock view holder for the notification player */
- private fun initPlayerHolderMocks() {
- whenever(holder.player).thenReturn(view)
- whenever(holder.appIcon).thenReturn(appIcon)
- whenever(holder.albumView).thenReturn(albumView)
- whenever(holder.titleText).thenReturn(titleText)
- whenever(holder.artistText).thenReturn(artistText)
+ /**
+ * Initialize elements common to both view holders
+ */
+ private fun initMediaViewHolderMocks(viewHolder: MediaViewHolder) {
+ whenever(viewHolder.player).thenReturn(view)
+ whenever(viewHolder.appIcon).thenReturn(appIcon)
+ whenever(viewHolder.albumView).thenReturn(albumView)
+ whenever(viewHolder.titleText).thenReturn(titleText)
+ whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(holder.seamless).thenReturn(seamless)
- whenever(holder.seamlessButton).thenReturn(seamlessButton)
- whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(holder.seamlessText).thenReturn(seamlessText)
- whenever(holder.seekBar).thenReturn(seekBar)
- whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
- whenever(holder.totalTimeView).thenReturn(totalTimeView)
+ whenever(viewHolder.seamless).thenReturn(seamless)
+ whenever(viewHolder.seamlessButton).thenReturn(seamlessButton)
+ whenever(viewHolder.seamlessIcon).thenReturn(seamlessIcon)
+ whenever(viewHolder.seamlessText).thenReturn(seamlessText)
+ whenever(viewHolder.seekBar).thenReturn(seekBar)
// Action buttons
- action0 = ImageButton(context)
- whenever(holder.action0).thenReturn(action0)
- whenever(holder.getAction(R.id.action0)).thenReturn(action0)
- action1 = ImageButton(context)
- whenever(holder.action1).thenReturn(action1)
- whenever(holder.getAction(R.id.action1)).thenReturn(action1)
- action2 = ImageButton(context)
- whenever(holder.action2).thenReturn(action2)
- whenever(holder.getAction(R.id.action2)).thenReturn(action2)
- action3 = ImageButton(context)
- whenever(holder.action3).thenReturn(action3)
- whenever(holder.getAction(R.id.action3)).thenReturn(action3)
- action4 = ImageButton(context)
- whenever(holder.action4).thenReturn(action4)
- whenever(holder.getAction(R.id.action4)).thenReturn(action4)
+ whenever(viewHolder.action0).thenReturn(action0)
+ whenever(viewHolder.getAction(R.id.action0)).thenReturn(action0)
+ whenever(viewHolder.action1).thenReturn(action1)
+ whenever(viewHolder.getAction(R.id.action1)).thenReturn(action1)
+ whenever(viewHolder.action2).thenReturn(action2)
+ whenever(viewHolder.getAction(R.id.action2)).thenReturn(action2)
+ whenever(viewHolder.action3).thenReturn(action3)
+ whenever(viewHolder.getAction(R.id.action3)).thenReturn(action3)
+ whenever(viewHolder.action4).thenReturn(action4)
+ whenever(viewHolder.getAction(R.id.action4)).thenReturn(action4)
// Long press menu
- whenever(holder.longPressText).thenReturn(longPressText)
+ whenever(viewHolder.longPressText).thenReturn(longPressText)
whenever(longPressText.handler).thenReturn(handler)
- whenever(holder.settings).thenReturn(settings)
- whenever(holder.settingsText).thenReturn(settingsText)
- whenever(holder.cancel).thenReturn(cancel)
- whenever(holder.cancelText).thenReturn(cancelText)
- whenever(holder.dismiss).thenReturn(dismiss)
- whenever(holder.dismissText).thenReturn(dismissText)
+ whenever(viewHolder.settings).thenReturn(settings)
+ whenever(viewHolder.settingsText).thenReturn(settingsText)
+ whenever(viewHolder.cancel).thenReturn(cancel)
+ whenever(viewHolder.cancelText).thenReturn(cancelText)
+ whenever(viewHolder.dismiss).thenReturn(dismiss)
+ whenever(viewHolder.dismissText).thenReturn(dismissText)
+ }
+
+ /** Mock view holder for the notification player */
+ private fun initPlayerHolderMocks() {
+ initMediaViewHolderMocks(holder)
+
+ whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+ whenever(holder.totalTimeView).thenReturn(totalTimeView)
}
/** Mock view holder for session player */
private fun initSessionHolderMocks() {
- whenever(sessionHolder.player).thenReturn(view)
- whenever(sessionHolder.albumView).thenReturn(albumView)
- whenever(sessionHolder.appIcon).thenReturn(appIcon)
- whenever(sessionHolder.titleText).thenReturn(titleText)
- whenever(sessionHolder.artistText).thenReturn(artistText)
- val seamlessBackground = mock(RippleDrawable::class.java)
- whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(sessionHolder.seamless).thenReturn(seamless)
- whenever(sessionHolder.seamlessButton).thenReturn(seamlessButton)
- whenever(sessionHolder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(sessionHolder.seamlessText).thenReturn(seamlessText)
- whenever(sessionHolder.seekBar).thenReturn(seekBar)
+ initMediaViewHolderMocks(sessionHolder)
- // Action buttons
- actionPlayPause = ImageButton(context)
+ // Semantic action buttons
whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
- actionNext = ImageButton(context)
whenever(sessionHolder.actionNext).thenReturn(actionNext)
whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
- actionPrev = ImageButton(context)
whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
- actionStart = ImageButton(context)
- whenever(sessionHolder.actionStart).thenReturn(actionStart)
- whenever(sessionHolder.getAction(R.id.actionStart)).thenReturn(actionStart)
- actionEnd = ImageButton(context)
- whenever(sessionHolder.actionEnd).thenReturn(actionEnd)
- whenever(sessionHolder.getAction(R.id.actionEnd)).thenReturn(actionEnd)
-
- // Long press menu
- whenever(sessionHolder.longPressText).thenReturn(longPressText)
- whenever(sessionHolder.settings).thenReturn(settings)
- whenever(sessionHolder.settingsText).thenReturn(settingsText)
- whenever(sessionHolder.cancel).thenReturn(cancel)
- whenever(sessionHolder.cancelText).thenReturn(cancelText)
- whenever(sessionHolder.dismiss).thenReturn(dismiss)
- whenever(sessionHolder.dismissText).thenReturn(dismissText)
}
@After
@@ -316,8 +302,8 @@
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
@@ -325,7 +311,7 @@
player.bindPlayer(state, PACKAGE)
verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
- assertThat(action0.contentDescription).isEqualTo("custom 1")
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
assertThat(action0.isEnabled()).isFalse()
verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
@@ -340,7 +326,7 @@
assertThat(action3.contentDescription).isEqualTo("next")
verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
- assertThat(action4.contentDescription).isEqualTo("custom 2")
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
assertThat(action4.isEnabled()).isFalse()
}
@@ -353,28 +339,96 @@
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
player.bindPlayer(state, PACKAGE)
- assertThat(actionStart.contentDescription).isEqualTo("custom 1")
- assertThat(actionStart.isEnabled()).isFalse()
-
assertThat(actionPrev.isEnabled()).isFalse()
assertThat(actionPrev.drawable).isNull()
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
assertThat(actionPlayPause.isEnabled()).isTrue()
assertThat(actionPlayPause.contentDescription).isEqualTo("play")
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE)
assertThat(actionNext.isEnabled()).isTrue()
assertThat(actionNext.contentDescription).isEqualTo("next")
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.VISIBLE)
- assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
- assertThat(actionEnd.isEnabled()).isFalse()
+ // Called twice since these IDs are used as generic buttons
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
+ assertThat(action0.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("custom 1")
+ assertThat(action1.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action1, ConstraintSet.GONE)
+
+ // Verify generic buttons are hidden
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ }
+
+ @Test
+ fun bindNotificationActionsNewLayout() {
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+ val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
+ val actions = listOf(
+ MediaAction(icon, Runnable {}, "previous"),
+ MediaAction(icon, Runnable {}, "play"),
+ MediaAction(icon, null, "next"),
+ MediaAction(icon, null, "custom 0"),
+ MediaAction(icon, Runnable {}, "custom 1")
+ )
+ val state = mediaData.copy(actions = actions,
+ actionsToShowInCompact = listOf(1, 2),
+ semanticActions = null)
+
+ player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
+ player.bindPlayer(state, PACKAGE)
+
+ // Verify semantic actions are hidden
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+
+ // Generic actions all enabled
+ assertThat(action0.contentDescription).isEqualTo("previous")
+ assertThat(action0.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("play")
+ assertThat(action1.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action1, ConstraintSet.VISIBLE)
+
+ assertThat(action2.contentDescription).isEqualTo("next")
+ assertThat(action2.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
+
+ assertThat(action3.contentDescription).isEqualTo("custom 0")
+ assertThat(action3.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
+ assertThat(action4.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
index 6b203bc..82a48ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -23,6 +23,7 @@
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -65,6 +66,8 @@
@Mock
private lateinit var broadcastDispatcher: BroadcastDispatcher
@Mock
+ private lateinit var broadcastSender: BroadcastSender
+ @Mock
private lateinit var mediaResumeListener: MediaResumeListener
@Mock
private lateinit var mediaDataManager: MediaDataManager
@@ -87,7 +90,7 @@
fun setup() {
MockitoAnnotations.initMocks(this)
MediaPlayerData.clear()
- mediaDataFilter = MediaDataFilter(context, broadcastDispatcher,
+ mediaDataFilter = MediaDataFilter(context, broadcastDispatcher, broadcastSender,
lockscreenUserManager, executor, clock)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 021f70e..925ae30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -659,11 +659,11 @@
actions.nextOrCustom!!.action!!.run()
verify(transportControls).skipToNext()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
@Test
@@ -697,11 +697,11 @@
assertThat(actions.nextOrCustom).isNotNull()
assertThat(actions.nextOrCustom!!.contentDescription).isEqualTo(customDesc[1])
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[2])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[2])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[3])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[3])
}
@Test
@@ -737,10 +737,10 @@
assertThat(actions.prevOrCustom).isNull()
assertThat(actions.nextOrCustom).isNull()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index b359ae5..8e201b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -117,9 +117,9 @@
dreamOverlayStateController)
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
- setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN)
- setupHost(qsHost, MediaHierarchyManager.LOCATION_QS)
- setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS)
+ setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
+ setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
+ setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
`when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
`when`(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
@@ -130,9 +130,9 @@
clearInvocations(mediaCarouselController)
}
- private fun setupHost(host: MediaHost, location: Int) {
+ private fun setupHost(host: MediaHost, location: Int, top: Int) {
`when`(host.location).thenReturn(location)
- `when`(host.currentBounds).thenReturn(Rect())
+ `when`(host.currentBounds).thenReturn(Rect(0, top, 0, top))
`when`(host.hostView).thenReturn(uniqueObjectHostView)
`when`(host.visible).thenReturn(true)
mediaHiearchyManager.register(host)
@@ -257,6 +257,20 @@
verify(mediaCarouselController).closeGuts()
}
+ @Test
+ fun getGuidedTransformationTranslationY_notInGuidedTransformation_returnsNegativeNumber() {
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY()).isLessThan(0)
+ }
+
+ @Test
+ fun getGuidedTransformationTranslationY_inGuidedTransformation_returnsCurrentTranslation() {
+ enterGuidedTransformation()
+
+ val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
+ assertThat(mediaHiearchyManager.getGuidedTransformationTranslationY())
+ .isEqualTo(expectedTranslation)
+ }
+
private fun enableSplitShade() {
context.getOrCreateTestableResources().addOverride(
R.bool.config_use_split_notification_shade, true
@@ -284,4 +298,16 @@
private fun expandQS() {
mediaHiearchyManager.qsExpansion = 1.0f
}
+
+ private fun enterGuidedTransformation() {
+ mediaHiearchyManager.qsExpansion = 1.0f
+ goToLockscreen()
+ mediaHiearchyManager.setTransitionToFullShadeAmount(123f)
+ }
+
+ companion object {
+ private const val QQS_TOP = 123
+ private const val QS_TOP = 456
+ private const val LOCKSCREEN_TOP = 789
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 3c2392a..7ac15125 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -26,29 +26,33 @@
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
-public class SeekBarObserverTest : SysuiTestCase() {
+class SeekBarObserverTest : SysuiTestCase() {
private val disabledHeight = 1
private val enabledHeight = 2
private lateinit var observer: SeekBarObserver
@Mock private lateinit var mockHolder: PlayerViewHolder
+ @Mock private lateinit var mockSquigglyProgress: SquigglyProgress
private lateinit var seekBarView: SeekBar
private lateinit var elapsedTimeView: TextView
private lateinit var totalTimeView: TextView
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
@Before
fun setUp() {
- mockHolder = mock(PlayerViewHolder::class.java)
context.orCreateTestableResources
.addOverride(R.dimen.qs_media_enabled_seekbar_height, enabledHeight)
@@ -56,6 +60,7 @@
.addOverride(R.dimen.qs_media_disabled_seekbar_height, disabledHeight)
seekBarView = SeekBar(context)
+ seekBarView.progressDrawable = mockSquigglyProgress
elapsedTimeView = TextView(context)
totalTimeView = TextView(context)
whenever(mockHolder.seekBar).thenReturn(seekBarView)
@@ -69,7 +74,7 @@
fun seekBarGone() {
// WHEN seek bar is disabled
val isEnabled = false
- val data = SeekBarViewModel.Progress(isEnabled, false, null, 0)
+ val data = SeekBarViewModel.Progress(isEnabled, false, false, null, 0)
observer.onChanged(data)
// THEN seek bar shows just a thin line with no text
assertThat(seekBarView.isEnabled()).isFalse()
@@ -84,7 +89,7 @@
fun seekBarVisible() {
// WHEN seek bar is enabled
val isEnabled = true
- val data = SeekBarViewModel.Progress(isEnabled, true, 3000, 12000)
+ val data = SeekBarViewModel.Progress(isEnabled, true, false, 3000, 12000)
observer.onChanged(data)
// THEN seek bar is visible and thick
assertThat(seekBarView.getVisibility()).isEqualTo(View.VISIBLE)
@@ -96,7 +101,7 @@
@Test
fun seekBarProgress() {
// WHEN part of the track has been played
- val data = SeekBarViewModel.Progress(true, true, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, true, true, 3000, 120000)
observer.onChanged(data)
// THEN seek bar shows the progress
assertThat(seekBarView.progress).isEqualTo(3000)
@@ -112,7 +117,7 @@
fun seekBarDisabledWhenSeekNotAvailable() {
// WHEN seek is not available
val isSeekAvailable = false
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isFalse()
@@ -122,9 +127,29 @@
fun seekBarEnabledWhenSeekNotAvailable() {
// WHEN seek is available
val isSeekAvailable = true
- val data = SeekBarViewModel.Progress(true, isSeekAvailable, 3000, 120000)
+ val data = SeekBarViewModel.Progress(true, isSeekAvailable, false, 3000, 120000)
observer.onChanged(data)
// THEN seek bar is not enabled
assertThat(seekBarView.isEnabled()).isTrue()
}
+
+ @Test
+ fun seekBarPlaying() {
+ // WHEN playing
+ val isPlaying = true
+ val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+ observer.onChanged(data)
+ // THEN progress drawable is animating
+ verify(mockSquigglyProgress).animate = true
+ }
+
+ @Test
+ fun seekBarNotPlaying() {
+ // WHEN not playing
+ val isPlaying = false
+ val data = SeekBarViewModel.Progress(true, true, isPlaying, 3000, 120000)
+ observer.onChanged(data)
+ // THEN progress drawable is not animating
+ verify(mockSquigglyProgress).animate = false
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
new file mode 100644
index 0000000..0787fd6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
@@ -0,0 +1,118 @@
+package com.android.systemui.media
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.LightingColorFilter
+import android.graphics.Paint
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SquigglyProgressTest : SysuiTestCase() {
+
+ private val colorFilter = LightingColorFilter(Color.RED, Color.BLUE)
+ private val strokeWidth = 5f
+ private val alpha = 128
+ private val tint = Color.GREEN
+
+ lateinit var squigglyProgress: SquigglyProgress
+ @Mock lateinit var canvas: Canvas
+ @Captor lateinit var wavePaintCaptor: ArgumentCaptor<Paint>
+ @Captor lateinit var linePaintCaptor: ArgumentCaptor<Paint>
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
+
+ @Before
+ fun setup() {
+ squigglyProgress = SquigglyProgress()
+ squigglyProgress.waveLength = 30f
+ squigglyProgress.lineAmplitude = 10f
+ squigglyProgress.phaseSpeed = 8f
+ squigglyProgress.strokeWidth = strokeWidth
+ squigglyProgress.bounds = Rect(0, 0, 300, 30)
+ }
+
+ @Test
+ fun testDrawPathAndLine() {
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+ }
+
+ @Test
+ fun testOnLevelChanged() {
+ assertThat(squigglyProgress.setLevel(5)).isFalse()
+ squigglyProgress.animate = true
+ assertThat(squigglyProgress.setLevel(4)).isTrue()
+ }
+
+ @Test
+ fun testStrokeWidth() {
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
+ assertThat(linePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
+ }
+
+ @Test
+ fun testAlpha() {
+ squigglyProgress.alpha = alpha
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(squigglyProgress.alpha).isEqualTo(alpha)
+ assertThat(wavePaintCaptor.value.alpha).isEqualTo(alpha)
+ assertThat(linePaintCaptor.value.alpha).isEqualTo((alpha / 255f * DISABLED_ALPHA).toInt())
+ }
+
+ @Test
+ fun testColorFilter() {
+ squigglyProgress.colorFilter = colorFilter
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
+ assertThat(linePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
+ }
+
+ @Test
+ fun testTint() {
+ squigglyProgress.setTint(tint)
+ squigglyProgress.draw(canvas)
+
+ verify(canvas).drawPath(any(), wavePaintCaptor.capture())
+ verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
+ linePaintCaptor.capture())
+
+ assertThat(wavePaintCaptor.value.color).isEqualTo(tint)
+ assertThat(linePaintCaptor.value.color).isEqualTo(tint)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 13e5821..380fa6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -37,15 +37,14 @@
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.Before;
import org.junit.Test;
@@ -64,11 +63,10 @@
private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
+ private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
@@ -77,17 +75,16 @@
private MediaOutputController mMediaOutputController;
private int mHeaderIconRes;
private IconCompat mIconCompat;
- private Drawable mAppSourceDrawable;
private CharSequence mHeaderTitle;
private CharSequence mHeaderSubtitle;
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
- mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
+ mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext, mBroadcastSender,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
}
@@ -178,15 +175,16 @@
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
- MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
- super(context, mediaOutputController);
+ MediaOutputBaseDialogImpl(Context context, BroadcastSender broadcastSender,
+ MediaOutputController mediaOutputController) {
+ super(context, broadcastSender, mediaOutputController);
mAdapter = mMediaOutputBaseAdapter;
}
@Override
Drawable getAppSourceIcon() {
- return mAppSourceDrawable;
+ return null;
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 6230700..d2dae74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -45,7 +45,6 @@
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
@@ -57,7 +56,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
-import com.android.systemui.statusbar.phone.ShadeController;
import com.google.common.collect.ImmutableList;
@@ -96,10 +94,8 @@
private NearbyDevice mNearbyDevice2 = mock(NearbyDevice.class);
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private final NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class);
@@ -124,9 +120,9 @@
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(
mCachedBluetoothDeviceManager);
- mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
@@ -176,9 +172,9 @@
@Test
public void start_withoutPackageName_verifyMediaControllerInit() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.start(mCb);
@@ -205,9 +201,9 @@
@Test
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.start(mCb);
@@ -510,9 +506,9 @@
@Test
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
- mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mSpyContext, null,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotifCollection, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index cb52e7c..db56f87 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -37,10 +37,10 @@
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
import org.junit.Before;
@@ -61,8 +61,8 @@
// Mock
private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private final ShadeController mShadeController = mock(ShadeController.class);
private final ActivityStarter mStarter = mock(ActivityStarter.class);
+ private final BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
private final MediaDevice mMediaDevice = mock(MediaDevice.class);
private final NotificationEntryManager mNotificationEntryManager =
@@ -78,12 +78,12 @@
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputDialog = new MediaOutputDialog(mContext, false,
+ mMediaOutputDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);
mMediaOutputDialog.show();
@@ -129,7 +129,7 @@
// Check the visibility metric logging by creating a new MediaOutput dialog,
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
- MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
+ MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false, mBroadcastSender,
mMediaOutputController, mUiEventLogger);
testDialog.show();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index f186f57..0cdde07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -28,17 +28,16 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
import org.junit.Before;
@@ -59,14 +58,13 @@
// Mock
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
- private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
+ private BroadcastSender mBroadcastSender = mock(BroadcastSender.class);
private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
private MediaDevice mMediaDevice = mock(MediaDevice.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
- private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
private NearbyMediaDevicesManager mNearbyMediaDevicesManager = mock(
NearbyMediaDevicesManager.class);
@@ -77,12 +75,12 @@
@Before
public void setUp() {
- mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
- mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator,
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mStarter,
+ mNotificationEntryManager, mDialogLaunchAnimator,
Optional.of(mNearbyMediaDevicesManager));
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
- mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
+ mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false, mBroadcastSender,
mMediaOutputController);
mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index afb63ab..a156820 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -37,6 +37,7 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.util.NotificationChannels;
@@ -59,7 +60,9 @@
// Test Instance.
mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
ActivityStarter starter = mDependency.injectMockDependency(ActivityStarter.class);
- mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter);
+ BroadcastSender broadcastSender = mDependency.injectMockDependency(BroadcastSender.class);
+ mPowerNotificationWarnings = new PowerNotificationWarnings(mContext, starter,
+ broadcastSender);
BatteryStateSnapshot snapshot = new BatteryStateSnapshot(100, false, false, 1,
BatteryManager.BATTERY_HEALTH_GOOD, 5, 15);
mPowerNotificationWarnings.updateSnapshot(snapshot);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 067caa9..64a0a23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -44,6 +44,7 @@
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.ArgumentMatchers.eq
private fun <T> anyObject(): T {
return Mockito.anyObject<T>()
@@ -260,6 +261,49 @@
}
@Test
+ fun setDragAmount_setsKeyguardTransitionProgress() {
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_setsKeyguardAlphaBasedOnDistance() {
+ val alphaDistance = context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_npvc_keyguard_content_alpha_transition_distance)
+ transitionController.dragDownAmount = 10f
+
+ val expectedAlpha = 1 - 10f / alphaDistance
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(eq(expectedAlpha), anyInt())
+ }
+
+ @Test
+ fun setDragAmount_notInSplitShade_setsKeyguardTranslationToZero() {
+ val mediaTranslationY = 123
+ disableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController).setKeyguardTransitionProgress(anyFloat(), eq(0))
+ }
+
+ @Test
+ fun setDragAmount_inSplitShade_setsKeyguardTranslationBasedOnMediaTranslation() {
+ val mediaTranslationY = 123
+ enableSplitShade()
+ whenever(mediaHierarchyManager.getGuidedTransformationTranslationY())
+ .thenReturn(mediaTranslationY)
+
+ transitionController.dragDownAmount = 10f
+
+ verify(notificationPanelController)
+ .setKeyguardTransitionProgress(anyFloat(), eq(mediaTranslationY))
+ }
+
+ @Test
fun setDragDownAmount_setsValueOnMediaHierarchyManager() {
transitionController.dragDownAmount = 10f
@@ -276,8 +320,16 @@
}
private fun enableSplitShade() {
+ setSplitShadeEnabled(true)
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, true
+ R.bool.config_use_split_notification_shade, enabled
)
configurationController.notifyConfigurationChanged()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index d094749..ca8529d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -16,18 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.app.Notification.VISIBILITY_PUBLIC;
-import static android.app.Notification.VISIBILITY_SECRET;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.os.Handler;
import android.os.UserHandle;
@@ -39,20 +29,16 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
-import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
-import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -66,13 +52,13 @@
@Mock private Handler mMainHandler;
@Mock private KeyguardStateController mKeyguardStateController;
- @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private HighPriorityProvider mHighPriorityProvider;
@Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
@Mock private NotifPipeline mNotifPipeline;
+ @Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationEntry mEntry;
private NotifFilter mKeyguardFilter;
@@ -81,9 +67,9 @@
public void setup() {
MockitoAnnotations.initMocks(this);
KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
- mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
- mBroadcastDispatcher, mStatusBarStateController,
- mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider);
+ mStatusBarStateController,
+ mKeyguardUpdateMonitor, mHighPriorityProvider, mSectionHeaderVisibilityProvider,
+ mKeyguardNotificationVisibilityProvider);
mEntry = new NotificationEntryBuilder()
.setUser(new UserHandle(NOTIF_USER_ID))
@@ -94,171 +80,4 @@
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
-
- @Test
- public void unfilteredState() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void keyguardNotShowing() {
- // GIVEN the lockscreen isn't showing
- setupUnfilteredState(mEntry);
- when(mKeyguardStateController.isShowing()).thenReturn(false);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void doNotShowLockscreenNotifications() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN we shouldn't show any lockscreen notifications
- when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void lockdown() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in lockdown:
- when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void publicMode_settingsDisallow() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in public mode and settings are configured to disallow
- // notifications in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
- .thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void publicMode_notifDisallowed() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification's user is in public mode and settings are configured to disallow
- // notifications in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
- mEntry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setVisibilityOverride(VISIBILITY_SECRET).build());
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void doesNotExceedThresholdToShow() {
- // GIVEN an 'unfiltered-keyguard-showing' state
- setupUnfilteredState(mEntry);
-
- // WHEN the notification doesn't exceed the threshold to show on the lockscreen
- mEntry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setImportance(IMPORTANCE_MIN)
- .build());
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
- }
-
- @Test
- public void summaryExceedsThresholdToShow() {
- // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
- // but it's part of a group (has a parent)
- final NotificationEntry entryWithParent = new NotificationEntryBuilder()
- .setUser(new UserHandle(NOTIF_USER_ID))
- .build();
-
- final GroupEntry parent = new GroupEntryBuilder()
- .setKey("test_group_key")
- .setSummary(new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build())
- .addChild(entryWithParent)
- .build();
-
- setupUnfilteredState(entryWithParent);
- entryWithParent.setRanking(new RankingBuilder()
- .setKey(entryWithParent.getKey())
- .setImportance(IMPORTANCE_MIN)
- .build());
-
- // WHEN its parent does exceed threshold tot show on the lockscreen
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
-
- // THEN don't filter out the entry
- assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
-
- // WHEN its parent doesn't exceed threshold to show on lockscreen
- when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
- modifyEntry(parent.getSummary(), builder -> builder
- .setImportance(IMPORTANCE_MIN)
- .done());
-
- // THEN filter out the entry
- assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
- }
-
- /**
- * setup a state where the notification will not be filtered by the
- * KeyguardNotificationCoordinator when the keyguard is showing.
- */
- private void setupUnfilteredState(NotificationEntry entry) {
- // keyguard is showing
- when(mKeyguardStateController.isShowing()).thenReturn(true);
-
- // show notifications on the lockscreen
- when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
-
- // neither the current user nor the notification's user is in lockdown
- when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
- when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
- when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
-
- // not in public mode
- when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
- when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
-
- // entry's ranking - should show on all lockscreens
- // + priority of the notification exceeds the threshold to be shown on the lockscreen
- entry.setRanking(new RankingBuilder()
- .setKey(mEntry.getKey())
- .setVisibilityOverride(VISIBILITY_PUBLIC)
- .setImportance(IMPORTANCE_HIGH)
- .build());
-
- // settings allows notifications in public mode
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
- when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
- .thenReturn(true);
-
- // notification doesn't have a summary
-
- // notification is high priority, so it shouldn't be filtered
- when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
new file mode 100644
index 0000000..de9ea27
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2022 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.statusbar.notification.interruption;
+
+import static android.app.Notification.VISIBILITY_PUBLIC;
+import static android.app.Notification.VISIBILITY_SECRET;
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.UserHandle;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.notification.SectionHeaderVisibilityProvider;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardNotificationVisibilityProviderTest extends SysuiTestCase {
+ private static final int NOTIF_USER_ID = 0;
+ private static final int CURR_USER_ID = 1;
+
+ @Mock
+ private Handler mMainHandler;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+ @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock private HighPriorityProvider mHighPriorityProvider;
+ @Mock private SectionHeaderVisibilityProvider mSectionHeaderVisibilityProvider;
+ @Mock private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private BroadcastDispatcher mBroadcastDispatcher;
+
+ private NotificationEntry mEntry;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ // TODO refactor the test of KeyguardNotificationVisibilityProvider out
+ mKeyguardNotificationVisibilityProvider = spy(new KeyguardNotificationVisibilityProvider(
+ mContext,
+ mMainHandler,
+ mKeyguardStateController,
+ mLockscreenUserManager,
+ mKeyguardUpdateMonitor,
+ mHighPriorityProvider,
+ mStatusBarStateController,
+ mBroadcastDispatcher
+ ));
+
+ mEntry = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .build();
+ }
+
+ @Test
+ public void unfilteredState() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void keyguardNotShowing() {
+ // GIVEN the lockscreen isn't showing
+ setupUnfilteredState(mEntry);
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void doNotShowLockscreenNotifications() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN we shouldn't show any lockscreen notifications
+ when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void lockdown() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in lockdown:
+ when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void publicMode_settingsDisallow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in public mode and settings are configured to disallow
+ // notifications in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+ .thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void publicMode_notifDisallowed() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification's user is in public mode and settings are configured to disallow
+ // notifications in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setVisibilityOverride(VISIBILITY_SECRET).build());
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void doesNotExceedThresholdToShow() {
+ // GIVEN an 'unfiltered-keyguard-showing' state
+ setupUnfilteredState(mEntry);
+
+ // WHEN the notification doesn't exceed the threshold to show on the lockscreen
+ mEntry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+ when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(mEntry));
+ }
+
+ @Test
+ public void summaryExceedsThresholdToShow() {
+ // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
+ // but it's part of a group (has a parent)
+ final NotificationEntry entryWithParent = new NotificationEntryBuilder()
+ .setUser(new UserHandle(NOTIF_USER_ID))
+ .build();
+
+ final GroupEntry parent = new GroupEntryBuilder()
+ .setKey("test_group_key")
+ .setSummary(new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .build())
+ .addChild(entryWithParent)
+ .build();
+
+ setupUnfilteredState(entryWithParent);
+ entryWithParent.setRanking(new RankingBuilder()
+ .setKey(entryWithParent.getKey())
+ .setImportance(IMPORTANCE_MIN)
+ .build());
+
+ // WHEN its parent does exceed threshold tot show on the lockscreen
+ when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
+
+ // THEN don't filter out the entry
+ assertFalse(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
+
+ // WHEN its parent doesn't exceed threshold to show on lockscreen
+ when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
+ modifyEntry(parent.getSummary(), builder -> builder
+ .setImportance(IMPORTANCE_MIN)
+ .done());
+
+ // THEN filter out the entry
+ assertTrue(mKeyguardNotificationVisibilityProvider.hideNotification(entryWithParent));
+ }
+
+ /**
+ * setup a state where the notification will not be filtered by the
+ * KeyguardNotificationCoordinator when the keyguard is showing.
+ */
+ private void setupUnfilteredState(NotificationEntry entry) {
+ // keyguard is showing
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ // show notifications on the lockscreen
+ when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
+
+ // neither the current user nor the notification's user is in lockdown
+ when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
+ when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
+ when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
+
+ // not in public mode
+ when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
+ when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
+
+ // entry's ranking - should show on all lockscreens
+ // + priority of the notification exceeds the threshold to be shown on the lockscreen
+ entry.setRanking(new RankingBuilder()
+ .setKey(mEntry.getKey())
+ .setVisibilityOverride(VISIBILITY_PUBLIC)
+ .setImportance(IMPORTANCE_HIGH)
+ .build());
+
+ // settings allows notifications in public mode
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
+ when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
+ .thenReturn(true);
+
+ // notification doesn't have a summary
+
+ // notification is high priority, so it shouldn't be filtered
+ when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 2e1297b..8a2dc26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -30,6 +30,9 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -48,6 +51,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -86,6 +90,10 @@
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
+ @Mock
+ NotifPipelineFlags mFlags;
+ @Mock
+ KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -104,8 +112,9 @@
mStatusBarStateController,
mHeadsUpManager,
mLogger,
- mMockHandler);
-
+ mMockHandler,
+ mFlags,
+ mKeyguardNotificationVisibilityProvider);
mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
@@ -194,6 +203,16 @@
}
@Test
+ public void testDoNotRunFilterOnNewPipeline() {
+ when(mFlags.isNewPipelineEnabled()).thenReturn(true);
+ // WHEN this entry should be filtered out
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ mNotifInterruptionStateProvider.shouldHeadsUp(entry);
+ verify(mFlags, times(1)).isNewPipelineEnabled();
+ verify(mNotificationFilter, times(0)).shouldFilterOut(eq(entry));
+ }
+
+ @Test
public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
// GIVEN state for "heads up when awake" is true
ensureStateForHeadsUpWhenAwake();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
index 953a330..c72f895 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesTest.java
@@ -131,6 +131,7 @@
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -309,7 +310,9 @@
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
mStatusBarStateController, mBatteryController, mHeadsUpManager,
mock(NotificationInterruptLogger.class),
- new Handler(TestableLooper.get(this).getLooper()));
+ new Handler(TestableLooper.get(this).getLooper()),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -846,6 +849,7 @@
@Test
public void testTransitionLaunch_noPreview_doesntGoUnlocked() {
mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
mCentralSurfaces.showKeyguardImpl();
// Starting a pulse should change the scrim controller to the pulsing state
@@ -868,6 +872,7 @@
@Test
public void testPulseWhileDozing_updatesScrimController() {
mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD);
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
mCentralSurfaces.showKeyguardImpl();
// Starting a pulse should change the scrim controller to the pulsing state
@@ -992,9 +997,12 @@
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- Handler mainHandler) {
+ Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller, headsUpManager, logger, mainHandler);
+ batteryController, controller, headsUpManager, logger, mainHandler,
+ flags, keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 6842295..4bac08e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -56,13 +56,11 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.test.filters.SmallTest;
@@ -389,8 +387,6 @@
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
- mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
- mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
mNotificationContainerParent.addView(mKeyguardStatusView);
mNotificationContainerParent.onFinishInflate();
when(mView.findViewById(R.id.notification_container_parent))
@@ -679,31 +675,6 @@
}
@Test
- public void testAllChildrenOfNotificationContainer_haveIds() {
- enableSplitShade(/* enabled= */ true);
- mNotificationContainerParent.removeAllViews();
- mNotificationContainerParent.addView(newViewWithId(1));
- mNotificationContainerParent.addView(newViewWithId(View.NO_ID));
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(mNotificationContainerParent.getChildAt(0).getId()).isEqualTo(1);
- assertThat(mNotificationContainerParent.getChildAt(1).getId()).isNotEqualTo(View.NO_ID);
- }
-
- @Test
- public void testSinglePaneShadeLayout_isAlignedToParent() {
- enableSplitShade(/* enabled= */ false);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
- .isEqualTo(ConstraintSet.PARENT_ID);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
- .isEqualTo(ConstraintSet.PARENT_ID);
- }
-
- @Test
public void testKeyguardStatusViewInSplitShade_changesConstraintsDependingOnNotifications() {
mStatusBarStateController.setState(KEYGUARD);
enableSplitShade(/* enabled= */ true);
@@ -752,46 +723,6 @@
}
@Test
- public void testSplitShadeLayout_isAlignedToGuideline() {
- enableSplitShade(/* enabled= */ true);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
- .isEqualTo(R.id.qs_edge_guideline);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
- .isEqualTo(R.id.qs_edge_guideline);
- }
-
- @Test
- public void testSplitShadeLayout_childrenHaveInsideMarginsOfZero() {
- enableSplitShade(/* enabled= */ true);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
- .isEqualTo(0);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin)
- .isEqualTo(10);
- }
-
- @Test
- public void testSinglePaneLayout_childrenHaveEqualMargins() {
- enableSplitShade(/* enabled= */ false);
-
- mNotificationPanelViewController.updateResources();
-
- assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
- .isEqualTo(10);
- assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).endMargin)
- .isEqualTo(10);
- }
-
- @Test
public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
mStatusBarStateController.setState(KEYGUARD);
@@ -1016,17 +947,6 @@
}
}
-
- private View newViewWithId(int id) {
- View view = new View(mContext);
- view.setId(id);
- ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- // required as cloning ConstraintSet fails if view doesn't have layout params
- view.setLayoutParams(layoutParams);
- return view;
- }
-
private ConstraintSet.Layout getConstraintSetLayout(@IdRes int id) {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(mNotificationContainerParent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 5fb4144..83eabb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -2,8 +2,14 @@
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
+import android.view.View
+import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManagerPolicyConstants
+import androidx.annotation.AnyRes
+import androidx.annotation.IdRes
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -13,6 +19,7 @@
import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
import com.android.systemui.recents.OverviewProxyService
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,8 +65,10 @@
lateinit var taskbarVisibilityCaptor: ArgumentCaptor<OverviewProxyListener>
@Captor
lateinit var windowInsetsCallbackCaptor: ArgumentCaptor<Consumer<WindowInsets>>
+ @Captor
+ lateinit var constraintSetCaptor: ArgumentCaptor<ConstraintSet>
- private lateinit var notificationsQSContainerController: NotificationsQSContainerController
+ private lateinit var controller: NotificationsQSContainerController
private lateinit var navigationModeCallback: ModeChangedListener
private lateinit var taskbarVisibilityCallback: OverviewProxyListener
private lateinit var windowInsetsCallback: Consumer<WindowInsets>
@@ -68,36 +77,40 @@
fun setup() {
MockitoAnnotations.initMocks(this)
mContext.ensureTestableResources()
+ whenever(notificationsQSContainer.context).thenReturn(mContext)
whenever(notificationsQSContainer.resources).thenReturn(mContext.resources)
- notificationsQSContainerController = NotificationsQSContainerController(
+ controller = NotificationsQSContainerController(
notificationsQSContainer,
navigationModeController,
overviewProxyService,
featureFlags
)
- mContext.orCreateTestableResources
- .addOverride(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
-
- whenever(notificationsQSContainer.defaultNotificationsMarginBottom)
- .thenReturn(NOTIFICATIONS_MARGIN)
+ overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
+ overrideResource(R.dimen.notification_panel_margin_bottom, NOTIFICATIONS_MARGIN)
+ overrideResource(R.bool.config_use_split_notification_shade, false)
whenever(navigationModeController.addListener(navigationModeCaptor.capture()))
.thenReturn(GESTURES_NAVIGATION)
doNothing().`when`(overviewProxyService).addCallback(taskbarVisibilityCaptor.capture())
doNothing().`when`(notificationsQSContainer)
.setInsetsChangedListener(windowInsetsCallbackCaptor.capture())
+ doNothing().`when`(notificationsQSContainer).applyConstraints(constraintSetCaptor.capture())
- notificationsQSContainerController.init()
- notificationsQSContainerController.onViewAttached()
+ controller.init()
+ controller.onViewAttached()
navigationModeCallback = navigationModeCaptor.value
taskbarVisibilityCallback = taskbarVisibilityCaptor.value
windowInsetsCallback = windowInsetsCallbackCaptor.value
}
+ private fun overrideResource(@AnyRes id: Int, value: Any) {
+ mContext.orCreateTestableResources.addOverride(id, value)
+ }
+
@Test
fun testTaskbarVisibleInSplitShade() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = true,
@@ -115,7 +128,7 @@
@Test
fun testTaskbarVisibleInSplitShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = true,
@@ -136,7 +149,7 @@
@Test
fun testTaskbarNotVisibleInSplitShade() {
// when taskbar is not visible, it means we're on the home screen
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -154,7 +167,7 @@
@Test
fun testTaskbarNotVisibleInSplitShade_newFooter() {
// when taskbar is not visible, it means we're on the home screen
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
@@ -173,7 +186,7 @@
@Test
fun testTaskbarNotVisibleInSplitShadeWithCutout() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -190,7 +203,7 @@
@Test
fun testTaskbarNotVisibleInSplitShadeWithCutout_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
@@ -209,7 +222,7 @@
@Test
fun testTaskbarVisibleInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(false)
given(taskbarVisible = true,
@@ -225,7 +238,7 @@
@Test
fun testTaskbarVisibleInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(true)
given(taskbarVisible = true,
@@ -243,7 +256,7 @@
@Test
fun testTaskbarNotVisibleInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(false)
given(taskbarVisible = false,
@@ -264,7 +277,7 @@
@Test
fun testTaskbarNotVisibleInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
+ disableSplitShade()
useNewFooter(true)
given(taskbarVisible = false,
@@ -285,8 +298,8 @@
@Test
fun testCustomizingInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setCustomizerShowing(true)
+ disableSplitShade()
+ controller.setCustomizerShowing(true)
useNewFooter(false)
// always sets spacings to 0
@@ -305,8 +318,8 @@
@Test
fun testCustomizingInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setCustomizerShowing(true)
+ disableSplitShade()
+ controller.setCustomizerShowing(true)
useNewFooter(true)
// always sets spacings to 0
@@ -325,8 +338,8 @@
@Test
fun testDetailShowingInSinglePaneShade() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setDetailShowing(true)
+ disableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(false)
// always sets spacings to 0
@@ -345,8 +358,8 @@
@Test
fun testDetailShowingInSinglePaneShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = false
- notificationsQSContainerController.setDetailShowing(true)
+ disableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(true)
// always sets spacings to 0
@@ -365,8 +378,8 @@
@Test
fun testDetailShowingInSplitShade() {
- notificationsQSContainerController.splitShadeEnabled = true
- notificationsQSContainerController.setDetailShowing(true)
+ enableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(false)
given(taskbarVisible = false,
@@ -383,8 +396,8 @@
@Test
fun testDetailShowingInSplitShade_newFooter() {
- notificationsQSContainerController.splitShadeEnabled = true
- notificationsQSContainerController.setDetailShowing(true)
+ enableSplitShade()
+ controller.setDetailShowing(true)
useNewFooter(true)
given(taskbarVisible = false,
@@ -402,16 +415,106 @@
@Test
fun testNotificationsMarginBottomIsUpdated() {
Mockito.clearInvocations(notificationsQSContainer)
- notificationsQSContainerController.splitShadeEnabled = true
+ enableSplitShade()
verify(notificationsQSContainer).setNotificationsMarginBottom(NOTIFICATIONS_MARGIN)
- whenever(notificationsQSContainer.defaultNotificationsMarginBottom).thenReturn(100)
- notificationsQSContainerController.updateMargins()
- notificationsQSContainerController.splitShadeEnabled = false
-
+ overrideResource(R.dimen.notification_panel_margin_bottom, 100)
+ disableSplitShade()
verify(notificationsQSContainer).setNotificationsMarginBottom(100)
}
+ @Test
+ fun testSplitShadeLayout_isAlignedToGuideline() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(R.id.qs_edge_guideline)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(R.id.qs_edge_guideline)
+ }
+
+ @Test
+ fun testSinglePaneLayout_childrenHaveEqualMargins() {
+ disableSplitShade()
+ controller.updateResources()
+ val qsStartMargin = getConstraintSetLayout(R.id.qs_frame).startMargin
+ val qsEndMargin = getConstraintSetLayout(R.id.qs_frame).endMargin
+ val notifStartMargin = getConstraintSetLayout(R.id.notification_stack_scroller).startMargin
+ val notifEndMargin = getConstraintSetLayout(R.id.notification_stack_scroller).endMargin
+ assertThat(qsStartMargin == qsEndMargin &&
+ notifStartMargin == notifEndMargin &&
+ qsStartMargin == notifStartMargin
+ ).isTrue()
+ }
+
+ @Test
+ fun testSplitShadeLayout_childrenHaveInsideMarginsOfZero() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startMargin)
+ .isEqualTo(0)
+ }
+
+ @Test
+ fun testSplitShadeLayout_qsFrameHasHorizontalMarginsOfZero() {
+ enableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin).isEqualTo(0)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin).isEqualTo(0)
+ }
+
+ @Test
+ fun testSinglePaneShadeLayout_qsFrameHasHorizontalMarginsSetToCorrectValue() {
+ disableSplitShade()
+ controller.updateResources()
+ val notificationPanelMarginHorizontal = context.resources
+ .getDimensionPixelSize(R.dimen.notification_panel_margin_horizontal)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endMargin)
+ .isEqualTo(notificationPanelMarginHorizontal)
+ assertThat(getConstraintSetLayout(R.id.qs_frame).startMargin)
+ .isEqualTo(notificationPanelMarginHorizontal)
+ }
+
+ @Test
+ fun testSinglePaneShadeLayout_isAlignedToParent() {
+ disableSplitShade()
+ controller.updateResources()
+ assertThat(getConstraintSetLayout(R.id.qs_frame).endToEnd)
+ .isEqualTo(ConstraintSet.PARENT_ID)
+ assertThat(getConstraintSetLayout(R.id.notification_stack_scroller).startToStart)
+ .isEqualTo(ConstraintSet.PARENT_ID)
+ }
+
+ @Test
+ fun testAllChildrenOfNotificationContainer_haveIds() {
+ // set dimen to 0 to avoid triggering updating bottom spacing
+ overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, 0)
+ val container = NotificationsQuickSettingsContainer(context, null)
+ container.removeAllViews()
+ container.addView(newViewWithId(1))
+ container.addView(newViewWithId(View.NO_ID))
+ val controller = NotificationsQSContainerController(container, navigationModeController,
+ overviewProxyService, featureFlags)
+ controller.updateResources()
+
+ assertThat(container.getChildAt(0).id).isEqualTo(1)
+ assertThat(container.getChildAt(1).id).isNotEqualTo(View.NO_ID)
+ }
+
+ private fun disableSplitShade() {
+ setSplitShadeEnabled(false)
+ }
+
+ private fun enableSplitShade() {
+ setSplitShadeEnabled(true)
+ }
+
+ private fun setSplitShadeEnabled(enabled: Boolean) {
+ overrideResource(R.bool.config_use_split_notification_shade, enabled)
+ controller.updateResources()
+ }
+
private fun given(
taskbarVisible: Boolean,
navigationMode: Int,
@@ -458,4 +561,18 @@
private fun useNewFooter(useNewFooter: Boolean) {
whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(useNewFooter)
}
-}
\ No newline at end of file
+
+ private fun getConstraintSetLayout(@IdRes id: Int): ConstraintSet.Layout {
+ return constraintSetCaptor.value.getConstraint(id).layout
+ }
+
+ private fun newViewWithId(id: Int): View {
+ val view = View(mContext)
+ view.id = id
+ val layoutParams = ConstraintLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ // required as cloning ConstraintSet fails if view doesn't have layout params
+ view.layoutParams = layoutParams
+ return view
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 10f4435..0b25467 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1234,10 +1234,8 @@
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
- /* expansion */ 0.0f);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
- /* expansion */ 1.0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0f, /* expansion */ 1.0f);
// Verify normal behavior after
mScrimController.setUnocclusionAnimationRunning(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 91c347f..1caacb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -41,6 +41,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -83,6 +84,7 @@
@Mock private lateinit var userManager: UserManager
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var broadcastSender: BroadcastSender
@Mock private lateinit var telephonyListenerManager: TelephonyListenerManager
@Mock private lateinit var secureSettings: SecureSettings
@Mock private lateinit var falsingManager: FalsingManager
@@ -159,6 +161,7 @@
handler,
activityStarter,
broadcastDispatcher,
+ broadcastSender,
uiEventLogger,
falsingManager,
telephonyListenerManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 82880fe..78ee9e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -98,6 +98,7 @@
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -343,7 +344,9 @@
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
- mock(Handler.class)
+ mock(Handler.class),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index cc848bc3..fafe4b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -85,6 +85,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
@@ -309,7 +310,9 @@
mock(BatteryController.class),
mock(HeadsUpManager.class),
mock(NotificationInterruptLogger.class),
- mock(Handler.class)
+ mock(Handler.class),
+ mock(NotifPipelineFlags.class),
+ mock(KeyguardNotificationVisibilityProvider.class)
);
when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(true);
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
index e698f1e..a7f0dc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/TestableNotificationInterruptStateProviderImpl.java
@@ -23,7 +23,9 @@
import android.service.dreams.IDreamManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -42,7 +44,9 @@
BatteryController batteryController,
HeadsUpManager headsUpManager,
NotificationInterruptLogger logger,
- Handler mainHandler) {
+ Handler mainHandler,
+ NotifPipelineFlags flags,
+ KeyguardNotificationVisibilityProvider keyguardNotificationVisibilityProvider) {
super(contentResolver,
powerManager,
dreamManager,
@@ -52,7 +56,9 @@
statusBarStateController,
headsUpManager,
logger,
- mainHandler);
+ mainHandler,
+ flags,
+ keyguardNotificationVisibilityProvider);
mUseHeadsUp = true;
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 7f10314..5ef1008 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -281,9 +281,9 @@
void onDoubleTapAndHold(int displayId);
- void requestImeLocked(AccessibilityServiceConnection connection);
+ void requestImeLocked(AbstractAccessibilityServiceConnection connection);
- void unbindImeLocked(AccessibilityServiceConnection connection);
+ void unbindImeLocked(AbstractAccessibilityServiceConnection connection);
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -387,7 +387,6 @@
& AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
mRequestAccessibilityButton = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
- // TODO(b/218193835): request ime when ime flag is set and clean up when ime flag is unset
mRequestImeApis = (info.flags
& AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR) != 0;
}
@@ -439,6 +438,7 @@
// If the XML manifest had data to configure the service its info
// should be already set. In such a case update only the dynamically
// configurable properties.
+ boolean oldRequestIme = mRequestImeApis;
AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
if (oldInfo != null) {
oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info);
@@ -447,6 +447,11 @@
setDynamicallyConfigurableProperties(info);
}
mSystemSupport.onClientChangeLocked(true);
+ if (!oldRequestIme && mRequestImeApis) {
+ mSystemSupport.requestImeLocked(this);
+ } else if (oldRequestIme && !mRequestImeApis) {
+ mSystemSupport.unbindImeLocked(this);
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0ea087d..249ee16 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -4305,7 +4305,7 @@
}
@Override
- public void requestImeLocked(AccessibilityServiceConnection connection) {
+ public void requestImeLocked(AbstractAccessibilityServiceConnection connection) {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::createSessionForConnection, this, connection));
mMainHandler.sendMessage(obtainMessage(
@@ -4313,12 +4313,12 @@
}
@Override
- public void unbindImeLocked(AccessibilityServiceConnection connection) {
+ public void unbindImeLocked(AbstractAccessibilityServiceConnection connection) {
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::unbindInputForConnection, this, connection));
}
- private void createSessionForConnection(AccessibilityServiceConnection connection) {
+ private void createSessionForConnection(AbstractAccessibilityServiceConnection connection) {
synchronized (mLock) {
if (mInputSessionRequested) {
connection.createImeSessionLocked();
@@ -4326,7 +4326,7 @@
}
}
- private void bindAndStartInputForConnection(AccessibilityServiceConnection connection) {
+ private void bindAndStartInputForConnection(AbstractAccessibilityServiceConnection connection) {
synchronized (mLock) {
if (mInputBinding != null) {
connection.bindInputLocked(mInputBinding);
@@ -4336,7 +4336,7 @@
}
}
- private void unbindInputForConnection(AccessibilityServiceConnection connection) {
+ private void unbindInputForConnection(AbstractAccessibilityServiceConnection connection) {
InputMethodManagerInternal.get().unbindAccessibilityFromCurrentClient(connection.mId);
synchronized (mLock) {
connection.unbindInputLocked();
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
index b1f572d..ac2d1dd 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchManagerService.java
@@ -129,7 +129,7 @@
@Override
public void search(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callBack) {
- searchRequest.setSource(
+ searchRequest.setCallerPackageName(
mContext.getPackageManager().getNameForUid(Binder.getCallingUid()));
runForUser("search", (service) -> {
synchronized (service.mLock) {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 2068e6d..68cd288 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -48,7 +48,6 @@
import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.AndroidPackageApi;
-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.ParsedMainComponent;
@@ -690,8 +689,6 @@
@Nullable
public abstract PackageStateInternal getPackageStateInternal(@NonNull String packageName);
- public abstract @Nullable PackageState getPackageState(@NonNull String packageName);
-
@NonNull
public abstract ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index b59cd4c..1a39ffa 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1166,9 +1166,17 @@
final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
try {
if (allowlist) {
- cm.updateMeteredNetworkAllowList(uid, enable);
+ if (enable) {
+ cm.addUidToMeteredNetworkAllowList(uid);
+ } else {
+ cm.removeUidFromMeteredNetworkAllowList(uid);
+ }
} else {
- cm.updateMeteredNetworkDenyList(uid, enable);
+ if (enable) {
+ cm.addUidToMeteredNetworkDenyList(uid);
+ } else {
+ cm.removeUidFromMeteredNetworkDenyList(uid);
+ }
}
synchronized (mRulesLock) {
if (enable) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9391b18..7075ed3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -75,7 +75,6 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ProviderInfo;
import android.content.pm.UserInfo;
-import android.content.res.Configuration;
import android.content.res.ObbInfo;
import android.database.ContentObserver;
import android.net.Uri;
@@ -124,7 +123,6 @@
import android.provider.MediaStore;
import android.provider.Settings;
import android.service.storage.ExternalStorageService;
-import android.sysprop.VoldProperties;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -1407,39 +1405,6 @@
private void handleDaemonConnected() {
initIfBootedAndConnected();
resetIfBootedAndConnected();
-
- // On an encrypted device we can't see system properties yet, so pull
- // the system locale out of the mount service.
- if ("".equals(VoldProperties.encrypt_progress().orElse(""))) {
- copyLocaleFromMountService();
- }
- }
-
- private void copyLocaleFromMountService() {
- String systemLocale;
- try {
- systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
- } catch (RemoteException e) {
- return;
- }
- if (TextUtils.isEmpty(systemLocale)) {
- return;
- }
-
- Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
- Locale locale = Locale.forLanguageTag(systemLocale);
- Configuration config = new Configuration();
- config.setLocale(locale);
- try {
- ActivityManager.getService().updatePersistentConfigurationWithAttribution(config,
- mContext.getOpPackageName(), mContext.getAttributionTag());
- } catch (RemoteException e) {
- Slog.e(TAG, "Error setting system locale from mount service", e);
- }
-
- // Temporary workaround for http://b/17945169.
- Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
- SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
}
private final IVoldListener mListener = new IVoldListener.Stub() {
@@ -3670,11 +3635,20 @@
mInstaller.tryMountDataMirror(volumeUuid);
}
}
- } catch (RemoteException | Installer.InstallerException e) {
+ } catch (Exception e) {
Slog.wtf(TAG, e);
// Make sure to re-throw this exception; we must not ignore failure
// to prepare the user storage as it could indicate that encryption
// wasn't successfully set up.
+ //
+ // Very unfortunately, these errors need to be ignored for broken
+ // users that already existed on-disk from older Android versions.
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
+ if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
+ Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
+ + "; device may be insecure!");
+ return;
+ }
throw new RuntimeException(e);
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 40ab0c0..58fa9fb 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2013,10 +2013,8 @@
return;
}
- ApnSetting apnSetting = preciseState.getApnSetting();
-
synchronized (mRecords) {
- if (validatePhoneId(phoneId)) {
+ if (validatePhoneId(phoneId) && preciseState.getApnSetting() != null) {
Pair<Integer, ApnSetting> key = Pair.create(preciseState.getTransportType(),
preciseState.getApnSetting());
PreciseDataConnectionState oldState = mPreciseDataConnectionStates.get(phoneId)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4037c04..95e35ef 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3780,7 +3780,7 @@
synchronized (mProcLock) {
mProcessList.killPackageProcessesLSP(packageName, appId, targetUserId,
ProcessList.SERVICE_ADJ, ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, "kill background");
+ ApplicationExitInfo.SUBREASON_KILL_BACKGROUND, "kill background");
}
}
}
@@ -3810,7 +3810,7 @@
mProcessList.killPackageProcessesLSP(null /* packageName */, -1 /* appId */,
UserHandle.USER_ALL, ProcessList.CACHED_APP_MIN_ADJ,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_KILL_BACKGROUND,
"kill all background");
}
@@ -4352,7 +4352,7 @@
ProcessList.INVALID_ADJ, true, false, true,
false, true /* setRemoved */, false,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_STOP_APP,
"fully stop " + packageName + "/" + userId + " by user request");
}
@@ -4404,7 +4404,7 @@
evenPersistent, true /* setRemoved */, uninstalling,
packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
: ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_FORCE_STOP,
(packageName == null ? ("stop user " + userId) : ("stop " + packageName))
+ " due to " + reason);
}
@@ -9756,7 +9756,7 @@
if (info.deniedPermissions != null) {
for (int j = 0; j < info.deniedPermissions.size(); j++) {
pw.print(" deny: ");
- pw.println(info.deniedPermissions.valueAt(i));
+ pw.println(info.deniedPermissions.valueAt(j));
}
}
}
@@ -13636,7 +13636,7 @@
UserHandle.getAppId(extraUid),
userId, ProcessList.INVALID_ADJ,
ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
+ ApplicationExitInfo.SUBREASON_PACKAGE_UPDATE,
"change " + ssp);
}
}
@@ -16365,7 +16365,7 @@
if (pr.mState.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND
&& pr.mReceivers.numberOfCurReceivers() == 0) {
pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, true);
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
} else {
// We delay killing processes that are not in the background or running a
// receiver.
@@ -17002,6 +17002,7 @@
@Override
public void addPendingTopUid(int uid, int pid) {
+ final boolean isNewPending = mPendingStartActivityUids.add(uid, pid);
// If the next top activity is in cached and frozen mode, WM should raise its priority
// to unfreeze it. This is done by calling AMS.updateOomAdj that will lower its oom adj.
// However, WM cannot hold the AMS clock here so the updateOomAdj operation is performed
@@ -17009,11 +17010,9 @@
// next top activity on time. This race will fail the following binder transactions WM
// sends to the activity. After this race issue between WM/ATMS and AMS is solved, this
// workaround can be removed. (b/213288355)
- if (!isPendingTopUid(uid)) {
+ if (isNewPending && mOomAdjuster != null) { // It can be null in unit test.
mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid);
}
-
- mPendingStartActivityUids.add(uid, pid);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 28b807c..2b61e7f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -343,6 +343,8 @@
return runSetStopUserOnSwitch(pw);
case "set-bg-abusive-uids":
return runSetBgAbusiveUids(pw);
+ case "list-bg-exemptions-config":
+ return runListBgExemptionsConfig(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -3292,6 +3294,19 @@
return 0;
}
+ private int runListBgExemptionsConfig(PrintWriter pw) throws RemoteException {
+ final ArraySet<String> sysConfigs = mInternal.mAppRestrictionController
+ .mBgRestrictionExemptioFromSysConfig;
+ if (sysConfigs != null) {
+ for (int i = 0, size = sysConfigs.size(); i < size; i++) {
+ pw.print(sysConfigs.valueAt(i));
+ pw.print(' ');
+ }
+ pw.println();
+ }
+ return 0;
+ }
+
private Resources getResources(PrintWriter pw) throws RemoteException {
// system resources does not contain all the device configuration, construct it manually.
Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 7579d2b..7cd45fe 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -1217,7 +1217,7 @@
mDefaultBgCurrentDrainBgRestrictedThreshold =
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainWindowMs = resources.getInteger(
- R.integer.config_bg_current_drain_window);
+ R.integer.config_bg_current_drain_window) * 1_000;
val = getFloatArray(resources.obtainTypedArray(
R.array.config_bg_current_drain_high_threshold_to_restricted_bucket));
mDefaultBgCurrentDrainRestrictedBucketHighThreshold =
@@ -1227,9 +1227,9 @@
mDefaultBgCurrentDrainBgRestrictedHighThreshold =
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainMediaPlaybackMinDuration = resources.getInteger(
- R.integer.config_bg_current_drain_media_playback_min_duration);
+ R.integer.config_bg_current_drain_media_playback_min_duration) * 1_000;
mDefaultBgCurrentDrainLocationMinDuration = resources.getInteger(
- R.integer.config_bg_current_drain_location_min_duration);
+ R.integer.config_bg_current_drain_location_min_duration) * 1_000;
mDefaultBgCurrentDrainEventDurationBasedThresholdEnabled = resources.getBoolean(
R.bool.config_bg_current_drain_event_duration_based_threshold_enabled);
mDefaultCurrentDrainTypesToRestrictedBucket = resources.getInteger(
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 6e6cb87..dc8403a 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -182,7 +182,7 @@
/**
* Whether or not to show the foreground service manager on tapping notifications.
*/
- private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = false;
+ private static final boolean ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER = true;
private final Context mContext;
private final HandlerThread mBgHandlerThread;
@@ -241,7 +241,7 @@
/**
* The pre-config packages that are exempted from the background restrictions.
*/
- private ArraySet<String> mBgRestrictionExemptioFromSysConfig;
+ ArraySet<String> mBgRestrictionExemptioFromSysConfig;
/**
* Lock specifically for bookkeeping around the carrier-privileged app set.
@@ -1595,8 +1595,8 @@
cancelRequestBgRestrictedIfNecessary(packageName, uid);
final Intent newIntent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
newIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mContext.sendBroadcastAsUser(newIntent,
- UserHandle.of(UserHandle.getUserId(uid)));
+ // Task manager runs in SystemUI, which is SYSTEM user only.
+ mContext.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM);
break;
}
}
@@ -1670,9 +1670,10 @@
if (ENABLE_SHOW_FOREGROUND_SERVICE_MANAGER) {
final Intent intent = new Intent(ACTION_SHOW_FOREGROUND_SERVICE_MANAGER);
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ // Task manager runs in SystemUI, which is SYSTEM user only.
pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
- UserHandle.of(UserHandle.getUserId(uid)));
+ UserHandle.SYSTEM);
} else {
final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
@@ -1750,7 +1751,7 @@
SYSTEM_UID, UserHandle.getUserId(uid));
final String title = mContext.getString(titleRes);
final String message = mContext.getString(messageRes,
- ai != null ? pm.getText(packageName, ai.labelRes, ai) : packageName);
+ ai != null ? ai.loadLabel(pm) : packageName);
final Icon icon = ai != null ? Icon.createWithResource(packageName, ai.icon) : null;
postNotification(notificationId, packageName, uid, title, message, icon, pendingIntent,
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ea63c08..ade44ea 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -21,6 +21,9 @@
import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
import static android.text.TextUtils.formatSimple;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+import static com.android.internal.util.FrameworkStatsLog.BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
@@ -29,6 +32,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -51,6 +55,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -64,6 +69,7 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.os.UserManager;
import android.permission.IPermissionManager;
import android.text.TextUtils;
import android.util.EventLog;
@@ -75,6 +81,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -250,12 +257,16 @@
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
r.enqueueClockTime = System.currentTimeMillis();
+ r.enqueueTime = SystemClock.uptimeMillis();
+ r.enqueueRealTime = SystemClock.elapsedRealtime();
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
r.enqueueClockTime = System.currentTimeMillis();
+ r.enqueueTime = SystemClock.uptimeMillis();
+ r.enqueueRealTime = SystemClock.elapsedRealtime();
mDispatcher.enqueueOrderedBroadcastLocked(r);
enqueueBroadcastHelper(r);
}
@@ -1121,6 +1132,7 @@
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -1292,6 +1304,7 @@
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
+ logBootCompletedBroadcastCompletionLatencyIfPossible(r);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
@@ -1408,6 +1421,7 @@
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
+ r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
if (mLogLatencyMetrics) {
@@ -1866,6 +1880,59 @@
return null;
}
+ private void logBootCompletedBroadcastCompletionLatencyIfPossible(BroadcastRecord r) {
+ // Only log after last receiver.
+ // In case of split BOOT_COMPLETED broadcast, make sure only call this method on the
+ // last BroadcastRecord of the split broadcast which has non-null resultTo.
+ final int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+ if (r.nextReceiver < numReceivers) {
+ return;
+ }
+ final String action = r.intent.getAction();
+ int event = 0;
+ if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
+ event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__LOCKED_BOOT_COMPLETED;
+ } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
+ event = BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED__EVENT__BOOT_COMPLETED;
+ }
+ if (event != 0) {
+ final int dispatchLatency = (int)(r.dispatchTime - r.enqueueTime);
+ final int completeLatency = (int)
+ (SystemClock.uptimeMillis() - r.enqueueTime);
+ final int dispatchRealLatency = (int)(r.dispatchRealTime - r.enqueueRealTime);
+ final int completeRealLatency = (int)
+ (SystemClock.elapsedRealtime() - r.enqueueRealTime);
+ int userType = FrameworkStatsLog.USER_LIFECYCLE_JOURNEY_REPORTED__USER_TYPE__TYPE_UNKNOWN;
+ // This method is called very infrequently, no performance issue we call
+ // LocalServices.getService() here.
+ final UserManagerInternal umInternal = LocalServices.getService(
+ UserManagerInternal.class);
+ final UserInfo userInfo = umInternal.getUserInfo(r.userId);
+ if (userInfo != null) {
+ userType = UserManager.getUserTypeForStatsd(userInfo.userType);
+ }
+ Slog.i(TAG_BROADCAST,
+ "BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED action:"
+ + action
+ + " dispatchLatency:" + dispatchLatency
+ + " completeLatency:" + completeLatency
+ + " dispatchRealLatency:" + dispatchRealLatency
+ + " completeRealLatency:" + completeRealLatency
+ + " receiversSize:" + r.receivers.size()
+ + " userId:" + r.userId
+ + " userType:" + (userInfo != null? userInfo.userType : null));
+ FrameworkStatsLog.write(
+ BOOT_COMPLETED_BROADCAST_COMPLETION_LATENCY_REPORTED,
+ event,
+ dispatchLatency,
+ completeLatency,
+ dispatchRealLatency,
+ completeRealLatency,
+ r.userId,
+ userType);
+ }
+ }
+
private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
// STOPSHIP (217251579): Temporarily use temp-allowlist reason to identify
// push messages and record response events.
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 8b1e829..2ee32b6 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -84,11 +84,14 @@
boolean deferred;
int splitCount; // refcount for result callback, when split
int splitToken; // identifier for cross-BroadcastRecord refcount
+ long enqueueTime; // uptimeMillis when the broadcast was enqueued
+ long enqueueRealTime; // elapsedRealtime when the broadcast was enqueued
long enqueueClockTime; // the clock time the broadcast was enqueued
long dispatchTime; // when dispatch started on this set of receivers
+ long dispatchRealTime; // elapsedRealtime when the broadcast was dispatched
long dispatchClockTime; // the clock time the dispatch started
long receiverTime; // when current receiver started for timeouts.
- long finishTime; // when we finished the broadcast.
+ long finishTime; // when we finished the current receiver.
boolean timeoutExempt; // true if this broadcast is not subject to receiver timeouts
int resultCode; // current result code value.
String resultData; // current result data value.
@@ -169,7 +172,7 @@
pw.print(prefix); pw.print("dispatchTime=");
TimeUtils.formatDuration(dispatchTime, now, pw);
pw.print(" (");
- TimeUtils.formatDuration(dispatchClockTime-enqueueClockTime, pw);
+ TimeUtils.formatDuration(dispatchTime - enqueueTime, pw);
pw.print(" since enq)");
if (finishTime != 0) {
pw.print(" finishTime="); TimeUtils.formatDuration(finishTime, now, pw);
@@ -324,8 +327,11 @@
delivery = from.delivery;
duration = from.duration;
resultTo = from.resultTo;
+ enqueueTime = from.enqueueTime;
+ enqueueRealTime = from.enqueueRealTime;
enqueueClockTime = from.enqueueClockTime;
dispatchTime = from.dispatchTime;
+ dispatchRealTime = from.dispatchRealTime;
dispatchClockTime = from.dispatchClockTime;
receiverTime = from.receiverTime;
finishTime = from.finishTime;
@@ -378,7 +384,9 @@
requiredPermissions, excludedPermissions, appOp, options, splitReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
-
+ split.enqueueTime = this.enqueueTime;
+ split.enqueueRealTime = this.enqueueRealTime;
+ split.enqueueClockTime = this.enqueueClockTime;
split.splitToken = this.splitToken;
return split;
}
@@ -448,9 +456,11 @@
final BroadcastRecord br = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, options,
- uid2receiverList.valueAt(i), resultTo,
+ uid2receiverList.valueAt(i), null /* _resultTo */,
resultCode, resultData, resultExtras, ordered, sticky, initialSticky, userId,
allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
+ br.enqueueTime = this.enqueueTime;
+ br.enqueueRealTime = this.enqueueRealTime;
br.enqueueClockTime = this.enqueueClockTime;
ret.put(uid2receiverList.keyAt(i), br);
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index e0d333e..7ed3dcf 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2561,7 +2561,7 @@
if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
&& state.getSetSchedGroup() == ProcessList.SCHED_GROUP_BACKGROUND) {
app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
- ApplicationExitInfo.SUBREASON_UNKNOWN, true);
+ ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
success = false;
} else {
int processGroup;
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 802ea00..455c75b 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -46,10 +46,13 @@
mContext = context;
}
- synchronized void add(int uid, int pid) {
+ /** Returns {@code true} if the uid is put to the pending array. Otherwise it existed. */
+ synchronized boolean add(int uid, int pid) {
if (mPendingUids.get(uid) == null) {
mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime()));
+ return true;
}
+ return false;
}
synchronized void delete(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 6e14203..48ca59d 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1890,7 +1890,7 @@
/** Return true if the client app for the SDK sandbox process is debuggable. */
private boolean isAppForSdkSandboxDebuggable(ProcessRecord sandboxProcess) {
// TODO (b/221004701) use client app process name
- final int appUid = Process.sdkSandboxToAppUid(sandboxProcess.uid);
+ final int appUid = Process.getAppUidForSdkSandboxUid(sandboxProcess.uid);
IPackageManager pm = mService.getPackageManager();
try {
String[] packages = pm.getPackagesForUid(appUid);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ad17655..8795347 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2618,7 +2618,7 @@
if (getStartedUserState(userId) == null) {
return false;
}
- if (!mInjector.getUserManager().isCredentialSharedWithParent(userId)) {
+ if (!mInjector.getUserManager().isCredentialSharableWithParent(userId)) {
return false;
}
if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
index 0abab6a..a76eb8f 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceFactoryImpl.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.Intent;
@@ -29,6 +30,7 @@
import com.android.internal.infra.ServiceConnector;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.LocalServices;
import com.android.server.app.GameServiceConfiguration.GameServiceComponentConfiguration;
import com.android.server.wm.WindowManagerInternal;
@@ -51,11 +53,13 @@
mContext,
new GameClassifierImpl(mContext.getPackageManager()),
ActivityManager.getService(),
+ LocalServices.getService(ActivityManagerInternal.class),
ActivityTaskManager.getService(),
(WindowManagerService) ServiceManager.getService(Context.WINDOW_SERVICE),
LocalServices.getService(WindowManagerInternal.class),
new GameServiceConnector(mContext, configuration),
- new GameSessionServiceConnector(mContext, configuration));
+ new GameSessionServiceConnector(mContext, configuration),
+ new ScreenshotHelper(mContext));
}
private static final class GameServiceConnector extends ServiceConnector.Impl<IGameService> {
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index e4edf4e..e920523 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -21,15 +21,20 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.Insets;
import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.games.CreateGameSessionRequest;
@@ -42,15 +47,19 @@
import android.service.games.IGameSession;
import android.service.games.IGameSessionController;
import android.service.games.IGameSessionService;
+import android.text.TextUtils;
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.WindowManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.infra.ServiceConnector.ServiceLifecycleCallbacks;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -59,6 +68,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
final class GameServiceProviderInstanceImpl implements GameServiceProviderInstance {
private static final String TAG = "GameServiceProviderInstance";
@@ -136,12 +146,42 @@
GameServiceProviderInstanceImpl.this.onTaskFocusChanged(taskId, focused);
});
}
+ };
- // TODO(b/204503192): Limit the lifespan of the game session in the Game Service provider
- // to only when the associated task is running. Right now it is possible for a task to
- // move into the background and for all associated processes to die and for the Game Session
- // provider's GameSessionService to continue to be running. Ideally we could unbind the
- // service when this happens.
+ /**
+ * The TaskStackListener declared above gives us good visibility into game task lifecycle.
+ * However, it is possible for the Android system to kill all the processes associated with a
+ * game task (e.g., when the system is under memory pressure or reaches a background process
+ * limit). When this happens, the game task remains (and no TaskStackListener callbacks are
+ * invoked), but we would nonetheless want to destroy a game session associated with the task
+ * if this were to happen.
+ *
+ * This process observer gives us visibility into process lifecycles and lets us track all the
+ * processes associated with each package so that any game sessions associated with the package
+ * are destroyed if the process count for a given package reaches zero (most packages will
+ * have at most one task). If processes for a given package are started up again, the destroyed
+ * game sessions will be re-created.
+ */
+ private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ // This callback is used to track how many processes are running for a given package.
+ // Then, when a process dies, we will know if it was the only process running for that
+ // package and the associated game sessions should be destroyed.
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onForegroundActivitiesChanged(pid);
+ });
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ mBackgroundExecutor.execute(() -> {
+ GameServiceProviderInstanceImpl.this.onProcessDied(pid);
+ });
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {}
};
private final IGameServiceController mGameServiceController =
@@ -185,9 +225,11 @@
private final Context mContext;
private final GameClassifier mGameClassifier;
private final IActivityManager mActivityManager;
+ private final ActivityManagerInternal mActivityManagerInternal;
private final IActivityTaskManager mActivityTaskManager;
private final WindowManagerService mWindowManagerService;
private final WindowManagerInternal mWindowManagerInternal;
+ private final ScreenshotHelper mScreenshotHelper;
private final ServiceConnector<IGameService> mGameServiceConnector;
private final ServiceConnector<IGameSessionService> mGameSessionServiceConnector;
@@ -195,6 +237,12 @@
private final ConcurrentHashMap<Integer, GameSessionRecord> mGameSessions =
new ConcurrentHashMap<>();
@GuardedBy("mLock")
+ private final ConcurrentHashMap<Integer, String> mPidToPackageMap = new ConcurrentHashMap<>();
+ @GuardedBy("mLock")
+ private final ConcurrentHashMap<String, Integer> mPackageNameToProcessCountMap =
+ new ConcurrentHashMap<>();
+
+ @GuardedBy("mLock")
private volatile boolean mIsRunning;
GameServiceProviderInstanceImpl(
@@ -203,21 +251,25 @@
@NonNull Context context,
@NonNull GameClassifier gameClassifier,
@NonNull IActivityManager activityManager,
+ @NonNull ActivityManagerInternal activityManagerInternal,
@NonNull IActivityTaskManager activityTaskManager,
@NonNull WindowManagerService windowManagerService,
@NonNull WindowManagerInternal windowManagerInternal,
@NonNull ServiceConnector<IGameService> gameServiceConnector,
- @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector) {
+ @NonNull ServiceConnector<IGameSessionService> gameSessionServiceConnector,
+ @NonNull ScreenshotHelper screenshotHelper) {
mUserHandle = userHandle;
mBackgroundExecutor = backgroundExecutor;
mContext = context;
mGameClassifier = gameClassifier;
mActivityManager = activityManager;
+ mActivityManagerInternal = activityManagerInternal;
mActivityTaskManager = activityTaskManager;
mWindowManagerService = windowManagerService;
mWindowManagerInternal = windowManagerInternal;
mGameServiceConnector = gameServiceConnector;
mGameSessionServiceConnector = gameSessionServiceConnector;
+ mScreenshotHelper = screenshotHelper;
}
@Override
@@ -253,6 +305,12 @@
Slog.w(TAG, "Failed to register task stack listener", e);
}
+ try {
+ mActivityManager.registerProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to register process observer", e);
+ }
+
mWindowManagerInternal.registerTaskSystemBarsListener(mTaskSystemBarsVisibilityListener);
}
@@ -264,6 +322,12 @@
mIsRunning = false;
try {
+ mActivityManager.unregisterProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to unregister process observer", e);
+ }
+
+ try {
mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to unregister task stack listener", e);
@@ -586,6 +650,126 @@
}
}
+ private void onForegroundActivitiesChanged(int pid) {
+ synchronized (mLock) {
+ onForegroundActivitiesChangedLocked(pid);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onForegroundActivitiesChangedLocked(int pid) {
+ if (mPidToPackageMap.containsKey(pid)) {
+ // We are already tracking this pid, nothing to do.
+ return;
+ }
+
+ final String packageName = mActivityManagerInternal.getPackageNameByPid(pid);
+ if (TextUtils.isEmpty(packageName)) {
+ // Game processes should always have a package name.
+ return;
+ }
+
+ if (!gameSessionExistsForPackageNameLocked(packageName)) {
+ // We only need to track processes for tasks with game session records.
+ return;
+ }
+
+ mPidToPackageMap.put(pid, packageName);
+ final int processCountForPackage = mPackageNameToProcessCountMap.getOrDefault(packageName,
+ 0) + 1;
+ mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+ if (DEBUG) {
+ Slog.d(TAG, "onForegroundActivitiesChangedLocked: tracking pid " + pid + ", for "
+ + packageName + ". Process count for package: " + processCountForPackage);
+ }
+
+ // If there are processes for the package, we may need to re-create game sessions
+ // that are associated with the package
+ if (processCountForPackage > 0) {
+ recreateEndedGameSessionsLocked(packageName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void recreateEndedGameSessionsLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (gameSessionRecord.isGameSessionEndedForProcessDeath() && packageName.equals(
+ gameSessionRecord.getComponentName().getPackageName())) {
+ if (DEBUG) {
+ Slog.d(TAG,
+ "recreateGameSessionsLocked(): re-creating game session for: "
+ + packageName + " with taskId: "
+ + gameSessionRecord.getTaskId());
+ }
+
+ final int taskId = gameSessionRecord.getTaskId();
+ mGameSessions.put(taskId, GameSessionRecord.awaitingGameSessionRequest(taskId,
+ gameSessionRecord.getComponentName()));
+ createGameSessionLocked(gameSessionRecord.getTaskId());
+ }
+ }
+ }
+
+ private void onProcessDied(int pid) {
+ synchronized (mLock) {
+ onProcessDiedLocked(pid);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onProcessDiedLocked(int pid) {
+ final String packageName = mPidToPackageMap.remove(pid);
+ if (packageName == null) {
+ // We weren't tracking this process.
+ return;
+ }
+
+ final Integer oldProcessCountForPackage = mPackageNameToProcessCountMap.get(packageName);
+ if (oldProcessCountForPackage == null) {
+ // This should never happen; we should have a process count for all tracked packages.
+ Slog.w(TAG, "onProcessDiedLocked(): Missing process count for package");
+ return;
+ }
+
+ final int processCountForPackage = oldProcessCountForPackage - 1;
+ mPackageNameToProcessCountMap.put(packageName, processCountForPackage);
+
+ // If there are no more processes for the game, then we will terminate any game sessions
+ // running for the package.
+ if (processCountForPackage <= 0) {
+ endGameSessionsForPackageLocked(packageName);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void endGameSessionsForPackageLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (gameSessionRecord.getGameSession() != null && packageName.equals(
+ gameSessionRecord.getComponentName().getPackageName())) {
+ if (DEBUG) {
+ Slog.d(TAG, "endGameSessionsForPackageLocked(): No more processes for "
+ + packageName + ", ending game session with taskId: "
+ + gameSessionRecord.getTaskId());
+ }
+ mGameSessions.put(gameSessionRecord.getTaskId(),
+ gameSessionRecord.withGameSessionEndedOnProcessDeath());
+ destroyGameSessionFromRecordLocked(gameSessionRecord);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean gameSessionExistsForPackageNameLocked(String packageName) {
+ for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
+ if (packageName.equals(gameSessionRecord.getComponentName().getPackageName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@Nullable
private GameSessionViewHostConfiguration createViewHostConfigurationForTask(int taskId) {
RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
@@ -651,7 +835,26 @@
Slog.w(TAG, "Could not get bitmap for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
} else {
- callback.complete(GameScreenshotResult.createSuccessResult(bitmap));
+ final Bundle bundle = ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(
+ bitmap);
+ final RunningTaskInfo runningTaskInfo = getRunningTaskInfoForTask(taskId);
+ if (runningTaskInfo == null) {
+ Slog.w(TAG, "Could not get running task info for id: " + taskId);
+ callback.complete(GameScreenshotResult.createInternalErrorResult());
+ }
+ final Rect crop = runningTaskInfo.configuration.windowConfiguration.getBounds();
+ final Consumer<Uri> completionConsumer = (uri) -> {
+ if (uri == null) {
+ callback.complete(GameScreenshotResult.createInternalErrorResult());
+ } else {
+ callback.complete(GameScreenshotResult.createSuccessResult());
+ }
+ };
+ mScreenshotHelper.provideScreenshot(bundle, crop, Insets.NONE, taskId,
+ mUserHandle.getIdentifier(), gameSessionRecord.getComponentName(),
+ WindowManager.ScreenshotSource.SCREENSHOT_OTHER,
+ BackgroundThread.getHandler(),
+ completionConsumer);
}
});
}
diff --git a/services/core/java/com/android/server/app/GameSessionRecord.java b/services/core/java/com/android/server/app/GameSessionRecord.java
index a241812..74e538e 100644
--- a/services/core/java/com/android/server/app/GameSessionRecord.java
+++ b/services/core/java/com/android/server/app/GameSessionRecord.java
@@ -35,6 +35,10 @@
// A Game Session is created and attached.
// GameSessionRecord.getGameSession() != null.
GAME_SESSION_ATTACHED,
+ // A Game Session did exist for a given game task but was destroyed because the last process
+ // for the game died.
+ // GameSessionRecord.getGameSession() == null.
+ GAME_SESSION_ENDED_PROCESS_DEATH,
}
private final int mTaskId;
@@ -99,6 +103,20 @@
}
@NonNull
+ public GameSessionRecord withGameSessionEndedOnProcessDeath() {
+ return new GameSessionRecord(
+ mTaskId,
+ State.GAME_SESSION_ENDED_PROCESS_DEATH,
+ mRootComponentName,
+ /* gameSession=*/ null,
+ /* surfacePackage=*/ null);
+ }
+
+ public boolean isGameSessionEndedForProcessDeath() {
+ return mState == State.GAME_SESSION_ENDED_PROCESS_DEATH;
+ }
+
+ @NonNull
public int getTaskId() {
return mTaskId;
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index ecb43f6..7db99f1 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -184,6 +184,9 @@
// Must be equal to number of CameraStreamProto in CameraActionEvent
private static final int MAX_STREAM_STATISTICS = 5;
+ private static final float MIN_PREVIEW_FPS = 30.0f;
+ private static final float MAX_PREVIEW_FPS = 60.0f;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final Handler mHandler;
@@ -821,6 +824,7 @@
Slog.v(TAG, "Stream " + i + ": width " + streamProtos[i].width
+ ", height " + streamProtos[i].height
+ ", format " + streamProtos[i].format
+ + ", maxPreviewFps " + streamStats.getMaxPreviewFps()
+ ", dataSpace " + streamProtos[i].dataSpace
+ ", usage " + streamProtos[i].usage
+ ", requestCount " + streamProtos[i].requestCount
@@ -1015,6 +1019,11 @@
return false;
}
+ private float getMinFps(CameraSessionStats cameraState) {
+ float maxFps = cameraState.getMaxPreviewFps();
+ return Math.max(Math.min(maxFps, MAX_PREVIEW_FPS), MIN_PREVIEW_FPS);
+ }
+
private void updateActivityCount(CameraSessionStats cameraState) {
String cameraId = cameraState.getCameraId();
int newCameraState = cameraState.getNewCameraState();
@@ -1068,7 +1077,9 @@
if (!alreadyActivePackage) {
WindowManagerInternal wmi =
LocalServices.getService(WindowManagerInternal.class);
- wmi.addNonHighRefreshRatePackage(clientName);
+ float minFps = getMinFps(cameraState);
+ wmi.addRefreshRateRangeForPackage(clientName,
+ minFps, MAX_PREVIEW_FPS);
}
// Update activity events
@@ -1107,7 +1118,7 @@
if (!stillActivePackage) {
WindowManagerInternal wmi =
LocalServices.getService(WindowManagerInternal.class);
- wmi.removeNonHighRefreshRatePackage(clientName);
+ wmi.removeRefreshRateRangeForPackage(clientName);
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 540ae81..7a0cf4b 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -73,8 +73,6 @@
private final SurfaceControlProxy mSurfaceControlProxy;
- private final boolean mIsBootDisplayModeSupported;
-
// Called with SyncRoot lock held.
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
@@ -87,7 +85,6 @@
super(syncRoot, context, handler, listener, TAG);
mInjector = injector;
mSurfaceControlProxy = mInjector.getSurfaceControlProxy();
- mIsBootDisplayModeSupported = mSurfaceControlProxy.getBootDisplayModeSupport();
}
@Override
@@ -352,7 +349,8 @@
if (preferredRecord != null) {
int preferredModeId = preferredRecord.mMode.getModeId();
- if (mIsBootDisplayModeSupported && mSystemPreferredModeId != preferredModeId) {
+ if (mSurfaceControlProxy.getBootDisplayModeSupport()
+ && mSystemPreferredModeId != preferredModeId) {
mSystemPreferredModeId = preferredModeId;
preferredModeChanged = true;
}
@@ -902,7 +900,7 @@
}
updateDeviceInfoLocked();
- if (!mIsBootDisplayModeSupported) {
+ if (!mSurfaceControlProxy.getBootDisplayModeSupport()) {
return;
}
if (mUserPreferredModeId == INVALID_MODE_ID) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1f9d080..77dcbd3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1757,6 +1757,15 @@
}
}
+ @NonNull
+ private static PackageManager getPackageManagerForUser(@NonNull Context context,
+ @UserIdInt int userId) {
+ return context.getUserId() == userId
+ ? context.getPackageManager()
+ : context.createContextAsUser(UserHandle.of(userId), 0 /* flags */)
+ .getPackageManager();
+ }
+
@GuardedBy("ImfLock.class")
private void switchUserOnHandlerLocked(@UserIdInt int newUserId,
IInputMethodClient clientToBeReset) {
@@ -1801,9 +1810,9 @@
updateFromSettingsLocked(true);
if (initialUserSwitch) {
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(), newUserId,
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, newUserId),
+ mSettings.getEnabledInputMethodListLocked());
}
if (DEBUG) Slog.d(TAG, "Switching user stage 3/3. newUserId=" + newUserId
@@ -1892,9 +1901,9 @@
final boolean imeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
buildInputMethodListLocked(!imeSelectedOnBoot /* resetDefaultEnabledIme */);
updateFromSettingsLocked(true);
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(), currentUserId,
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, currentUserId),
+ mSettings.getEnabledInputMethodListLocked());
}
}
}
@@ -6122,10 +6131,9 @@
setInputMethodEnabledLocked(imi.getId(), true);
}
updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(),
- mSettings.getCurrentUserId(),
- mContext.getBasePackageName());
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+ getPackageManagerForUser(mContext, mSettings.getCurrentUserId()),
+ mSettings.getEnabledInputMethodListLocked());
nextIme = mSettings.getSelectedInputMethod();
nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
} else {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index e619fff..4633df2 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -18,17 +18,16 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserHandleAware;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -663,8 +662,9 @@
return !subtype.isAuxiliary();
}
- static void setNonSelectedSystemImesDisabledUntilUsed(IPackageManager packageManager,
- List<InputMethodInfo> enabledImis, @UserIdInt int userId, String callingPackage) {
+ @UserHandleAware
+ static void setNonSelectedSystemImesDisabledUntilUsed(PackageManager packageManagerForUser,
+ List<InputMethodInfo> enabledImis) {
if (DEBUG) {
Slog.d(TAG, "setNonSelectedSystemImesDisabledUntilUsed");
}
@@ -675,7 +675,8 @@
}
// Only the current spell checker should be treated as an enabled one.
final SpellCheckerInfo currentSpellChecker =
- TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(userId);
+ TextServicesManagerInternal.get().getCurrentSpellCheckerForUser(
+ packageManagerForUser.getUserId());
for (final String packageName : systemImesDisabledUntilUsed) {
if (DEBUG) {
Slog.d(TAG, "check " + packageName);
@@ -702,11 +703,12 @@
}
ApplicationInfo ai = null;
try {
- ai = packageManager.getApplicationInfo(packageName,
- PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
- } catch (RemoteException e) {
+ ai = packageManagerForUser.getApplicationInfo(packageName,
+ PackageManager.ApplicationInfoFlags.of(
+ PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
+ } catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "getApplicationInfo failed. packageName=" + packageName
- + " userId=" + userId, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
continue;
}
if (ai == null) {
@@ -717,18 +719,18 @@
if (!isSystemPackage) {
continue;
}
- setDisabledUntilUsed(packageManager, packageName, userId, callingPackage);
+ setDisabledUntilUsed(packageManagerForUser, packageName);
}
}
- private static void setDisabledUntilUsed(IPackageManager packageManager, String packageName,
- int userId, String callingPackage) {
+ private static void setDisabledUntilUsed(PackageManager packageManagerForUser,
+ String packageName) {
final int state;
try {
- state = packageManager.getApplicationEnabledSetting(packageName, userId);
- } catch (RemoteException e) {
+ state = packageManagerForUser.getApplicationEnabledSetting(packageName);
+ } catch (IllegalArgumentException e) {
Slog.w(TAG, "getApplicationEnabledSetting failed. packageName=" + packageName
- + " userId=" + userId, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
return;
}
if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -737,12 +739,12 @@
Slog.d(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED");
}
try {
- packageManager.setApplicationEnabledSetting(packageName,
+ packageManagerForUser.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
- 0 /* newState */, userId, callingPackage);
- } catch (RemoteException e) {
+ 0 /* newState */);
+ } catch (IllegalArgumentException e) {
Slog.w(TAG, "setApplicationEnabledSetting failed. packageName=" + packageName
- + " userId=" + userId + " callingPackage=" + callingPackage, e);
+ + " userId=" + packageManagerForUser.getUserId(), e);
return;
}
} else {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0f4648a..52834cb 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -373,7 +373,7 @@
LockscreenCredential profileUserPassword) {
if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + profileUserId);
// Only for profiles that shares credential with parent
- if (!isCredentialSharedWithParent(profileUserId)) {
+ if (!isCredentialSharableWithParent(profileUserId)) {
return;
}
// Do not tie profile when work challenge is enabled
@@ -789,7 +789,7 @@
private void ensureProfileKeystoreUnlocked(int userId) {
final KeyStore ks = KeyStore.getInstance();
if (ks.state(userId) == KeyStore.State.LOCKED
- && isCredentialSharedWithParent(userId)
+ && isCredentialSharableWithParent(userId)
&& hasUnifiedChallenge(userId)) {
Slog.i(TAG, "Profile got unlocked, will unlock its keystore");
// If boot took too long and the password in vold got expired, parent keystore will
@@ -810,7 +810,7 @@
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
tieProfileLockIfNecessary(userId, LockscreenCredential.createNone());
}
@@ -1077,7 +1077,7 @@
final int userCount = users.size();
for (int i = 0; i < userCount; i++) {
UserInfo user = users.get(i);
- if (isCredentialSharedWithParent(user.id)
+ if (isCredentialSharableWithParent(user.id)
&& !getSeparateProfileChallengeEnabledInternal(user.id)) {
success &= SyntheticPasswordCrypto.migrateLockSettingsKey(
PROFILE_KEY_NAME_ENCRYPT + user.id);
@@ -1471,7 +1471,7 @@
Thread.currentThread().interrupt();
}
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
if (!hasUnifiedChallenge(userId)) {
mBiometricDeferredQueue.processPendingLockoutResets();
}
@@ -1480,7 +1480,7 @@
for (UserInfo profile : mUserManager.getProfiles(userId)) {
if (profile.id == userId) continue;
- if (!isCredentialSharedWithParent(profile.id)) continue;
+ if (!isCredentialSharableWithParent(profile.id)) continue;
if (hasUnifiedChallenge(profile.id)) {
if (mUserManager.isUserRunning(profile.id)) {
@@ -1517,7 +1517,7 @@
}
private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
return null;
}
Map<Integer, LockscreenCredential> result = new ArrayMap<>();
@@ -1525,7 +1525,7 @@
final int size = profiles.size();
for (int i = 0; i < size; i++) {
final UserInfo profile = profiles.get(i);
- if (!isCredentialSharedWithParent(profile.id)) {
+ if (!isCredentialSharableWithParent(profile.id)) {
continue;
}
final int profileUserId = profile.id;
@@ -1560,7 +1560,7 @@
*/
private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
Map<Integer, LockscreenCredential> profilePasswordMap) {
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
return;
}
final boolean isSecure = isUserSecure(userId);
@@ -1569,7 +1569,7 @@
for (int i = 0; i < size; i++) {
final UserInfo profile = profiles.get(i);
final int profileUserId = profile.id;
- if (isCredentialSharedWithParent(profileUserId)) {
+ if (isCredentialSharableWithParent(profileUserId)) {
if (getSeparateProfileChallengeEnabledInternal(profileUserId)) {
continue;
}
@@ -1596,12 +1596,12 @@
}
private boolean isProfileWithUnifiedLock(int userId) {
- return isCredentialSharedWithParent(userId)
+ return isCredentialSharableWithParent(userId)
&& !getSeparateProfileChallengeEnabledInternal(userId);
}
private boolean isProfileWithSeparatedLock(int userId) {
- return isCredentialSharedWithParent(userId)
+ return isCredentialSharableWithParent(userId)
&& getSeparateProfileChallengeEnabledInternal(userId);
}
@@ -1719,7 +1719,7 @@
setSeparateProfileChallengeEnabledLocked(userId, true, /* unused */ null);
notifyPasswordChanged(credential, userId);
}
- if (isCredentialSharedWithParent(userId)) {
+ if (isCredentialSharableWithParent(userId)) {
// Make sure the profile doesn't get locked straight after setting work challenge.
setDeviceUnlockedForUser(userId);
}
@@ -1734,7 +1734,7 @@
/**
* @param savedCredential if the user is a profile with
- * {@link UserManager#isCredentialSharedWithParent()} with unified challenge and
+ * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and
* savedCredential is empty, LSS will try to re-derive the profile password internally.
* TODO (b/80170828): Fix this so profile password is always passed in.
* @param isLockTiedToParent is {@code true} if {@code userId} is a profile and its new
@@ -1800,7 +1800,10 @@
}
private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
- updateEncryptionPasswordIfNeeded(newCredential, userHandle);
+ if (userHandle == UserHandle.USER_SYSTEM && isDeviceEncryptionEnabled() &&
+ shouldEncryptWithCredentials() && newCredential.isNone()) {
+ setCredentialRequiredToDecrypt(false);
+ }
if (newCredential.isPattern()) {
setBoolean(LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, true, userHandle);
}
@@ -1809,26 +1812,6 @@
}
/**
- * Update device encryption password if calling user is USER_SYSTEM and device supports
- * encryption.
- */
- private void updateEncryptionPasswordIfNeeded(LockscreenCredential credential, int userHandle) {
- // Update the device encryption password.
- if (userHandle != UserHandle.USER_SYSTEM || !isDeviceEncryptionEnabled()) {
- return;
- }
- if (!shouldEncryptWithCredentials()) {
- updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
- return;
- }
- if (credential.isNone()) {
- // Set the encryption password to default.
- setCredentialRequiredToDecrypt(false);
- }
- updateEncryptionPassword(credential.getStorageCryptType(), credential.getCredential());
- }
-
- /**
* Store the hash of the *current* password in the password history list, if device policy
* enforces password history requirement.
*/
@@ -1927,8 +1910,8 @@
}
}
- protected boolean isCredentialSharedWithParent(int userId) {
- return getUserManagerFromCache(userId).isCredentialSharedWithParent();
+ protected boolean isCredentialSharableWithParent(int userId) {
+ return getUserManagerFromCache(userId).isCredentialSharableWithParent();
}
private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
@@ -1942,34 +1925,6 @@
}
}
- /** Update the encryption password if it is enabled **/
- @Override
- public void updateEncryptionPassword(final int type, final byte[] password) {
- if (!hasSecureLockScreen() && password != null && password.length != 0) {
- throw new UnsupportedOperationException(
- "This operation requires the lock screen feature.");
- }
- if (!isDeviceEncryptionEnabled()) {
- return;
- }
- final IBinder service = ServiceManager.getService("mount");
- if (service == null) {
- Slog.e(TAG, "Could not find the mount service to update the encryption password");
- return;
- }
-
- // TODO(b/120484642): This is a location where we still use a String for vold
- String passwordString = password != null ? new String(password) : null;
- mHandler.post(() -> {
- IStorageManager storageManager = mInjector.getStorageManager();
- try {
- storageManager.changeEncryptionPassword(type, passwordString);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error changing encryption password", e);
- }
- });
- }
-
/** Register the given WeakEscrowTokenRemovedListener. */
@Override
public boolean registerWeakEscrowTokenRemovedListener(
@@ -2206,7 +2161,7 @@
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock profile which shares credential with parent with unified lock
- if (isCredentialSharedWithParent(pi.id)
+ if (isCredentialSharableWithParent(pi.id)
&& !getSeparateProfileChallengeEnabledInternal(pi.id)
&& mStorage.hasChildProfileLock(pi.id)) {
try {
@@ -2600,7 +2555,7 @@
mManagedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
- if (unknownUser || isCredentialSharedWithParent(userId)) {
+ if (unknownUser || isCredentialSharableWithParent(userId)) {
removeKeystoreProfileKey(userId);
}
// Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
@@ -3320,7 +3275,7 @@
* Returns a fixed pseudorandom byte string derived from the user's synthetic password.
* This is used to salt the password history hash to protect the hash against offline
* bruteforcing, since rederiving this value requires a successful authentication.
- * If user is a profile with {@link UserManager#isCredentialSharedWithParent()} true and with
+ * If user is a profile with {@link UserManager#isCredentialSharableWithParent()} true and with
* unified challenge, currentCredential is ignored.
*/
@Override
diff --git a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
deleted file mode 100644
index 6b442a6..0000000
--- a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2022 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.logcat;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentSender;
-import android.os.Bundle;
-import android.os.ServiceManager;
-import android.os.logcat.ILogcatManagerService;
-import android.util.Slog;
-import android.view.View;
-import android.widget.TextView;
-
-import com.android.internal.R;
-import com.android.internal.app.AlertActivity;
-import com.android.internal.app.AlertController;
-
-
-/**
- * This dialog is shown to the user before an activity in a harmful app is launched.
- *
- * See {@code PackageManager.setLogcatAppInfo} for more info.
- */
-public class LogAccessConfirmationActivity extends AlertActivity implements
- DialogInterface.OnClickListener {
- private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
-
- private String mPackageName;
- private IntentSender mTarget;
- private final ILogcatManagerService mLogcatManagerService =
- ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
-
- private int mUid;
- private int mGid;
- private int mPid;
- private int mFd;
-
- private static final String EXTRA_UID = "uid";
- private static final String EXTRA_GID = "gid";
- private static final String EXTRA_PID = "pid";
- private static final String EXTRA_FD = "fd";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- final Intent intent = getIntent();
- mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
- mUid = intent.getIntExtra("uid", 0);
- mGid = intent.getIntExtra("gid", 0);
- mPid = intent.getIntExtra("pid", 0);
- mFd = intent.getIntExtra("fd", 0);
-
- final AlertController.AlertParams p = mAlertParams;
- p.mTitle = getString(R.string.log_access_confirmation_title);
- p.mView = createView();
-
- p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
- p.mPositiveButtonListener = this;
- p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
- p.mNegativeButtonListener = this;
-
- mAlert.installContent(mAlertParams);
- }
-
- private View createView() {
- final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
- null /*root*/);
- ((TextView) view.findViewById(R.id.app_name_text))
- .setText(mPackageName);
- ((TextView) view.findViewById(R.id.message))
- .setText(getIntent().getExtras().getString("body"));
- return view;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- try {
- mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
- } catch (Throwable t) {
- Slog.e(TAG, "Could not start the LogcatManagerService.", t);
- }
- finish();
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- try {
- mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
- } catch (Throwable t) {
- Slog.e(TAG, "Could not start the LogcatManagerService.", t);
- }
- finish();
- break;
- }
- }
-
- /**
- * Create the Intent for a LogAccessConfirmationActivity.
- */
- public static Intent createIntent(Context context, String targetPackageName,
- IntentSender target, int uid, int gid, int pid, int fd) {
- final Intent intent = new Intent();
- intent.setClass(context, LogAccessConfirmationActivity.class);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
- intent.putExtra(EXTRA_UID, uid);
- intent.putExtra(EXTRA_GID, gid);
- intent.putExtra(EXTRA_PID, pid);
- intent.putExtra(EXTRA_FD, fd);
-
- return intent;
- }
-
-}
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
new file mode 100644
index 0000000..7116ca3
--- /dev/null
+++ b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 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.logcat;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.logcat.ILogcatManagerService;
+import android.util.Slog;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.internal.R;
+
+/**
+ * Dialog responsible for obtaining user consent per-use log access
+ */
+public class LogAccessDialogActivity extends Activity implements
+ View.OnClickListener {
+ private static final String TAG = LogAccessDialogActivity.class.getSimpleName();
+ private Context mContext;
+
+ private final ILogcatManagerService mLogcatManagerService =
+ ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
+
+ private String mPackageName;
+
+ private int mUid;
+ private int mGid;
+ private int mPid;
+ private int mFd;
+ private String mAlertTitle;
+ private AlertDialog.Builder mAlertDialog;
+ private AlertDialog mAlert;
+
+ private static final int DIALOG_TIME_OUT = 300000;
+ private static final int MSG_DISMISS_DIALOG = 0;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mContext = this;
+
+ Intent intent = getIntent();
+ mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ mUid = intent.getIntExtra("com.android.server.logcat.uid", 0);
+ mGid = intent.getIntExtra("com.android.server.logcat.gid", 0);
+ mPid = intent.getIntExtra("com.android.server.logcat.pid", 0);
+ mFd = intent.getIntExtra("com.android.server.logcat.fd", 0);
+ mAlertTitle = getTitleString(mContext, mPackageName, mUid);
+
+ if (mAlertTitle != null) {
+
+ mAlertDialog = new AlertDialog.Builder(this);
+ mAlertDialog.setView(createView());
+
+ mAlert = mAlertDialog.create();
+ mAlert.show();
+ mHandler.sendEmptyMessageDelayed(MSG_DISMISS_DIALOG, DIALOG_TIME_OUT);
+
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mAlert != null && mAlert.isShowing()) {
+ mAlert.dismiss();
+ }
+ mAlert = null;
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(android.os.Message msg) {
+ switch (msg.what) {
+ case MSG_DISMISS_DIALOG:
+ if (mAlert != null) {
+ mAlert.dismiss();
+ mAlert = null;
+ try {
+ mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ };
+
+ private String getTitleString(Context context, String callingPackage, int uid) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ return context.getString(
+ com.android.internal.R.string.log_access_confirmation_title,
+ pm.getApplicationInfoAsUser(callingPackage,
+ PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ UserHandle.getUserId(uid)).loadLabel(pm));
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "App name is unknown.", e);
+ return null;
+ }
+ }
+
+ private View createView() {
+ final View view = getLayoutInflater().inflate(
+ R.layout.log_access_user_consent_dialog_permission, null /*root*/);
+
+ ((TextView) view.findViewById(R.id.log_access_dialog_title))
+ .setText(mAlertTitle);
+
+ Button button_allow = (Button) view.findViewById(R.id.log_access_dialog_allow_button);
+ button_allow.setOnClickListener(this);
+
+ Button button_deny = (Button) view.findViewById(R.id.log_access_dialog_deny_button);
+ button_deny.setOnClickListener(this);
+
+ return view;
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.log_access_dialog_allow_button:
+ try {
+ mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ finish();
+ break;
+ case R.id.log_access_dialog_deny_button:
+ try {
+ mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
+ }
+ finish();
+ break;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 490e00e..7b63fa2 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -18,15 +18,12 @@
import android.annotation.NonNull;
import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManagerInternal;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
import android.os.ILogd;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -34,16 +31,14 @@
import android.os.logcat.ILogcatManagerService;
import android.util.Slog;
-import com.android.internal.R;
-import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+
/**
* Service responsible for managing the access to Logcat.
*/
@@ -54,43 +49,16 @@
private final BinderService mBinderService;
private final ExecutorService mThreadExecutor;
private ILogd mLogdService;
- private NotificationManager mNotificationManager;
private @NonNull ActivityManager mActivityManager;
private ActivityManagerInternal mActivityManagerInternal;
private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
- private static int sUidImportanceListenerCount = 0;
- private static final int AID_SHELL_UID = 2000;
-
- // TODO This allowlist is just a temporary workaround for the tests:
- // FrameworksServicesTests
- // PlatformRuleTests
- // After adapting the test suites, the allowlist will be removed in
- // the upcoming bug fix patches.
- private static final String[] ALLOWABLE_TESTING_PACKAGES = {
- "android.platform.test.rule.tests",
- "com.android.frameworks.servicestests"
- };
-
- // TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
- private boolean isAllowableTestingPackage(int uid) {
- PackageManager pm = mContext.getPackageManager();
-
- String[] packageNames = pm.getPackagesForUid(uid);
-
- if (ArrayUtils.isEmpty(packageNames)) {
- return false;
- }
-
- for (String name : packageNames) {
- Slog.e(TAG, "isAllowableTestingPackage: " + name);
-
- if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
- return true;
- }
- }
-
- return false;
- };
+ private static final String TARGET_PACKAGE_NAME = "android";
+ private static final String TARGET_ACTIVITY_NAME =
+ "com.android.server.logcat.LogAccessDialogActivity";
+ private static final String EXTRA_UID = "com.android.server.logcat.uid";
+ private static final String EXTRA_GID = "com.android.server.logcat.gid";
+ private static final String EXTRA_PID = "com.android.server.logcat.pid";
+ private static final String EXTRA_FD = "com.android.server.logcat.fd";
private final class BinderService extends ILogcatManagerService.Stub {
@Override
@@ -110,7 +78,7 @@
try {
getLogdService().approve(uid, gid, pid, fd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
@@ -119,7 +87,7 @@
try {
getLogdService().decline(uid, gid, pid, fd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
}
@@ -133,46 +101,16 @@
}
}
- private String getBodyString(Context context, String callingPackage, int uid) {
- PackageManager pm = context.getPackageManager();
- try {
- return context.getString(
- com.android.internal.R.string.log_access_confirmation_body,
- pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
- UserHandle.getUserId(uid)).loadLabel(pm));
- } catch (NameNotFoundException e) {
- // App name is unknown.
- return null;
- }
- }
-
- private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
- int fd) {
-
+ private void showDialog(int uid, int gid, int pid, int fd) {
final ActivityManagerInternal activityManagerInternal =
LocalServices.getService(ActivityManagerInternal.class);
PackageManager pm = mContext.getPackageManager();
String packageName = activityManagerInternal.getPackageNameByPid(pid);
if (packageName != null) {
- String notificationBody = getBodyString(mContext, packageName, uid);
-
- final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
- packageName, null, uid, gid, pid, fd);
-
- if (notificationBody == null) {
- // Decline the logd access if the nofitication body is unknown
- Slog.e(TAG, "Unknown notification body, declining the logd access");
- declineLogdAccess(uid, gid, pid, fd);
- return;
- }
-
- // TODO Next version will replace notification with dialogue
- // per UX guidance.
- generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
- mIntent);
+ Intent mIntent = createIntent(packageName, uid, gid, pid, fd);
+ mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
return;
-
}
String[] packageNames = pm.getPackagesForUid(uid);
@@ -186,115 +124,28 @@
String firstPackageName = packageNames[0];
- if (firstPackageName == null || firstPackageName.length() == 0) {
+ if (firstPackageName.isEmpty() || firstPackageName == null) {
// Decline the logd access if the package name from uid is unknown
Slog.e(TAG, "Unknown calling package name, declining the logd access");
declineLogdAccess(uid, gid, pid, fd);
return;
}
- String notificationBody = getBodyString(mContext, firstPackageName, uid);
-
- final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
- firstPackageName, null, uid, gid, pid, fd);
-
- if (notificationBody == null) {
- Slog.e(TAG, "Unknown notification body, declining the logd access");
- declineLogdAccess(uid, gid, pid, fd);
- return;
- }
-
- // TODO Next version will replace notification with dialogue
- // per UX guidance.
- generateNotificationWithBodyContent(notificationId, clientInfo,
- notificationBody, mIntent);
+ final Intent mIntent = createIntent(firstPackageName, uid, gid, pid, fd);
+ mContext.startActivityAsUser(mIntent, UserHandle.SYSTEM);
}
private void declineLogdAccess(int uid, int gid, int pid, int fd) {
try {
getLogdService().decline(uid, gid, pid, fd);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Fails to call remote functions ", ex);
- }
- }
-
- private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
- String notificationBody, Intent intent) {
- final Notification.Builder notificationBuilder = new Notification.Builder(
- mContext,
- SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
- intent.putExtra("body", notificationBody);
-
- notificationBuilder
- .setSmallIcon(R.drawable.ic_info)
- .setContentTitle(
- mContext.getString(R.string.log_access_confirmation_title))
- .setContentText(notificationBody)
- .setContentIntent(
- PendingIntent.getActivity(mContext, 0, intent,
- PendingIntent.FLAG_IMMUTABLE))
- .setTicker(mContext.getString(R.string.log_access_confirmation_title))
- .setOnlyAlertOnce(true)
- .setAutoCancel(true);
- mNotificationManager.notify(notificationId, notificationBuilder.build());
- }
-
- /**
- * A class which watches an uid for background access and notifies the logdMonitor when
- * the package status becomes foreground (importance change)
- */
- private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
- private final int mExpectedUid;
- private final int mExpectedGid;
- private final int mExpectedPid;
- private final int mExpectedFd;
- private int mExpectedImportance;
- private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
-
- UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
- mExpectedUid = uid;
- mExpectedGid = gid;
- mExpectedPid = pid;
- mExpectedFd = fd;
- mExpectedImportance = importance;
- }
-
- @Override
- public void onUidImportance(int uid, int importance) {
- if (uid == mExpectedUid) {
- mCurrentImportance = importance;
-
- /**
- * 1) If the process status changes to foreground, send a notification
- * for user consent.
- * 2) If the process status remains background, we decline logd access request.
- **/
- if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
- String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
- sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
- mExpectedFd);
- mActivityManager.removeOnUidImportanceListener(this);
-
- synchronized (LogcatManagerService.this) {
- sUidImportanceListenerCount--;
- }
- } else {
- try {
- getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Fails to call remote functions ", ex);
- }
- }
- }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Fails to call remote functions", e);
}
}
private static String getClientInfo(int uid, int gid, int pid, int fd) {
return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
- + Integer.toString(pid) + " FD=" + Integer.toString(fd);
+ + Integer.toString(pid) + " FD=" + Integer.toString(fd);
}
private class LogdMonitor implements Runnable {
@@ -338,18 +189,22 @@
try {
getLogdService().approve(mUid, mGid, mPid, mFd);
} catch (RemoteException e) {
- e.printStackTrace();
+ Slog.e(TAG, "Fails to call remote functions", e);
}
return;
}
- // TODO Temporarily approve all the requests to unblock testing failures.
- try {
- getLogdService().approve(mUid, mGid, mPid, mFd);
- } catch (RemoteException e) {
- e.printStackTrace();
+ final int procState = mActivityManager.getUidImportance(Binder.getCallingUid());
+ // If the process is foreground, send a notification for user consent
+ if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ showDialog(mUid, mGid, mPid, mFd);
+ } else {
+ /**
+ * If the process is background, decline the logd access.
+ **/
+ declineLogdAccess(mUid, mGid, mPid, mFd);
+ return;
}
- return;
}
}
}
@@ -360,7 +215,6 @@
mBinderService = new BinderService();
mThreadExecutor = Executors.newCachedThreadPool();
mActivityManager = context.getSystemService(ActivityManager.class);
- mNotificationManager = mContext.getSystemService(NotificationManager.class);
}
@Override
@@ -375,4 +229,23 @@
private void addLogdService() {
mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
}
+
+ /**
+ * Create the Intent for LogAccessDialogActivity.
+ */
+ public Intent createIntent(String targetPackageName, int uid, int gid, int pid, int fd) {
+ final Intent intent = new Intent();
+
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
+ intent.putExtra(EXTRA_UID, uid);
+ intent.putExtra(EXTRA_GID, gid);
+ intent.putExtra(EXTRA_PID, pid);
+ intent.putExtra(EXTRA_FD, fd);
+
+ intent.setComponent(new ComponentName(TARGET_PACKAGE_NAME, TARGET_ACTIVITY_NAME));
+
+ return intent;
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d65dc13..265ad7d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1623,18 +1623,6 @@
}
};
- @VisibleForTesting
- final IAppOpsCallback mAppOpsCallback = new IAppOpsCallback.Stub() {
- @Override public void opChanged(int op, int uid, String packageName) {
- if (mEnableAppSettingMigration) {
- int opValue = mAppOps.checkOpNoThrow(
- AppOpsManager.OP_POST_NOTIFICATION, uid, packageName);
- boolean blocked = op != MODE_ALLOWED;
- sendAppBlockStateChangedBroadcast(packageName, uid, blocked);
- }
- }
- };
-
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -2133,12 +2121,6 @@
mUsageStatsManagerInternal = usageStatsManagerInternal;
mAppOps = appOps;
mAppOpsService = iAppOps;
- try {
- mAppOpsService.startWatchingMode(
- AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not register OP_POST_NOTIFICATION listener");
- }
mAppUsageStats = appUsageStats;
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
mCompanionManager = companionManager;
@@ -3409,6 +3391,7 @@
}
mPermissionHelper.setNotificationPermission(
pkg, UserHandle.getUserId(uid), enabled, true);
+ sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
} else {
synchronized (mNotificationLock) {
boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 6a2b2d5..76d3d23 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -29,7 +29,6 @@
import android.apex.IApexService;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.content.pm.parsing.result.ParseResult;
@@ -834,7 +833,7 @@
throw new RuntimeException(re);
} catch (Exception e) {
throw new PackageManagerException(
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"apexd verification failed : " + e.getMessage());
}
}
@@ -861,7 +860,7 @@
throw new RuntimeException(re);
} catch (Exception e) {
throw new PackageManagerException(
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to mark apexd session as ready : " + e.getMessage());
}
}
diff --git a/services/core/java/com/android/server/pm/ApkChecksums.java b/services/core/java/com/android/server/pm/ApkChecksums.java
index aa467e7..2824585 100644
--- a/services/core/java/com/android/server/pm/ApkChecksums.java
+++ b/services/core/java/com/android/server/pm/ApkChecksums.java
@@ -34,6 +34,7 @@
import android.content.pm.ApkChecksum;
import android.content.pm.Checksum;
import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
@@ -62,6 +63,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.security.VerityUtils;
+import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.ByteArrayOutputStream;
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index c24bfec..5013570 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -36,7 +36,6 @@
import android.os.storage.VolumeInfo;
import android.security.AndroidKeyStoreMaintenance;
import android.system.keystore2.Domain;
-import android.system.keystore2.KeyDescriptor;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -555,26 +554,6 @@
return prepareAppDataFuture;
}
- public void migrateKeyStoreData(int previousAppId, int appId) {
- // If previous UID is system UID, declaring inheritKeyStoreKeys is not supported.
- // Silently ignore the request to migrate keys.
- if (previousAppId == Process.SYSTEM_UID) return;
-
- for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
- int srcUid = UserHandle.getUid(userId, previousAppId);
- int destUid = UserHandle.getUid(userId, appId);
- final KeyDescriptor[] keys = AndroidKeyStoreMaintenance.listEntries(Domain.APP, srcUid);
- if (keys == null) continue;
- for (final KeyDescriptor key : keys) {
- KeyDescriptor dest = new KeyDescriptor();
- dest.domain = Domain.APP;
- dest.nspace = destUid;
- dest.alias = key.alias;
- AndroidKeyStoreMaintenance.migrateKeyNamespace(key, dest);
- }
- }
- }
-
void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
return;
diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java
new file mode 100644
index 0000000..bbef237
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 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;
+
+import android.os.Process;
+
+import com.android.server.utils.WatchedSparseArray;
+
+/**
+ * A wrapper over {@link WatchedSparseArray} that tracks the current maximum App ID.
+ */
+public class AppIdSettingMap extends WatchedSparseArray<SettingBase> {
+ private int mCurrentMaxAppId;
+
+ @Override
+ public void put(int key, SettingBase value) {
+ if (key > mCurrentMaxAppId) {
+ mCurrentMaxAppId = key;
+ }
+ super.put(key, value);
+ }
+
+ @Override
+ public AppIdSettingMap snapshot() {
+ AppIdSettingMap l = new AppIdSettingMap();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * @return the maximum of all the App IDs that have been added to the map. 0 if map is empty.
+ */
+ public int getCurrentMaxAppId() {
+ return mCurrentMaxAppId;
+ }
+
+ /**
+ * @return the next available App ID that has not been added to the map
+ */
+ public int getNextAvailableAppId() {
+ if (mCurrentMaxAppId == 0) {
+ // No app id has been added yet
+ return Process.FIRST_APPLICATION_UID;
+ } else {
+ return mCurrentMaxAppId + 1;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index d117967..7b2dc28 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -52,6 +52,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.QuadFunction;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.android.server.compat.CompatChange;
import com.android.server.om.OverlayReferenceMapper;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -486,12 +487,12 @@
}
/** Builder method for an AppsFilter */
- public static AppsFilter create(
- PackageManagerInternal pms, PackageManagerServiceInjector injector) {
+ public static AppsFilter create(@NonNull PackageManagerServiceInjector injector,
+ @NonNull PackageManagerInternal pmInt) {
final boolean forceSystemAppsQueryable =
injector.getContext().getResources()
.getBoolean(R.bool.config_forceSystemPackagesQueryable);
- final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector);
+ final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pmInt, injector);
final String[] forcedQueryablePackageNames;
if (forceSystemAppsQueryable) {
// all system apps already queryable, no need to read and parse individual exceptions
@@ -512,7 +513,7 @@
};
AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig,
forcedQueryablePackageNames, forceSystemAppsQueryable, null,
- injector.getBackgroundExecutor(), pms);
+ injector.getBackgroundExecutor(), pmInt);
featureConfig.setAppsFilter(appsFilter);
return appsFilter;
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index ecbb4a9..9ff4aab 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -19,6 +19,7 @@
import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
@@ -269,7 +270,7 @@
PackageManagerService pm = mInjector.getPackageManagerService();
ArraySet<String> packagesToOptimize;
if (packageNames == null) {
- packagesToOptimize = mDexOptHelper.getOptimizablePackages();
+ packagesToOptimize = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
} else {
packagesToOptimize = new ArraySet<>(packageNames);
}
@@ -334,7 +335,7 @@
return false;
}
- ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages();
+ ArraySet<String> pkgs = mDexOptHelper.getOptimizablePackages(pm.snapshotComputer());
if (pkgs.isEmpty()) {
Slog.i(TAG, "No packages to optimize");
markPostBootUpdateCompleted(params);
@@ -556,8 +557,8 @@
}
/** Gets the size of a package. */
- private long getPackageSize(PackageManagerService pm, String pkg) {
- PackageInfo info = pm.snapshotComputer().getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ private long getPackageSize(@NonNull Computer snapshot, String pkg) {
+ PackageInfo info = snapshot.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
long size = 0;
if (info != null && info.applicationInfo != null) {
File path = Paths.get(info.applicationInfo.sourceDir).toFile();
@@ -605,8 +606,9 @@
Slog.d(TAG, "Should Downgrade " + shouldDowngrade);
}
if (shouldDowngrade) {
+ final Computer snapshot = pm.snapshotComputer();
Set<String> unusedPackages =
- pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+ snapshot.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
if (DEBUG) {
Slog.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
}
@@ -618,7 +620,7 @@
// Should be aborted by the scheduler.
return abortCode;
}
- @DexOptResult int downgradeResult = downgradePackage(pm, pkg,
+ @DexOptResult int downgradeResult = downgradePackage(snapshot, pm, pkg,
/* isForPrimaryDex= */ true, isPostBootUpdate);
if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
@@ -629,7 +631,7 @@
return status;
}
if (supportSecondaryDex) {
- downgradeResult = downgradePackage(pm, pkg,
+ downgradeResult = downgradePackage(snapshot, pm, pkg,
/* isForPrimaryDex= */false, isPostBootUpdate);
status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
if (status != STATUS_OK) {
@@ -696,8 +698,8 @@
* @return PackageDexOptimizer.DEX_*
*/
@DexOptResult
- private int downgradePackage(PackageManagerService pm, String pkg, boolean isForPrimaryDex,
- boolean isPostBootUpdate) {
+ private int downgradePackage(@NonNull Computer snapshot, PackageManagerService pm, String pkg,
+ boolean isForPrimaryDex, boolean isPostBootUpdate) {
if (DEBUG) {
Slog.d(TAG, "Downgrading " + pkg);
}
@@ -709,15 +711,15 @@
if (!isPostBootUpdate) {
dexoptFlags |= DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB;
}
- long package_size_before = getPackageSize(pm, pkg);
+ long package_size_before = getPackageSize(snapshot, pkg);
int result = PackageDexOptimizer.DEX_OPT_SKIPPED;
if (isForPrimaryDex || PLATFORM_PACKAGE_NAME.equals(pkg)) {
// This applies for system apps or if packages location is not a directory, i.e.
// monolithic install.
- if (!pm.canHaveOatDir(pkg)) {
+ if (!pm.canHaveOatDir(snapshot, pkg)) {
// For apps that don't have the oat directory, instead of downgrading,
// remove their compiler artifacts from dalvik cache.
- pm.deleteOatArtifactsOfPackage(pkg);
+ pm.deleteOatArtifactsOfPackage(snapshot, pkg);
} else {
result = performDexOptPrimary(pkg, reason, dexoptFlags);
}
@@ -726,8 +728,9 @@
}
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
+ final Computer newSnapshot = pm.snapshotComputer();
FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
- getPackageSize(pm, pkg), /*aggressive=*/ false);
+ getPackageSize(newSnapshot, pkg), /*aggressive=*/ false);
}
return result;
}
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index df7387d..f1394d4 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -119,14 +119,10 @@
intent.setPackage(targetPkg);
}
// Modify the UID when posting to other users
- final String[] uidExtraNames =
- { Intent.EXTRA_UID, Intent.EXTRA_PREVIOUS_UID, Intent.EXTRA_NEW_UID };
- for (String name : uidExtraNames) {
- int uid = intent.getIntExtra(name, -1);
- if (uid >= 0 && UserHandle.getUserId(uid) != userId) {
- uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
- intent.putExtra(name, uid);
- }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0 && UserHandle.getUserId(uid) != userId) {
+ uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+ intent.putExtra(Intent.EXTRA_UID, uid);
}
if (broadcastAllowList != null && PLATFORM_PACKAGE_NAME.equals(targetPkg)) {
intent.putExtra(Intent.EXTRA_VISIBILITY_ALLOW_LIST,
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 6103d68..8e85301 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -58,10 +58,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import java.util.List;
import java.util.Set;
@@ -92,92 +88,69 @@
* and other managers (like PermissionManager) mean deadlock is possible. On the
* other hand, not overriding in {@link ComputerLocked} may leave a function walking
* unstable data.
- *
- * To coax developers to consider such issues carefully, all methods in
- * {@link Computer} must be annotated with <code>@LiveImplementation(override =
- * MANDATORY)</code> or <code>LiveImplementation(locked = NOT_ALLOWED)</code>. A unit
- * test verifies the annotation and that the annotation corresponds to the code in
- * {@link ComputerEngine} and {@link ComputerLocked}.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public interface Computer extends PackageDataSnapshot {
/**
- * Every method must be annotated.
- */
- @Target({ ElementType.METHOD })
- @Retention(RetentionPolicy.RUNTIME)
- @interface LiveImplementation {
- // A Computer method must be annotated with one of the following values:
- // MANDATORY - the method must be overridden in ComputerEngineLive. The
- // format of the override is a call to the super method, wrapped in a
- // synchronization block.
- // NOT_ALLOWED - the method may not appear in the live computer. It must
- // be final in the ComputerEngine.
- int MANDATORY = 1;
- int NOT_ALLOWED = 2;
- int override() default MANDATORY;
- String rationale() default "";
- }
-
- /**
* Administrative statistics: record that the snapshot has been used. Every call
* to use() increments the usage counter.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
default void use() {
}
/**
* Fetch the snapshot usage counter.
* @return The number of times this snapshot was used.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
default int getUsed() {
return 0;
}
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
@PackageManager.ResolveInfoFlagsBits long flags,
@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent, String resolvedType,
long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
@NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent, String resolvedType,
long flags, int userId, int callingUid, boolean includeInstantApps);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
@NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(Intent intent,
String resolvedType, long flags, int filterCallingUid, int userId,
boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
String instantAppPkgName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ActivityInfo getActivityInfo(ComponentName component, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Important: The provided filterCallingUid is used exclusively to filter out activities
+ * that can be seen based on user state. It's typically the original caller uid prior
+ * to clearing. Because it can only be provided by trusted code, its value can be
+ * trusted and will be used as-is; unlike userId which will be validated by this method.
+ */
ActivityInfo getActivityInfoInternal(ComponentName component, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
AndroidPackage getPackage(String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
AndroidPackage getPackage(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ApplicationInfo generateApplicationInfoFromSettings(String packageName, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ApplicationInfo getApplicationInfo(String packageName, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Important: The provided filterCallingUid is used exclusively to filter out applications
+ * that can be seen based on user state. It's typically the original caller uid prior
+ * to clearing. Because it can only be provided by trusted code, its value can be
+ * trusted and will be used as-is; unlike userId which will be validated by this method.
+ */
ApplicationInfo getApplicationInfoInternal(String packageName, long flags,
int filterCallingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
ComponentName getDefaultHomeActivity(int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent, String resolvedType,
long flags, int sourceUserId, int parentUserId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
Intent getHomeIntent();
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
String resolvedType, int userId);
@@ -192,15 +165,11 @@
* @param intent
* @return A filtered list of resolved activities.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
List<ResolveInfo> applyPostResolutionFilter(@NonNull List<ResolveInfo> resolveInfos,
String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
boolean resolveForStart, int userId, Intent intent);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo generatePackageInfo(PackageStateInternal ps, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfo(String packageName, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageInfo getPackageInfoInternal(String packageName, long versionCode, long flags,
int filterCallingUid, int userId);
@@ -209,79 +178,69 @@
* known {@link PackageState} instances without a {@link PackageState#getAndroidPackage()}
* will not be represented.
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
String[] getAllAvailablePackageNames();
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageStateInternal getPackageStateInternal(String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
PackageStateInternal getPackageStateInternal(String packageName, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
- @Nullable PackageState getPackageStateCopied(@NonNull String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
int sourceUserId, int targetUserId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
ServiceInfo getServiceInfo(ComponentName component, long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
SharedLibraryInfo getSharedLibraryInfo(String name, long version);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
String getInstantAppPackageName(int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String resolveExternalPackageName(AndroidPackage pkg);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String resolveInternalPackageName(String packageName, long versionCode);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
String[] getPackagesForUid(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
UserInfo getProfileParent(int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean canViewInstantApps(int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid, int userId,
long flags);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isCallerSameApp(String packageName, int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
@PackageManager.ComponentType int type);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
- boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+
+ /**
+ * From Android R, camera intents have to match system apps. The only exception to this is if
+ * the DPC has set the camera persistent preferred activity. This case was introduced
+ * because it is important that the DPC has the ability to set both system and non-system
+ * camera persistent preferred activities.
+ *
+ * @return {@code true} if the intent is a camera intent and the persistent preferred
+ * activity was not set by the DPC.
+ */
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent, int userId,
String resolvedType, long flags);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isInstantApp(String packageName, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isInstantAppInternal(String packageName, @UserIdInt int userId, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
@Nullable ComponentName component, @PackageManager.ComponentType int componentType,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@Nullable PackageStateInternal ps, int callingUid,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
boolean shouldFilterApplication(@NonNull SharedUserSetting sus, int callingUid,
int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
int checkUidPermission(String permName, int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
int getPackageUidInternal(String packageName, long flags, int userId, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForApplication(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForComponent(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForPackage(long flags, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Update given flags when being used to request {@link ResolveInfo}.
+ * <p>Instant apps are resolved specially, depending upon context. Minimally,
+ * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
+ * flag set. However, this flag is only honoured in three circumstances:
+ * <ul>
+ * <li>when called from a system process</li>
+ * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
+ * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
+ * action and a {@code android.intent.category.BROWSABLE} category</li>
+ * </ul>
+ */
long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
boolean isImplicitImageCaptureIntentAndNotSetByDpc);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
long updateFlagsForResolve(long flags, int userId, int callingUid, boolean wantInstantApps,
boolean onlyExposedExplicitly, boolean isImplicitImageCaptureIntentAndNotSetByDpc);
@@ -299,117 +258,99 @@
* @param checkShell whether to prevent shell from access if there's a debugging restriction
* @param message the message to log on security exception
*/
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
+
+ /**
+ * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
+ * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
+ *
+ * @param checkShell whether to prevent shell from access if there's a debugging restriction
+ * @param message the message to log on security exception
+ */
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
boolean requirePermissionWhenSameUser, String message);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(@NonNull String packageName);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
SigningDetails getSigningDetails(int uid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(String packageName, int callingUid, int userId);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
boolean filterAppAccess(int uid, int callingUid);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
Intent intent, String resolvedType, long flags, List<ResolveInfo> query, boolean always,
boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
- @Computer.LiveImplementation(override = Computer.LiveImplementation.NOT_ALLOWED)
- ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, long flags,
+ ResolveInfo findPersistentPreferredActivity(Intent intent, String resolvedType, long flags,
List<ResolveInfo> query, boolean debug, int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
PreferredIntentResolver getPreferredActivities(@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArrayMap<String, ? extends PackageStateInternal> getPackageStates();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getRenamedPackage(@NonNull String packageName);
/**
* @return set of packages to notify
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManagerService.PackageStartability
int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageAvailable(String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] currentToCanonicalPackageNames(@NonNull String[] names);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] canonicalToCurrentPackageNames(@NonNull String[] names);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
int[] getPackageGids(@NonNull String packageName,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getTargetSdkVersion(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
@NonNull ComponentName component, @NonNull Intent intent, String resolvedType);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ActivityInfo getReceiverInfo(@NonNull ComponentName component,
@PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
int userId, boolean throwIfPermNotDeclared);
- @Computer.LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ /**
+ * Returns true if the system or user is explicitly preventing an otherwise valid installer to
+ * complete an install. This includes checks like unknown sources and user restrictions.
+ */
boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
@PackageManager.PackageInfoFlagsBits long flags, int callingUid, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
@NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo getProviderInfo(@NonNull ComponentName component,
@PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String[] getSystemSharedLibraryNames();
@@ -417,136 +358,103 @@
* @return the state if the given package has a state and isn't filtered by visibility.
* Provides no guarantee that the package is in any usable state.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int checkSignatures(@NonNull String pkg1, @NonNull String pkg2);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int checkUidSignatures(int uid1, int uid2);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
@PackageManager.CertificateInputType int type);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<String> getAllPackages();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getNameForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String[] getNamesForUids(@NonNull int[] uids);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getUidForSharedUser(@NonNull String sharedUserName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getFlagsForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getPrivateFlagsForUid(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isUidPrivileged(int uid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] getAppOpPermissionPackages(@NonNull String permissionName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(@NonNull String[] permissions,
@PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<ApplicationInfo> getInstalledApplications(
@PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo resolveContentProvider(@NonNull String name,
@PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId, int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
@NonNull String visibleAuthority);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
@NonNull List<ProviderInfo> outInfo);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName, int uid,
@PackageManager.ComponentInfoFlagsBits long flags, @Nullable String metaDataKey);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<InstrumentationInfo> queryInstrumentation(
@NonNull String targetPackage, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<PackageStateInternal> findSharedNonSystemLibraries(
@NonNull PackageStateInternal pkgSetting);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getApplicationHiddenSettingAsUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName, @UserIdInt int[] userIds,
boolean isInstantApp);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
String getInstallerPackageName(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
InstallSourceInfo getInstallSourceInfo(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.EnabledState
int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
@UserIdInt int userId);
@@ -557,25 +465,19 @@
* are all effectively enabled for the given component. Or if the component cannot be found,
* returns false.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
KeySet getSigningKeySet(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId);
@@ -585,49 +487,37 @@
* package visibility filtering is enabled on it. If the UID is part of a shared user ID,
* return {@code true} if any one application belongs to the shared user ID meets the criteria.
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canQueryPackage(int callingUid, @Nullable String targetPackageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getPackageUid(@NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@PackageManager.InstallReason
int getInstallReason(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canPackageQuery(@NonNull String sourcePackageName, @NonNull String targetPackageName,
@UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
@UserIdInt int sourceUserId, @UserIdInt int targetUserId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
SparseArray<String> getAppsWithSharedUserIds();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] getSharedUserPackagesForPackage(@NonNull String packageName, @UserIdInt int userId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
Set<String> getUnusedPackages(long downgradeTimeThresholdMillis);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId);
@@ -638,55 +528,49 @@
*
* @return The filtered packages
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
String[] filterOnlySystemPackages(@Nullable String... pkgNames);
// The methods in this block should be removed once SettingBase is interface snapshotted
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
List<AndroidPackage> getPackagesForAppId(int appId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
int getUidTargetSdkVersion(int uid);
/**
* @see PackageManagerInternal#getProcessesForUid(int)
*/
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
// End block
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
SharedUserApi getSharedUser(int sharedUserAppIde);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@NonNull
ComponentResolverApi getComponentResolver();
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
PackageStateInternal getDisabledSystemPackage(@NonNull String packageName);
- @Computer.LiveImplementation(override = LiveImplementation.MANDATORY)
@Nullable
ResolveInfo getInstantAppInstallerInfo();
+
+ @NonNull
+ WatchedArrayMap<String, Integer> getFrozenPackages();
+
+ @Nullable
+ ComponentName getInstantAppInstallerComponent();
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 0c9855b..06e827a 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -466,7 +466,7 @@
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
flags));
List<ResolveInfo> list = Collections.emptyList();
boolean skipPostResolution = false;
@@ -1722,15 +1722,6 @@
return mSettings.getPackage(packageName);
}
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- int callingUid = Binder.getCallingUid();
- packageName = resolveInternalPackageNameInternalLocked(
- packageName, PackageManager.VERSION_CODE_HIGHEST, callingUid);
- PackageStateInternal pkgSetting = mSettings.getPackage(packageName);
- return pkgSetting == null ? null : PackageStateImpl.copy(pkgSetting);
- }
-
public final ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
final int callingUid = Binder.getCallingUid();
if (getInstantAppPackageName(callingUid) != null) {
@@ -2468,7 +2459,7 @@
* @return {@code true} if the intent is a camera intent and the persistent preferred
* activity was not set by the DPC.
*/
- public final boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
+ public final boolean isImplicitImageCaptureIntentAndNotSetByDpc(Intent intent,
int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
intent, userId, resolvedType, flags);
@@ -3228,12 +3219,12 @@
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
// Try to find a matching persistent preferred activity.
- result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+ result.mPreferredResolveInfo = findPersistentPreferredActivity(intent,
resolvedType, flags, query, debug, userId);
// If a persistent preferred activity matched, use it.
@@ -3444,7 +3435,7 @@
userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
}
- public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ public final ResolveInfo findPersistentPreferredActivity(Intent intent,
String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
List<ResolveInfo> query, boolean debug, int userId) {
final int n = query.size();
@@ -5418,7 +5409,7 @@
}
long flags = updateFlagsForResolve(0, parent.id, callingUid,
false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+ isImplicitImageCaptureIntentAndNotSetByDpc(intent, parent.id,
resolvedType, 0));
flags |= PackageManager.MATCH_DEFAULT_ONLY;
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
@@ -5694,4 +5685,17 @@
public ResolveInfo getInstantAppInstallerInfo() {
return mInstantAppInstallerInfo;
}
+
+ @NonNull
+ @Override
+ public WatchedArrayMap<String, Integer> getFrozenPackages() {
+ return mFrozenPackages;
+ }
+
+ @Nullable
+ @Override
+ public ComponentName getInstantAppInstallerComponent() {
+ return mLocalInstantAppInstallerActivity == null
+ ? null : mLocalInstantAppInstallerActivity.getComponentName();
+ }
}
diff --git a/services/core/java/com/android/server/pm/ComputerLocked.java b/services/core/java/com/android/server/pm/ComputerLocked.java
index 5d89c7d..af196d5 100644
--- a/services/core/java/com/android/server/pm/ComputerLocked.java
+++ b/services/core/java/com/android/server/pm/ComputerLocked.java
@@ -16,62 +16,21 @@
package com.android.server.pm;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-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.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
/**
* This subclass is the external interface to the live computer. Some internal helper
- * methods are overridden to fetch live data instead of snapshot data. For each
- * Computer interface that is overridden in this class, the override takes the PM lock
- * and then delegates to the live computer engine. This is required because there are
- * no locks taken in the engine itself.
+ * methods are overridden to fetch live data instead of snapshot data.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public final class ComputerLocked extends ComputerEngine {
- private final Object mLock;
ComputerLocked(PackageManagerService.Snapshot args) {
super(args);
- mLock = mService.mLock;
}
protected ComponentName resolveComponentName() {
@@ -83,814 +42,4 @@
protected ApplicationInfo androidApplication() {
return mService.getCoreAndroidApplication();
}
-
- public @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
- String resolvedType, int flags, int userId, int callingUid,
- String instantAppPkgName) {
- synchronized (mLock) {
- return super.queryIntentServicesInternalBody(intent, resolvedType, flags, userId,
- callingUid, instantAppPkgName);
- }
- }
- public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
- Intent intent, String resolvedType, long flags, int filterCallingUid, int userId,
- boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
- String instantAppPkgName) {
- synchronized (mLock) {
- return super.queryIntentActivitiesInternalBody(intent, resolvedType, flags,
- filterCallingUid, userId, resolveForStart, allowDynamicSplits, pkgName,
- instantAppPkgName);
- }
- }
- public ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
- int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getActivityInfoInternalBody(component, flags, filterCallingUid,
- userId);
- }
- }
- public AndroidPackage getPackage(String packageName) {
- synchronized (mLock) {
- return super.getPackage(packageName);
- }
- }
- public AndroidPackage getPackage(int uid) {
- synchronized (mLock) {
- return super.getPackage(uid);
- }
- }
- public ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
- int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getApplicationInfoInternalBody(packageName, flags, filterCallingUid,
- userId);
- }
- }
- public ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
- Intent intent, int matchFlags, List<ResolveInfo> candidates,
- CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
- synchronized (mLock) {
- return super.filterCandidatesWithDomainPreferredActivitiesLPrBody(intent,
- matchFlags, candidates, xpDomainInfo, userId, debug);
- }
- }
- public PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
- int flags, int filterCallingUid, int userId) {
- synchronized (mLock) {
- return super.getPackageInfoInternalBody(packageName, versionCode, flags,
- filterCallingUid, userId);
- }
- }
-
- @Override
- public String[] getAllAvailablePackageNames() {
- synchronized (mLock) {
- return super.getAllAvailablePackageNames();
- }
- }
-
- public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- synchronized (mLock) {
- return super.getPackageStateInternal(packageName, callingUid);
- }
- }
-
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getPackageStateCopied(packageName);
- }
- }
-
- public ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getInstalledPackagesBody(flags, userId, callingUid);
- }
- }
- public ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getServiceInfoBody(component, flags, userId, callingUid);
- }
- }
- public String getInstantAppPackageName(int callingUid) {
- synchronized (mLock) {
- return super.getInstantAppPackageName(callingUid);
- }
- }
- public String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
- boolean isCallerInstantApp) {
- synchronized (mLock) {
- return super.getPackagesForUidInternalBody(callingUid, userId, appId,
- isCallerInstantApp);
- }
- }
- public boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.isInstantAppInternalBody(packageName, userId, callingUid);
- }
- }
- public boolean isInstantAppResolutionAllowedBody(Intent intent,
- List<ResolveInfo> resolvedActivities, int userId, boolean skipPackageCheck,
- int flags) {
- synchronized (mLock) {
- return super.isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
- skipPackageCheck, flags);
- }
- }
- public int getPackageUidInternal(String packageName, int flags, int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getPackageUidInternal(packageName, flags, userId, callingUid);
- }
- }
- public SigningDetails getSigningDetails(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getSigningDetails(packageName);
- }
- }
- public SigningDetails getSigningDetails(int uid) {
- synchronized (mLock) {
- return super.getSigningDetails(uid);
- }
- }
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- synchronized (mLock) {
- return super.filterAppAccess(pkg, callingUid, userId);
- }
- }
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- synchronized (mLock) {
- return super.filterAppAccess(packageName, callingUid, userId);
- }
- }
- public boolean filterAppAccess(int uid, int callingUid) {
- synchronized (mLock) {
- return super.filterAppAccess(uid, callingUid);
- }
- }
- public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- synchronized (mLock) {
- super.dump(type, fd, pw, dumpState);
- }
- }
- public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityBody(
- Intent intent, String resolvedType, int flags, List<ResolveInfo> query, boolean always,
- boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
- int callingUid, boolean isDeviceProvisioned) {
- synchronized (mLock) {
- return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
- removeMatches, debug, userId, queryMayBeFiltered, callingUid,
- isDeviceProvisioned);
- }
- }
-
- @Override
- public PreferredIntentResolver getPreferredActivities(int userId) {
- synchronized (mLock) {
- return super.getPreferredActivities(userId);
- }
- }
-
- @NonNull
- @Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- synchronized (mLock) {
- return super.getPackageStates();
- }
- }
-
- @Nullable
- @Override
- public String getRenamedPackage(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getRenamedPackage(packageName);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
- synchronized (mLock) {
- return super.getNotifyPackagesForReplacedReceived(packages);
- }
- }
-
- @Override
- public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageStartability(safeMode, packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isPackageAvailable(packageName, userId);
- }
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- synchronized (mLock) {
- return super.currentToCanonicalPackageNames(names);
- }
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- synchronized (mLock) {
- return super.canonicalToCurrentPackageNames(names);
- }
- }
-
- @Override
- public int[] getPackageGids(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageGids(packageName, flags, userId);
- }
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getTargetSdkVersion(packageName);
- }
- }
-
- @Override
- public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
- synchronized (mLock) {
- return super.activitySupportsIntent(resolveComponentName, component, intent,
- resolvedType);
- }
- }
-
- @Nullable
- @Override
- public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getReceiverInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
- @UserIdInt int userId, boolean throwIfPermNotDeclared) {
- synchronized (mLock) {
- return super.canRequestPackageInstalls(packageName, callingUid, userId,
- throwIfPermNotDeclared);
- }
- }
-
- @Override
- public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
- @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getDeclaredSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getProviderInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- synchronized (mLock) {
- return super.getSystemSharedLibraryNames();
- }
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1,
- @NonNull String pkg2) {
- synchronized (mLock) {
- return super.checkSignatures(pkg1, pkg2);
- }
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- synchronized (mLock) {
- return super.checkUidSignatures(uid1, uid2);
- }
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- int type) {
- synchronized (mLock) {
- return super.hasSigningCertificate(packageName, certificate, type);
- }
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
- synchronized (mLock) {
- return super.hasUidSigningCertificate(uid, certificate, type);
- }
- }
-
- @Override
- public List<String> getAllPackages() {
- synchronized (mLock) {
- return super.getAllPackages();
- }
- }
-
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- synchronized (mLock) {
- return super.getNameForUid(uid);
- }
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(int[] uids) {
- synchronized (mLock) {
- return super.getNamesForUids(uids);
- }
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- synchronized (mLock) {
- return super.getUidForSharedUser(sharedUserName);
- }
- }
-
- @Override
- public int getFlagsForUid(int uid) {
- synchronized (mLock) {
- return super.getFlagsForUid(uid);
- }
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- synchronized (mLock) {
- return super.getPrivateFlagsForUid(uid);
- }
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- synchronized (mLock) {
- return super.isUidPrivileged(uid);
- }
- }
-
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- synchronized (mLock) {
- return super.getAppOpPermissionPackages(permissionName);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackagesHoldingPermissions(permissions, flags, userId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.getInstalledApplications(flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo resolveContentProvider(@NonNull String name,
- @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- synchronized (mLock) {
- return super.resolveContentProvider(name, flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
- @NonNull String visibleAuthority) {
- synchronized (mLock) {
- return super.getGrantImplicitAccessProviderInfo(recipientUid, visibleAuthority);
- }
- }
-
- @Override
- public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
- @NonNull List<ProviderInfo> outInfo) {
- synchronized (mLock) {
- super.querySyncProviders(safeMode, outNames, outInfo);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- synchronized (mLock) {
- return super.queryContentProviders(processName, uid, flags, metaDataKey);
- }
- }
-
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- synchronized (mLock) {
- return super.getInstrumentationInfo(component, flags);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- synchronized (mLock) {
- return super.queryInstrumentation(targetPackage, flags);
- }
- }
-
- @NonNull
- @Override
- public List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- synchronized (mLock) {
- return super.findSharedNonSystemLibraries(pkgSetting);
- }
- }
-
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getApplicationHiddenSettingAsUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isPackageSuspendedForUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isSuspendingAnyPackages(suspendingPackage, userId);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getAllIntentFilters(packageName);
- }
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getBlockUninstallForUser(packageName, userId);
- }
- }
-
- @Nullable
- @Override
- public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- synchronized (mLock) {
- return super.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getInstallerPackageName(packageName);
- }
- }
-
- @Nullable
- @Override
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getInstallSourceInfo(packageName);
- }
- }
-
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getApplicationEnabledSetting(packageName, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getComponentEnabledSetting(component, callingUid, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getComponentEnabledSettingInternal(component, callingUid, userId);
- }
- }
-
- @Override
- public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.isComponentEffectivelyEnabled(componentInfo, userId);
- }
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- synchronized (mLock) {
- return super.getKeySetByAlias(packageName, alias);
- }
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getSigningKeySet(packageName);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- synchronized (mLock) {
- return super.isPackageSignedByKeySet(packageName, ks);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- synchronized (mLock) {
- return super.isPackageSignedByKeySetExactly(packageName, ks);
- }
- }
-
- @Nullable
- @Override
- public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getVisibilityAllowList(packageName, userId);
- }
- }
-
- @Override
- public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- synchronized (mLock) {
- return super.canQueryPackage(callingUid, targetPackageName);
- }
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageUid(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.canAccessComponent(callingUid, component, userId);
- }
- }
-
- @Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- synchronized (mLock) {
- return super.isCallerInstallerOfRecord(pkg, callingUid);
- }
- }
-
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getInstallReason(packageName, userId);
- }
- }
-
- @Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
- }
-
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- synchronized (mLock) {
- return super.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
- synchronized (mLock) {
- return super.getPersistentApplications(safeMode, flags);
- }
- }
-
- @NonNull
- @Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- synchronized (mLock) {
- return super.getAppsWithSharedUserIds();
- }
- }
-
- @NonNull
- @Override
- public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getSharedUserPackagesForPackage(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- synchronized (mLock) {
- return super.getUnusedPackages(downgradeTimeThresholdMillis);
- }
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getHarmfulAppWarning(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
- synchronized (mLock) {
- return super.filterOnlySystemPackages(pkgNames);
- }
- }
-
- @NonNull
- @Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- synchronized (mLock) {
- return super.getPackagesForAppId(appId);
- }
- }
-
- @Override
- public int getUidTargetSdkVersion(int uid) {
- synchronized (mLock) {
- return super.getUidTargetSdkVersion(uid);
- }
- }
-
- @Nullable
- @Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- synchronized (mLock) {
- return super.getProcessesForUid(uid);
- }
- }
-
- @Override
- public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- synchronized (mLock) {
- return super.getPackageStateFiltered(packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
- synchronized (mLock) {
- return super.getBlockUninstall(userId, packageName);
- }
- }
-
- @NonNull
- @Override
- public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
- synchronized (mLock) {
- return super.getSharedLibraries();
- }
- }
-
- @Nullable
- @Override
- public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
- synchronized (mLock) {
- return super.getPackageOrSharedUser(appId);
- }
- }
-
- @Nullable
- @Override
- public SharedUserApi getSharedUser(int sharedUserAppId) {
- synchronized (mLock) {
- return super.getSharedUser(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- synchronized (mLock) {
- return super.getSharedUserPackages(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ComponentResolverApi getComponentResolver() {
- synchronized (mLock) {
- return super.getComponentResolver();
- }
- }
-
- @Nullable
- @Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- synchronized (mLock) {
- return super.getDisabledSystemPackage(packageName);
- }
- }
-
- @Nullable
- @Override
- public ResolveInfo getInstantAppInstallerInfo() {
- synchronized (mLock) {
- return super.getInstantAppInstallerInfo();
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/ComputerTracker.java b/services/core/java/com/android/server/pm/ComputerTracker.java
deleted file mode 100644
index 216ad71..0000000
--- a/services/core/java/com/android/server/pm/ComputerTracker.java
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*
- * Copyright (C) 2021 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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.InstallSourceInfo;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ProcessInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SharedLibraryInfo;
-import android.content.pm.SigningDetails;
-import android.content.pm.UserInfo;
-import android.content.pm.VersionedPackage;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Pair;
-import android.util.SparseArray;
-
-import com.android.server.pm.parsing.pkg.AndroidPackage;
-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.resolution.ComponentResolverApi;
-import com.android.server.utils.WatchedArrayMap;
-import com.android.server.utils.WatchedLongSparseArray;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * This subclass delegates to methods in a Computer after reference-counting the computer.
- */
-public final class ComputerTracker implements Computer {
-
- // The number of times a thread reused a computer in its stack instead of fetching
- // a snapshot computer.
- private final AtomicInteger mReusedSnapshot = new AtomicInteger(0);
-
- private final PackageManagerService mService;
- ComputerTracker(PackageManagerService s) {
- mService = s;
- }
-
- private ThreadComputer snapshot() {
- ThreadComputer current = PackageManagerService.sThreadComputer.get();
- if (current.mRefCount > 0) {
- current.acquire();
- mReusedSnapshot.incrementAndGet();
- } else {
- current.acquire(mService.snapshotComputer());
- }
- return current;
- }
-
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,
- int filterCallingUid, int userId, boolean resolveForStart,
- boolean allowDynamicSplits) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
- privateResolveFlags, filterCallingUid, userId, resolveForStart,
- allowDynamicSplits);
- } finally {
- current.release();
- }
- }
- public @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternal(intent, resolvedType, flags,
- userId);
- } finally {
- current.release();
- }
- }
- public @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
- int callingUid, boolean includeInstantApps) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentServicesInternal(intent, resolvedType, flags,
- userId, callingUid, includeInstantApps);
- } finally {
- current.release();
- }
- }
- public @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits,
- String pkgName, String instantAppPkgName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.queryIntentActivitiesInternalBody(intent, resolvedType,
- flags, filterCallingUid, userId, resolveForStart, allowDynamicSplits,
- pkgName, instantAppPkgName);
- } finally {
- current.release();
- }
- }
- public ActivityInfo getActivityInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getActivityInfo(component, flags, userId);
- } finally {
- current.release();
- }
- }
- public ActivityInfo getActivityInfoInternal(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getActivityInfoInternal(component, flags, filterCallingUid,
- userId);
- } finally {
- current.release();
- }
- }
- public AndroidPackage getPackage(String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackage(packageName);
- } finally {
- current.release();
- }
- }
- public AndroidPackage getPackage(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackage(uid);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo generateApplicationInfoFromSettings(String packageName,
- long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.generateApplicationInfoFromSettings(packageName, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo getApplicationInfo(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getApplicationInfo(packageName, flags, userId);
- } finally {
- current.release();
- }
- }
- public ApplicationInfo getApplicationInfoInternal(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getApplicationInfoInternal(packageName, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public ComponentName getDefaultHomeActivity(int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getDefaultHomeActivity(userId);
- } finally {
- current.release();
- }
- }
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getHomeActivitiesAsUser(allHomeCandidates, userId);
- } finally {
- current.release();
- }
- }
- public CrossProfileDomainInfo getCrossProfileDomainPreferredLpr(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int sourceUserId,
- int parentUserId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getCrossProfileDomainPreferredLpr(intent, resolvedType,
- flags, sourceUserId, parentUserId);
- } finally {
- current.release();
- }
- }
- public Intent getHomeIntent() {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getHomeIntent();
- } finally {
- current.release();
- }
- }
- public List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(
- Intent intent, String resolvedType, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getMatchingCrossProfileIntentFilters(intent, resolvedType,
- userId);
- } finally {
- current.release();
- }
- }
- public List<ResolveInfo> applyPostResolutionFilter(
- @NonNull List<ResolveInfo> resolveInfos,
- String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid,
- boolean resolveForStart, int userId, Intent intent) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.applyPostResolutionFilter(resolveInfos, ephemeralPkgName,
- allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
- } finally {
- current.release();
- }
- }
- public PackageInfo generatePackageInfo(PackageStateInternal ps,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.generatePackageInfo(ps, flags, userId);
- } finally {
- current.release();
- }
- }
- public PackageInfo getPackageInfo(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageInfo(packageName, flags, userId);
- } finally {
- current.release();
- }
- }
- public PackageInfo getPackageInfoInternal(String packageName, long versionCode,
- long flags, int filterCallingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageInfoInternal(packageName, versionCode, flags,
- filterCallingUid, userId);
- } finally {
- current.release();
- }
- }
- public PackageStateInternal getPackageStateInternal(String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateInternal(packageName);
- } finally {
- current.release();
- }
- }
- public PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateInternal(packageName, callingUid);
- } finally {
- current.release();
- }
- }
-
- @Nullable
- public PackageState getPackageStateCopied(@NonNull String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageStateCopied(packageName);
- } finally {
- current.release();
- }
- }
-
- public ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getInstalledPackages(flags, userId);
- } finally {
- current.release();
- }
- }
- public ResolveInfo createForwardingResolveInfoUnchecked(WatchedIntentFilter filter,
- int sourceUserId, int targetUserId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.createForwardingResolveInfoUnchecked(filter, sourceUserId,
- targetUserId);
- } finally {
- current.release();
- }
- }
- public ServiceInfo getServiceInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getServiceInfo(component, flags, userId);
- } finally {
- current.release();
- }
- }
- public SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSharedLibraryInfo(name, version);
- } finally {
- current.release();
- }
- }
- public SigningDetails getSigningDetails(@NonNull String packageName) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSigningDetails(packageName);
- } finally {
- current.release();
- }
- }
- public SigningDetails getSigningDetails(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getSigningDetails(uid);
- } finally {
- current.release();
- }
- }
- public String getInstantAppPackageName(int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getInstantAppPackageName(callingUid);
- } finally {
- current.release();
- }
- }
- public String resolveExternalPackageName(AndroidPackage pkg) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.resolveExternalPackageName(pkg);
- } finally {
- current.release();
- }
- }
- public String resolveInternalPackageName(String packageName, long versionCode) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.resolveInternalPackageName(packageName, versionCode);
- } finally {
- current.release();
- }
- }
- public String[] getPackagesForUid(int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackagesForUid(uid);
- } finally {
- current.release();
- }
- }
- public UserInfo getProfileParent(int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getProfileParent(userId);
- } finally {
- current.release();
- }
- }
- public boolean canViewInstantApps(int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.canViewInstantApps(callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(pkg, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(packageName, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean filterAppAccess(int uid, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterAppAccess(uid, callingUid);
- } finally {
- current.release();
- }
- }
- public boolean filterSharedLibPackage(@Nullable PackageStateInternal ps, int uid,
- int userId, @PackageManager.ComponentInfoFlagsBits long flags) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.filterSharedLibPackage(ps, uid, userId, flags);
- } finally {
- current.release();
- }
- }
- public boolean isCallerSameApp(String packageName, int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isCallerSameApp(packageName, uid);
- } finally {
- current.release();
- }
- }
- public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isComponentVisibleToInstantApp(component);
- } finally {
- current.release();
- }
- }
- public boolean isComponentVisibleToInstantApp(@Nullable ComponentName component,
- @PackageManager.ComponentType int type) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isComponentVisibleToInstantApp(component, type);
- } finally {
- current.release();
- }
- }
- public boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent,
- int userId, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent,
- userId, resolvedType, flags);
- } finally {
- current.release();
- }
- }
- public boolean isInstantApp(String packageName, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isInstantApp(packageName, userId);
- } finally {
- current.release();
- }
- }
- public boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
- int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isInstantAppInternal(packageName, userId, callingUid);
- } finally {
- current.release();
- }
- }
- public boolean isSameProfileGroup(@UserIdInt int callerUserId,
- @UserIdInt int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.isSameProfileGroup(callerUserId, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
- int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(sus, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
- int callingUid, @Nullable ComponentName component,
- @PackageManager.ComponentType int componentType, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(ps, callingUid, component,
- componentType, userId);
- } finally {
- current.release();
- }
- }
- public boolean shouldFilterApplication(@Nullable PackageStateInternal ps,
- int callingUid, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.shouldFilterApplication(ps, callingUid, userId);
- } finally {
- current.release();
- }
- }
- public int checkUidPermission(String permName, int uid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.checkUidPermission(permName, uid);
- } finally {
- current.release();
- }
- }
- public int getPackageUidInternal(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.getPackageUidInternal(packageName, flags, userId,
- callingUid);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForApplication(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForApplication(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForComponent(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForComponent(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForPackage(long flags, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForPackage(flags, userId);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
- } finally {
- current.release();
- }
- }
- public long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly,
- boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, onlyExposedExplicitly,
- isImplicitImageCaptureIntentAndNotSetByDpc);
- } finally {
- current.release();
- }
- }
- public void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.dump(type, fd, pw, dumpState);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- } finally {
- current.release();
- }
- }
- public void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell,
- boolean requirePermissionWhenSameUser, String message) {
- ThreadComputer current = snapshot();
- try {
- current.mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, requirePermissionWhenSameUser, message);
- } finally {
- current.release();
- }
- }
- public PackageManagerService.FindPreferredActivityBodyResult findPreferredActivityInternal(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
- int userId, boolean queryMayBeFiltered) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
- query, always, removeMatches, debug, userId, queryMayBeFiltered);
- } finally {
- current.release();
- }
- }
- public ResolveInfo findPersistentPreferredActivityLP(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean debug, int userId) {
- ThreadComputer current = snapshot();
- try {
- return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
- flags, query, debug, userId);
- } finally {
- current.release();
- }
- }
-
- @Override
- public String[] getAllAvailablePackageNames() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllAvailablePackageNames();
- }
- }
-
- @Override
- public PreferredIntentResolver getPreferredActivities(int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPreferredActivities(userId);
- }
- }
-
- @NonNull
- @Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStates();
- }
- }
-
- @Nullable
- @Override
- public String getRenamedPackage(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getRenamedPackage(packageName);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<String> getNotifyPackagesForReplacedReceived(@NonNull String[] packages) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNotifyPackagesForReplacedReceived(packages);
- }
- }
-
- @Override
- public int getPackageStartability(boolean safeMode, @NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStartability(safeMode, packageName, callingUid,
- userId);
- }
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageAvailable(packageName, userId);
- }
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.currentToCanonicalPackageNames(names);
- }
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canonicalToCurrentPackageNames(names);
- }
- }
-
- @Override
- public int[] getPackageGids(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageGids(packageName, flags, userId);
- }
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getTargetSdkVersion(packageName);
- }
- }
-
- @Override
- public boolean activitySupportsIntent(@NonNull ComponentName resolveComponentName,
- @NonNull ComponentName component, @NonNull Intent intent, String resolvedType) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.activitySupportsIntent(resolveComponentName, component, intent,
- resolvedType);
- }
- }
-
- @Nullable
- @Override
- public ActivityInfo getReceiverInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getReceiverInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canRequestPackageInstalls(@NonNull String packageName, int callingUid,
- @UserIdInt int userId, boolean throwIfPermNotDeclared) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canRequestPackageInstalls(packageName, callingUid, userId,
- throwIfPermNotDeclared);
- }
- }
-
- @Override
- public boolean isInstallDisabledForPackage(@NonNull String packageName, int uid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isInstallDisabledForPackage(packageName, uid, userId);
- }
- }
-
- @Override
- public List<VersionedPackage> getPackagesUsingSharedLibrary(@NonNull SharedLibraryInfo libInfo,
- @PackageManager.PackageInfoFlagsBits long flags, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid,
- userId);
- }
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getProviderInfo(component, flags, userId);
- }
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSystemSharedLibraryNames();
- }
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1,
- @NonNull String pkg2) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.checkSignatures(pkg1, pkg2);
- }
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.checkUidSignatures(uid1, uid2);
- }
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- int type) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.hasSigningCertificate(packageName, certificate, type);
- }
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate, int type) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.hasUidSigningCertificate(uid, certificate, type);
- }
- }
-
- @Override
- public List<String> getAllPackages() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllPackages();
- }
- }
-
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNameForUid(uid);
- }
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(int[] uids) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getNamesForUids(uids);
- }
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUidForSharedUser(sharedUserName);
- }
- }
-
- @Override
- public int getFlagsForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getFlagsForUid(uid);
- }
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPrivateFlagsForUid(uid);
- }
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isUidPrivileged(uid);
- }
- }
-
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAppOpPermissionPackages(permissionName);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstalledApplications(flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo resolveContentProvider(@NonNull String name,
- @PackageManager.ResolveInfoFlagsBits long flags, @UserIdInt int userId,
- int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.resolveContentProvider(name, flags, userId, callingUid);
- }
- }
-
- @Nullable
- @Override
- public ProviderInfo getGrantImplicitAccessProviderInfo(int recipientUid,
- @NonNull String visibleAuthority) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getGrantImplicitAccessProviderInfo(recipientUid,
- visibleAuthority);
- }
- }
-
- @Override
- public void querySyncProviders(boolean safeMode, @NonNull List<String> outNames,
- @NonNull List<ProviderInfo> outInfo) {
- try (ThreadComputer current = snapshot()) {
- current.mComputer.querySyncProviders(safeMode, outNames, outInfo);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
- }
- }
-
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstrumentationInfo(component, flags);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.queryInstrumentation(targetPackage, flags);
- }
- }
-
- @NonNull
- @Override
- public List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.findSharedNonSystemLibraries(pkgSetting);
- }
- }
-
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSuspendedForUser(packageName, userId);
- }
- }
-
- @Override
- public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
- }
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAllIntentFilters(packageName);
- }
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBlockUninstallForUser(packageName, userId);
- }
- }
-
- @Nullable
- @Override
- public SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallerPackageName(packageName);
- }
- }
-
- @Nullable
- @Override
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallSourceInfo(packageName);
- }
- }
-
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getApplicationEnabledSetting(packageName, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentEnabledSetting(component, callingUid, userId);
- }
- }
-
- @Override
- public int getComponentEnabledSettingInternal(@NonNull ComponentName component, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentEnabledSettingInternal(
- component, callingUid, userId);
- }
- }
-
- @Override
- public boolean isComponentEffectivelyEnabled(@NonNull ComponentInfo componentInfo,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isComponentEffectivelyEnabled(componentInfo, userId);
- }
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getKeySetByAlias(packageName, alias);
- }
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSigningKeySet(packageName);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSignedByKeySet(packageName, ks);
- }
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isPackageSignedByKeySetExactly(packageName, ks);
- }
- }
-
- @Nullable
- @Override
- public int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getVisibilityAllowList(packageName, userId);
- }
- }
-
- @Override
- public boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canQueryPackage(callingUid, targetPackageName);
- }
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageUid(packageName, flags, userId);
- }
- }
-
- @Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canAccessComponent(callingUid, component, userId);
- }
- }
-
- @Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.isCallerInstallerOfRecord(pkg, callingUid);
- }
- }
-
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstallReason(packageName, userId);
- }
- }
-
- @Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
- }
-
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
- }
-
- @NonNull
- @Override
- public List<ApplicationInfo> getPersistentApplications(boolean safeMode, int flags) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPersistentApplications(safeMode, flags);
- }
- }
-
- @NonNull
- @Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getAppsWithSharedUserIds();
- }
- }
-
- @NonNull
- @Override
- public String[] getSharedUserPackagesForPackage(@NonNull String packageName,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUserPackagesForPackage(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
- }
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getHarmfulAppWarning(packageName, userId);
- }
- }
-
- @NonNull
- @Override
- public String[] filterOnlySystemPackages(@Nullable String... pkgNames) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.filterOnlySystemPackages(pkgNames);
- }
- }
-
- @NonNull
- @Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackagesForAppId(appId);
- }
- }
-
- @Override
- public int getUidTargetSdkVersion(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getUidTargetSdkVersion(uid);
- }
- }
-
- @Nullable
- @Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getProcessesForUid(uid);
- }
- }
-
- @Override
- public PackageStateInternal getPackageStateFiltered(@NonNull String packageName, int callingUid,
- @UserIdInt int userId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageStateFiltered(packageName, callingUid, userId);
- }
- }
-
- @Override
- public boolean getBlockUninstall(@UserIdInt int userId, @NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getBlockUninstall(userId, packageName);
- }
- }
-
- @NonNull
- @Override
- public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedLibraries();
- }
- }
-
- @Nullable
- @Override
- public Pair<PackageStateInternal, SharedUserApi> getPackageOrSharedUser(int appId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getPackageOrSharedUser(appId);
- }
- }
-
- @Nullable
- @Override
- public SharedUserApi getSharedUser(int sharedUserAppId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUser(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getSharedUserPackages(sharedUserAppId);
- }
- }
-
- @NonNull
- @Override
- public ComponentResolverApi getComponentResolver() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getComponentResolver();
- }
- }
-
- @Nullable
- @Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getDisabledSystemPackage(packageName);
- }
- }
-
- @Nullable
- @Override
- public ResolveInfo getInstantAppInstallerInfo() {
- try (ThreadComputer current = snapshot()) {
- return current.mComputer.getInstantAppInstallerInfo();
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index a9dc0f3..0e1c1ad 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -147,6 +147,7 @@
final SparseArray<TempUserState> priorUserStates;
/** enabled state of the uninstalled application */
synchronized (mPm.mLock) {
+ final Computer computer = mPm.snapshotComputer();
uninstalledPs = mPm.mSettings.getPackageLPr(packageName);
if (uninstalledPs == null) {
Slog.w(TAG, "Not removing non-existent package " + packageName);
@@ -170,10 +171,10 @@
if (pkg != null) {
SharedLibraryInfo libraryInfo = null;
if (pkg.getStaticSharedLibName() != null) {
- libraryInfo = mPm.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
+ libraryInfo = computer.getSharedLibraryInfo(pkg.getStaticSharedLibName(),
pkg.getStaticSharedLibVersion());
} else if (pkg.getSdkLibName() != null) {
- libraryInfo = mPm.getSharedLibraryInfo(pkg.getSdkLibName(),
+ libraryInfo = computer.getSharedLibraryInfo(pkg.getSdkLibName(),
pkg.getSdkLibVersionMajor());
}
@@ -183,7 +184,7 @@
continue;
}
List<VersionedPackage> libClientPackages =
- mPm.getPackagesUsingSharedLibrary(libraryInfo,
+ computer.getPackagesUsingSharedLibrary(libraryInfo,
MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId);
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
@@ -243,9 +244,7 @@
if (res) {
final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;
info.sendPackageRemovedBroadcasts(killApp, removedBySystem);
- if (disabledSystemPs != null) {
- info.sendSystemPackageUpdatedBroadcasts(disabledSystemPs.getAppId());
- }
+ info.sendSystemPackageUpdatedBroadcasts();
}
// Force a gc to clear up things.
@@ -456,11 +455,11 @@
if (affectedUserIds == null) {
affectedUserIds = mPm.resolveUserIds(userId);
}
+ final Computer snapshot = mPm.snapshotComputer();
for (final int affectedUserId : affectedUserIds) {
if (hadSuspendAppsPermission.get(affectedUserId)) {
- mPm.unsuspendForSuspendingPackage(mPm.snapshotComputer(), packageName,
- affectedUserId);
- mPm.removeAllDistractingPackageRestrictions(affectedUserId);
+ mPm.unsuspendForSuspendingPackage(snapshot, packageName, affectedUserId);
+ mPm.removeAllDistractingPackageRestrictions(snapshot, affectedUserId);
}
}
@@ -603,9 +602,6 @@
if (outInfo != null) {
// Delete the updated package
outInfo.mIsRemovedPackageSystemUpdate = true;
- if (disabledPs.getAppId() != deletedPs.getAppId()) {
- outInfo.mNewAppId = disabledPs.getAppId();
- }
}
if (disabledPs.getVersionCode() < deletedPs.getVersionCode()
@@ -626,7 +622,8 @@
final int callingUid = Binder.getCallingUid();
mPm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
- final boolean canViewInstantApps = mPm.canViewInstantApps(callingUid, userId);
+ final Computer snapshot = mPm.snapshotComputer();
+ final boolean canViewInstantApps = snapshot.canViewInstantApps(callingUid, userId);
Preconditions.checkNotNull(versionedPackage);
Preconditions.checkNotNull(observer);
Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
@@ -649,12 +646,13 @@
}
// Normalize package name to handle renamed packages and static libs
- final String internalPackageName = mPm.resolveInternalPackageName(packageName, versionCode);
+ final String internalPackageName =
+ snapshot.resolveInternalPackageName(packageName, versionCode);
final int uid = Binder.getCallingUid();
- if (!isOrphaned(internalPackageName)
+ if (!isOrphaned(snapshot, internalPackageName)
&& !allowSilentUninstall
- && !isCallerAllowedToSilentlyUninstall(uid, internalPackageName)) {
+ && !isCallerAllowedToSilentlyUninstall(snapshot, uid, internalPackageName)) {
mPm.mHandler.post(() -> {
try {
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
@@ -685,8 +683,7 @@
return;
}
- if (!deleteAllUsers && mPm.mIPackageManager
- .getBlockUninstallForUser(internalPackageName, userId)) {
+ if (!deleteAllUsers && snapshot.getBlockUninstallForUser(internalPackageName, userId)) {
mPm.mHandler.post(() -> {
try {
observer.onPackageDeleted(packageName,
@@ -761,44 +758,45 @@
});
}
- private boolean isOrphaned(String packageName) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+ private boolean isOrphaned(@NonNull Computer snapshot, String packageName) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
return packageState != null && packageState.getInstallSource().isOrphaned;
}
- private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
+ private boolean isCallerAllowedToSilentlyUninstall(@NonNull Computer snapshot, int callingUid,
+ String pkgName) {
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return true;
}
final int callingUserId = UserHandle.getUserId(callingUid);
// If the caller installed the pkgName, then allow it to silently uninstall.
- if (callingUid == mPm.mIPackageManager.getPackageUid(
- mPm.mIPackageManager.getInstallerPackageName(pkgName), 0, callingUserId)) {
+ if (callingUid == snapshot.getPackageUid(snapshot.getInstallerPackageName(pkgName), 0,
+ callingUserId)) {
return true;
}
// Allow package verifier to silently uninstall.
- if (mPm.mRequiredVerifierPackage != null && callingUid == mPm.mIPackageManager
+ if (mPm.mRequiredVerifierPackage != null && callingUid == snapshot
.getPackageUid(mPm.mRequiredVerifierPackage, 0, callingUserId)) {
return true;
}
// Allow package uninstaller to silently uninstall.
- if (mPm.mRequiredUninstallerPackage != null && callingUid == mPm.mIPackageManager
+ if (mPm.mRequiredUninstallerPackage != null && callingUid == snapshot
.getPackageUid(mPm.mRequiredUninstallerPackage, 0, callingUserId)) {
return true;
}
// Allow storage manager to silently uninstall.
- if (mPm.mStorageManagerPackage != null && callingUid == mPm.mIPackageManager.getPackageUid(
+ if (mPm.mStorageManagerPackage != null && callingUid == snapshot.getPackageUid(
mPm.mStorageManagerPackage, 0, callingUserId)) {
return true;
}
// Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
// uninstall for device owner provisioning.
- return mPm.mIPackageManager.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+ return snapshot.checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
== PERMISSION_GRANTED;
}
@@ -904,8 +902,8 @@
int installedForUsersCount = 0;
synchronized (mPm.mLock) {
// Normalize package name to handle renamed packages and static libs
- final String internalPkgName = mPm.resolveInternalPackageName(packageName,
- versionCode);
+ final String internalPkgName = mPm.snapshotComputer()
+ .resolveInternalPackageName(packageName, versionCode);
final PackageSetting ps = mPm.mSettings.getPackageLPr(internalPkgName);
if (ps != null) {
int[] installedUsers = ps.queryInstalledUsers(mUserManagerInternal.getUserIds(),
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 74ea7cc..50b2e23 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -266,8 +266,9 @@
return;
}
+ final Computer snapshot = mPm.snapshotComputer();
List<PackageStateInternal> pkgSettings =
- getPackagesForDexopt(mPm.getPackageStates().values(), mPm);
+ getPackagesForDexopt(snapshot.getPackageStates().values(), mPm);
List<AndroidPackage> pkgs = new ArrayList<>(pkgSettings.size());
for (int index = 0; index < pkgSettings.size(); index++) {
@@ -282,17 +283,19 @@
final int elapsedTimeSeconds =
(int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
+ final Computer newSnapshot = mPm.snapshotComputer();
+
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_dexopted", stats[0]);
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_skipped", stats[1]);
MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_failed", stats[2]);
- MetricsLogger.histogram(
- mPm.mContext, "opt_dialog_num_total", getOptimizablePackages().size());
+ MetricsLogger.histogram(mPm.mContext, "opt_dialog_num_total",
+ getOptimizablePackages(newSnapshot).size());
MetricsLogger.histogram(mPm.mContext, "opt_dialog_time_s", elapsedTimeSeconds);
}
- public ArraySet<String> getOptimizablePackages() {
+ public ArraySet<String> getOptimizablePackages(@NonNull Computer snapshot) {
ArraySet<String> pkgs = new ArraySet<>();
- mPm.forEachPackageState(packageState -> {
+ mPm.forEachPackageState(snapshot, packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
pkgs.add(packageState.getPackageName());
@@ -302,10 +305,10 @@
}
/*package*/ boolean performDexOpt(DexoptOptions options) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final Computer snapshot = mPm.snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
- } else if (mPm.mIPackageManager.isInstantApp(options.getPackageName(),
- UserHandle.getCallingUserId())) {
+ } else if (snapshot.isInstantApp(options.getPackageName(), UserHandle.getCallingUserId())) {
return false;
}
@@ -417,10 +420,10 @@
mPm.getDexManager().getPackageUseInfoOrDefault(p.getPackageName()), options);
}
- public void forceDexOpt(String packageName) {
+ public void forceDexOpt(@NonNull Computer snapshot, String packageName) {
PackageManagerServiceUtils.enforceSystemOrRoot("forceDexOpt");
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
final AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (packageState == null || pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
@@ -485,19 +488,21 @@
ArrayList<PackageStateInternal> sortTemp = new ArrayList<>(remainingPkgSettings.size());
+ final Computer snapshot = packageManagerService.snapshotComputer();
+
// Give priority to core apps.
- applyPackageFilter(pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
+ applyPackageFilter(snapshot, pkgSetting -> pkgSetting.getPkg().isCoreApp(), result,
remainingPkgSettings, sortTemp, packageManagerService);
// Give priority to system apps that listen for pre boot complete.
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
- applyPackageFilter(pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
+ applyPackageFilter(snapshot, pkgSetting -> pkgNames.contains(pkgSetting.getPackageName()), result,
remainingPkgSettings, sortTemp, packageManagerService);
// Give priority to apps used by other apps.
DexManager dexManager = packageManagerService.getDexManager();
- applyPackageFilter(pkgSetting ->
+ applyPackageFilter(snapshot, pkgSetting ->
dexManager.getPackageUseInfoOrDefault(pkgSetting.getPackageName())
.isAnyCodePathUsedByOtherApps(),
result, remainingPkgSettings, sortTemp, packageManagerService);
@@ -535,7 +540,7 @@
// No historical info. Take all.
remainingPredicate = pkgSetting -> true;
}
- applyPackageFilter(remainingPredicate, result, remainingPkgSettings, sortTemp,
+ applyPackageFilter(snapshot, remainingPredicate, result, remainingPkgSettings, sortTemp,
packageManagerService);
if (debug) {
@@ -550,7 +555,7 @@
// package will be removed from {@code packages} and added to {@code result} with its
// dependencies. If usage data is available, the positive packages will be sorted by usage
// data (with {@code sortTemp} as temporary storage).
- private static void applyPackageFilter(
+ private static void applyPackageFilter(@NonNull Computer snapshot,
Predicate<PackageStateInternal> filter,
Collection<PackageStateInternal> result,
Collection<PackageStateInternal> packages,
@@ -568,8 +573,7 @@
for (PackageStateInternal pkgSetting : sortTemp) {
result.add(pkgSetting);
- List<PackageStateInternal> deps =
- packageManagerService.findSharedNonSystemLibraries(pkgSetting);
+ List<PackageStateInternal> deps = snapshot.findSharedNonSystemLibraries(pkgSetting);
if (!deps.isEmpty()) {
deps.removeAll(result);
result.addAll(deps);
diff --git a/services/core/java/com/android/server/pm/DomainVerificationConnection.java b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
index db8c6dc..20e4dd8 100644
--- a/services/core/java/com/android/server/pm/DomainVerificationConnection.java
+++ b/services/core/java/com/android/server/pm/DomainVerificationConnection.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Message;
import android.os.UserHandle;
@@ -35,13 +34,10 @@
public final class DomainVerificationConnection implements DomainVerificationService.Connection,
DomainVerificationProxyV1.Connection, DomainVerificationProxyV2.Connection {
final PackageManagerService mPm;
- final PackageManagerInternal mPmInternal;
final UserManagerInternal mUmInternal;
- // TODO(b/198166813): remove PMS dependency
DomainVerificationConnection(PackageManagerService pm) {
mPm = pm;
- mPmInternal = mPm.mInjector.getLocalService(PackageManagerInternal.class);
mUmInternal = mPm.mInjector.getLocalService(UserManagerInternal.class);
}
@@ -82,18 +78,18 @@
@Override
public boolean isCallerPackage(int callingUid, @NonNull String packageName) {
final int callingUserId = UserHandle.getUserId(callingUid);
- return callingUid == mPmInternal.getPackageUid(packageName, 0, callingUserId);
+ return callingUid == mPm.snapshotComputer().getPackageUid(packageName, 0, callingUserId);
}
@Nullable
@Override
public AndroidPackage getPackage(@NonNull String packageName) {
- return mPmInternal.getPackage(packageName);
+ return mPm.snapshotComputer().getPackage(packageName);
}
@Override
public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return mPmInternal.filterAppAccess(packageName, callingUid, userId);
+ return mPm.snapshotComputer().filterAppAccess(packageName, callingUid, userId);
}
@Override
@@ -108,6 +104,6 @@
@NonNull
public Computer snapshot() {
- return (Computer) mPmInternal.snapshot();
+ return mPm.snapshotComputer();
}
}
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 05ef3c4..f83ef5a 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -55,6 +55,7 @@
@NeverCompile // Avoid size overhead of debugging code.
public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final Computer snapshot = mPm.snapshotComputer();
DumpState dumpState = new DumpState();
ArraySet<String> permissionNames = null;
@@ -121,7 +122,7 @@
}
// Normalize package name to handle renamed packages and static libs
- pkg = mPm.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
+ pkg = snapshot.resolveInternalPackageName(pkg, PackageManager.VERSION_CODE_HIGHEST);
pw.println(mPm.checkPermission(perm, pkg, user));
return;
@@ -243,7 +244,7 @@
// Return if the package doesn't exist.
if (packageName != null
- && mPm.getPackageStateInternal(packageName) == null
+ && snapshot.getPackageStateInternal(packageName) == null
&& !mPm.mApexManager.isApexPackage(packageName)) {
pw.println("Unable to find package: " + packageName);
return;
@@ -257,7 +258,7 @@
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_VERSION)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_VERSION, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
}
if (!checkin
@@ -273,7 +274,7 @@
final String knownPackage = PackageManagerInternal.knownPackageToString(i);
ipw.print(knownPackage);
ipw.println(":");
- final String[] pkgNames = mPm.getKnownPackageNamesInternal(i,
+ final String[] pkgNames = mPm.getKnownPackageNamesInternal(snapshot, i,
UserHandle.USER_SYSTEM);
ipw.increaseIndent();
if (ArrayUtils.isEmpty(pkgNames)) {
@@ -288,8 +289,6 @@
ipw.decreaseIndent();
}
- final Computer snapshot = mPm.snapshotComputer();
-
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
&& packageName == null) {
final String requiredVerifierPackage = mPm.mRequiredVerifierPackage;
@@ -343,7 +342,7 @@
if (dumpState.isDumping(DumpState.DUMP_LIBS)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_LIBS, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_FEATURES)
@@ -389,17 +388,17 @@
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
- mPm.dumpComputer(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
&& packageName == null) {
- mPm.dumpComputer(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
- mPm.dumpComputer(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
@@ -429,7 +428,7 @@
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_QUERIES)) {
- mPm.dumpComputer(DumpState.DUMP_QUERIES, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
@@ -529,12 +528,12 @@
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
- mPm.dumpComputer(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
}
if (!checkin
&& dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
- mPm.dumpComputer(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
+ snapshot.dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
@@ -581,7 +580,7 @@
pw.println(" Known digesters list flag: "
+ PackageManagerService.getKnownDigestersList());
- PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts();
+ PerUidReadTimeouts[] items = mPm.getPerUidReadTimeouts(snapshot);
pw.println(" Timeouts (" + items.length + "):");
for (PerUidReadTimeouts item : items) {
pw.print(" (");
diff --git a/services/core/java/com/android/server/pm/IPackageManagerBase.java b/services/core/java/com/android/server/pm/IPackageManagerBase.java
new file mode 100644
index 0000000..e1aee6d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/IPackageManagerBase.java
@@ -0,0 +1,1189 @@
+/*
+ * Copyright (C) 2022 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;
+
+
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.IPackageDeleteObserver2;
+import android.content.pm.IPackageInstaller;
+import android.content.pm.IPackageManager;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstallSourceInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.SharedLibraryInfo;
+import android.content.pm.VersionedPackage;
+import android.content.pm.dex.IArtManager;
+import android.os.Binder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.permission.PermissionManager;
+
+import com.android.internal.R;
+import com.android.internal.content.InstallLocationUtils;
+import com.android.internal.util.CollectionUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
+import com.android.server.pm.verify.domain.proxy.DomainVerificationProxyV1;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Contains all simply proxy methods which need a snapshot instance and just calls a method on it,
+ * with no additional logic. Separated with all methods marked final and deprecated to prevent their
+ * use from other methods which may need a snapshot for non-trivial reasons.
+ */
+public abstract class IPackageManagerBase extends IPackageManager.Stub {
+
+ @NonNull
+ private final PackageManagerService mService;
+
+ @NonNull
+ private final Context mContext;
+
+ @NonNull private final DexOptHelper mDexOptHelper;
+ @NonNull private final ModuleInfoProvider mModuleInfoProvider;
+ @NonNull private final PreferredActivityHelper mPreferredActivityHelper;
+ @NonNull private final ResolveIntentHelper mResolveIntentHelper;
+
+ @NonNull
+ private final DomainVerificationManagerInternal mDomainVerificationManager;
+
+ @NonNull
+ private final DomainVerificationConnection mDomainVerificationConnection;
+
+ @NonNull
+ private final PackageInstallerService mInstallerService;
+
+ @NonNull
+ private final PackageProperty mPackageProperty;
+
+ @NonNull
+ private final ComponentName mResolveComponentName;
+
+ @Nullable
+ private final ComponentName mInstantAppResolverSettingsComponent;
+
+ @NonNull
+ private final String mRequiredSupplementalProcessPackage;
+
+ @Nullable
+ private final String mServicesExtensionPackageName;
+
+ @Nullable
+ private final String mSharedSystemSharedLibraryPackageName;
+
+ public IPackageManagerBase(@NonNull PackageManagerService service, @NonNull Context context,
+ @NonNull DexOptHelper dexOptHelper, @NonNull ModuleInfoProvider moduleInfoProvider,
+ @NonNull PreferredActivityHelper preferredActivityHelper,
+ @NonNull ResolveIntentHelper resolveIntentHelper,
+ @NonNull DomainVerificationManagerInternal domainVerificationManager,
+ @NonNull DomainVerificationConnection domainVerificationConnection,
+ @NonNull PackageInstallerService installerService,
+ @NonNull PackageProperty packageProperty, @NonNull ComponentName resolveComponentName,
+ @Nullable ComponentName instantAppResolverSettingsComponent,
+ @NonNull String requiredSupplementalProcessPackage,
+ @Nullable String servicesExtensionPackageName,
+ @Nullable String sharedSystemSharedLibraryPackageName) {
+ mService = service;
+ mContext = context;
+ mDexOptHelper = dexOptHelper;
+ mModuleInfoProvider = moduleInfoProvider;
+ mPreferredActivityHelper = preferredActivityHelper;
+ mResolveIntentHelper = resolveIntentHelper;
+ mDomainVerificationManager = domainVerificationManager;
+ mDomainVerificationConnection = domainVerificationConnection;
+ mInstallerService = installerService;
+ mPackageProperty = packageProperty;
+ mResolveComponentName = resolveComponentName;
+ mInstantAppResolverSettingsComponent = instantAppResolverSettingsComponent;
+ mRequiredSupplementalProcessPackage = requiredSupplementalProcessPackage;
+ mServicesExtensionPackageName = servicesExtensionPackageName;
+ mSharedSystemSharedLibraryPackageName = sharedSystemSharedLibraryPackageName;
+ }
+
+ protected Computer snapshot() {
+ return mService.snapshotComputer();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean activitySupportsIntent(ComponentName component, Intent intent,
+ String resolvedType) {
+ return snapshot().activitySupportsIntent(mResolveComponentName, component, intent,
+ resolvedType);
+ }
+
+ @Override
+ @Deprecated
+ public final void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
+ int sourceUserId, int targetUserId, int flags) {
+ mService.addCrossProfileIntentFilter(snapshot(),
+ new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId,
+ flags);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final boolean addPermission(PermissionInfo info) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final boolean addPermissionAsync(PermissionInfo info) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
+ }
+
+ @Override
+ @Deprecated
+ public final void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+ int userId) {
+ mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
+ activity, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void addPreferredActivity(IntentFilter filter, int match,
+ ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
+ mPreferredActivityHelper.addPreferredActivity(snapshot(),
+ new WatchedIntentFilter(filter), match, set, activity, true, userId,
+ "Adding preferred", removeExisting);
+ }
+
+ /*
+ * Returns if intent can be forwarded from the sourceUserId to the targetUserId
+ */
+ @Override
+ @Deprecated
+ public final boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
+ @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
+ return snapshot().canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canRequestPackageInstalls(String packageName, int userId) {
+ return snapshot().canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
+ true /* throwIfPermNotDeclared*/);
+ }
+
+ @Override
+ @Deprecated
+ public final String[] canonicalToCurrentPackageNames(String[] names) {
+ return snapshot().canonicalToCurrentPackageNames(names);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final int checkPermission(String permName, String pkgName, int userId) {
+ return mService.checkPermission(permName, pkgName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
+ return snapshot().checkSignatures(pkg1, pkg2);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkUidPermission(String permName, int uid) {
+ return snapshot().checkUidPermission(permName, uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int checkUidSignatures(int uid1, int uid2) {
+ return snapshot().checkUidSignatures(uid1, uid2);
+ }
+
+ @Override
+ @Deprecated
+ public final void clearPackagePersistentPreferredActivities(String packageName, int userId) {
+ mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void clearPackagePreferredActivities(String packageName) {
+ mPreferredActivityHelper.clearPackagePreferredActivities(snapshot(),
+ packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final String[] currentToCanonicalPackageNames(String[] names) {
+ return snapshot().currentToCanonicalPackageNames(names);
+ }
+
+ @Override
+ @Deprecated
+ public final void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId) {
+ mService.deleteExistingPackageAsUser(versionedPackage, observer, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePackageAsUser(String packageName, int versionCode,
+ IPackageDeleteObserver observer, int userId, int flags) {
+ deletePackageVersioned(new VersionedPackage(packageName, versionCode),
+ new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId,
+ flags);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePackageVersioned(VersionedPackage versionedPackage,
+ final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
+ mService.deletePackageVersioned(versionedPackage, observer, userId, deleteFlags);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+ return mPreferredActivityHelper.findPersistentPreferredActivity(snapshot(), intent, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void forceDexOpt(String packageName) {
+ mDexOptHelper.forceDexOpt(snapshot(), packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getActivityInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+ return snapshot().getActivityInfo(component, flags, userId);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
+ return snapshot().getAllIntentFilters(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getAllPackages() {
+ return snapshot().getAllPackages();
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @NonNull
+ @Override
+ @Deprecated
+ public final String[] getAppOpPermissionPackages(@NonNull String permissionName) {
+ return snapshot().getAppOpPermissionPackages(permissionName);
+ }
+
+ @Override
+ @Deprecated
+ public final String getAppPredictionServicePackageName() {
+ return mService.mAppPredictionServicePackage;
+ }
+
+ @PackageManager.EnabledState
+ @Override
+ @Deprecated
+ public final int getApplicationEnabledSetting(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getApplicationEnabledSetting(packageName, userId);
+ }
+
+ /**
+ * Returns true if application is not found or there was an error. Otherwise it returns the
+ * hidden state of the package for the given user.
+ */
+ @Override
+ @Deprecated
+ public final boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getApplicationHiddenSettingAsUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ApplicationInfo getApplicationInfo(String packageName,
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+ return snapshot().getApplicationInfo(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final IArtManager getArtManager() {
+ return mService.mArtManagerService;
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ String getAttentionServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(R.string.config_defaultAttentionService));
+ }
+
+ @Override
+ @Deprecated
+ public final boolean getBlockUninstallForUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getBlockUninstallForUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
+ return snapshot().getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getContentCaptureServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultContentCaptureService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
+ @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
+ @NonNull int userId) {
+ return snapshot().getDeclaredSharedLibraries(packageName, flags, userId);
+ }
+
+ /**
+ * Non-Binder method, support for the backup/restore mechanism: write the default browser (etc)
+ * settings in its canonical XML format. Returns the default browser XML representation as a
+ * byte array, or null if there is none.
+ */
+ @Override
+ @Deprecated
+ public final byte[] getDefaultAppsBackup(int userId) {
+ return mPreferredActivityHelper.getDefaultAppsBackup(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getDefaultTextClassifierPackageName() {
+ return mService.mDefaultTextClassifierPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final int getFlagsForUid(int uid) {
+ return snapshot().getFlagsForUid(uid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final CharSequence getHarmfulAppWarning(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().getHarmfulAppWarning(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return snapshot.getHomeActivitiesAsUser(allHomeCandidates,
+ UserHandle.getCallingUserId());
+ }
+
+ @Deprecated
+ public final String getIncidentReportApproverPackageName() {
+ return mService.mIncidentReportApproverPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final int getInstallLocation() {
+ // allow instant app access
+ return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
+ InstallLocationUtils.APP_INSTALL_AUTO);
+ }
+
+ @PackageManager.InstallReason
+ @Override
+ @Deprecated
+ public final int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
+ return snapshot().getInstallReason(packageName, userId);
+ }
+
+ @Override
+ @Nullable
+ @Deprecated
+ public final InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
+ return snapshot().getInstallSourceInfo(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<ApplicationInfo> getInstalledApplications(
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return new ParceledListSlice<>(
+ snapshot().getInstalledApplications(flags, userId, callingUid));
+ }
+
+ @Override
+ @Deprecated
+ public final List<ModuleInfo> getInstalledModules(int flags) {
+ return mModuleInfoProvider.getInstalledModules(flags);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<PackageInfo> getInstalledPackages(
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getInstalledPackages(flags, userId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String getInstallerPackageName(@NonNull String packageName) {
+ return snapshot().getInstallerPackageName(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getInstantAppInstallerComponent() {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return snapshot.getInstantAppInstallerComponent();
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ ComponentName getInstantAppResolverComponent() {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return mService.getInstantAppResolver(snapshot);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getInstantAppResolverSettingsComponent() {
+ return mInstantAppResolverSettingsComponent;
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component,
+ int flags) {
+ return snapshot().getInstrumentationInfo(component, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<IntentFilterVerificationInfo>
+ getIntentFilterVerifications(String packageName) {
+ return ParceledListSlice.emptyList();
+ }
+
+ @Override
+ @Deprecated
+ public final int getIntentVerificationStatus(String packageName, int userId) {
+ return mDomainVerificationManager.getLegacyState(packageName, userId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
+ return snapshot().getKeySetByAlias(packageName, alias);
+ }
+
+ @Override
+ @Deprecated
+ public final ModuleInfo getModuleInfo(String packageName,
+ @PackageManager.ModuleInfoFlags int flags) {
+ return mModuleInfoProvider.getModuleInfo(packageName, flags);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String getNameForUid(int uid) {
+ return snapshot().getNameForUid(uid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String[] getNamesForUids(@NonNull int[] uids) {
+ return snapshot().getNamesForUids(uids);
+ }
+
+ @Override
+ @Deprecated
+ public final int[] getPackageGids(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageGids(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfo(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageInfo(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageInfoInternal(versionedPackage.getPackageName(),
+ versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final IPackageInstaller getPackageInstaller() {
+ // Return installer service for internal calls.
+ if (PackageManagerServiceUtils.isSystemOrRoot()) {
+ return mInstallerService;
+ }
+ final Computer snapshot = snapshot();
+ // Return null for InstantApps.
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return null;
+ }
+ return mInstallerService;
+ }
+
+ @Override
+ @Deprecated
+ public final void getPackageSizeInfo(final String packageName, int userId,
+ final IPackageStatsObserver observer) {
+ throw new UnsupportedOperationException(
+ "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageUid(@NonNull String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getPackageUid(packageName, flags, userId);
+ }
+
+ /**
+ * <em>IMPORTANT:</em> Not all packages returned by this method may be known
+ * to the system. There are two conditions in which this may occur:
+ * <ol>
+ * <li>The package is on adoptable storage and the device has been removed</li>
+ * <li>The package is being removed and the internal structures are partially updated</li>
+ * </ol>
+ * The second is an artifact of the current data structures and should be fixed. See
+ * b/111075456 for one such instance.
+ * This binder API is cached. If the algorithm in this method changes,
+ * or if the underlying objecs (as returned by getSettingLPr()) change
+ * then the logic that invalidates the cache must be revisited. See
+ * calls to invalidateGetPackagesForUidCache() to locate the points at
+ * which the cache is invalidated.
+ */
+ @Override
+ @Deprecated
+ public final String[] getPackagesForUid(int uid) {
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ snapshot().enforceCrossUserOrProfilePermission(callingUid, userId,
+ /* requireFullPermission */ false,
+ /* checkShell */ false, "getPackagesForUid");
+ return snapshot().getPackagesForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
+ @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
+ @UserIdInt int userId) {
+ return snapshot().getPackagesHoldingPermissions(permissions, flags, userId);
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @Override
+ @Deprecated
+ public final PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
+ return mService.getPermissionGroupInfo(groupName, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
+ final Computer snapshot = snapshot();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ return ParceledListSlice.emptyList();
+ }
+ return new ParceledListSlice<>(snapshot.getPersistentApplications(isSafeMode(), flags));
+ }
+
+ @Override
+ @Deprecated
+ public final int getPreferredActivities(List<IntentFilter> outFilters,
+ List<ComponentName> outActivities, String packageName) {
+ return mPreferredActivityHelper.getPreferredActivities(snapshot(), outFilters,
+ outActivities, packageName);
+ }
+
+ /**
+ * Non-Binder method, support for the backup/restore mechanism: write the full set of preferred
+ * activities in its canonical XML format. Returns the XML output as a byte array, or null if
+ * there is none.
+ */
+ @Override
+ @Deprecated
+ public final byte[] getPreferredActivityBackup(int userId) {
+ return mPreferredActivityHelper.getPreferredActivityBackup(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final int getPrivateFlagsForUid(int uid) {
+ return snapshot().getPrivateFlagsForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageManager.Property getProperty(String propertyName, String packageName,
+ String className) {
+ Objects.requireNonNull(propertyName);
+ Objects.requireNonNull(packageName);
+ PackageStateInternal packageState = snapshot().getPackageStateFiltered(packageName,
+ Binder.getCallingUid(), UserHandle.getCallingUserId());
+ if (packageState == null) {
+ return null;
+ }
+ return mPackageProperty.getProperty(propertyName, packageName, className);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ProviderInfo getProviderInfo(@NonNull ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getProviderInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getReceiverInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+ return snapshot().getReceiverInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @Nullable
+ String getRotationResolverPackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultRotationResolverService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final ServiceInfo getServiceInfo(@NonNull ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
+ return snapshot().getServiceInfo(component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ String getServicesSystemSharedLibraryPackageName() {
+ return mServicesExtensionPackageName;
+ }
+
+ @Override
+ @Deprecated
+ public final String getSetupWizardPackageName() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Non-system caller");
+ }
+ return mService.mSetupWizardPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getSharedLibraries(packageName, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ String getSharedSystemSharedLibraryPackageName() {
+ return mSharedSystemSharedLibraryPackageName;
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final KeySet getSigningKeySet(@NonNull String packageName) {
+ return snapshot().getSigningKeySet(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final String getSdkSandboxPackageName() {
+ return mService.getSdkSandboxPackageName();
+ }
+
+ @Override
+ @Deprecated
+ public final String getSystemCaptionsServicePackageName() {
+ return mService.ensureSystemPackageName(snapshot(),
+ mService.getPackageFromComponentString(
+ R.string.config_defaultSystemCaptionsService));
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final String[] getSystemSharedLibraryNames() {
+ return snapshot().getSystemSharedLibraryNames();
+ }
+
+ @Override
+ @Deprecated
+ public final String getSystemTextClassifierPackageName() {
+ return mService.mSystemTextClassifierPackageName;
+ }
+
+ @Override
+ @Deprecated
+ public final int getTargetSdkVersion(@NonNull String packageName) {
+ return snapshot().getTargetSdkVersion(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final int getUidForSharedUser(@NonNull String sharedUserName) {
+ return snapshot().getUidForSharedUser(sharedUserName);
+ }
+
+ @SuppressLint("MissingPermission")
+ @Override
+ @Deprecated
+ public final String getWellbeingPackageName() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return CollectionUtils.firstOrNull(
+ mContext.getSystemService(RoleManager.class).getRoleHolders(
+ RoleManager.ROLE_SYSTEM_WELLBEING));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ // NOTE: Can't remove due to unsupported app usage
+ @SuppressLint("MissingPermission")
+ @Override
+ @Deprecated
+ public final void grantRuntimePermission(String packageName, String permName,
+ final int userId) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mContext.getSystemService(PermissionManager.class)
+ .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSigningCertificate(@NonNull String packageName,
+ @NonNull byte[] certificate,
+ @PackageManager.CertificateInputType int type) {
+ return snapshot().hasSigningCertificate(packageName, certificate, type);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSystemFeature(String name, int version) {
+ return mService.hasSystemFeature(name, version);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasSystemUidErrors() {
+ // allow instant applications
+ return false;
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
+ @PackageManager.CertificateInputType int type) {
+ return snapshot().hasUidSigningCertificate(uid, certificate, type);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isDeviceUpgrading() {
+ return mService.isDeviceUpgrading();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isFirstBoot() {
+ return mService.isFirstBoot();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantApp(String packageName, int userId) {
+ return snapshot().isInstantApp(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isOnlyCoreApps() {
+ return mService.isOnlyCoreApps();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageAvailable(String packageName, int userId) {
+ return snapshot().isPackageAvailable(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ return mService.isPackageDeviceAdminOnAnyUser(snapshot(),
+ packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
+ return snapshot().isPackageSignedByKeySet(packageName, ks);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSignedByKeySetExactly(@NonNull String packageName,
+ @NonNull KeySet ks) {
+ return snapshot().isPackageSignedByKeySetExactly(packageName, ks);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSuspendedForUser(@NonNull String packageName,
+ @UserIdInt int userId) {
+ return snapshot().isPackageSuspendedForUser(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSafeMode() {
+ // allow instant applications
+ return mService.getSafeMode();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isStorageLow() {
+ return mService.isStorageLow();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isUidPrivileged(int uid) {
+ return snapshot().isUidPrivileged(uid);
+ }
+
+ /**
+ * Ask the package manager to perform a dex-opt with the given compiler filter.
+ * <p>
+ * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+ * state.
+ */
+ @Override
+ @Deprecated
+ public final boolean performDexOptMode(String packageName,
+ boolean checkProfiles, String targetCompilerFilter, boolean force,
+ boolean bootComplete, String splitName) {
+ return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
+ force, bootComplete, splitName);
+ }
+
+ /**
+ * Ask the package manager to perform a dex-opt with the given compiler filter on the secondary
+ * dex files belonging to the given package.
+ * <p>
+ * Note: exposed only for the shell command to allow moving packages explicitly to a definite
+ * state.
+ */
+ @Override
+ @Deprecated
+ public final boolean performDexOptSecondary(String packageName, String compilerFilter,
+ boolean force) {
+ return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ try {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
+
+ return new ParceledListSlice<>(snapshot().queryIntentActivitiesInternal(intent,
+ resolvedType, flags, userId));
+ } finally {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
+ int uid, @PackageManager.ComponentInfoFlagsBits long flags,
+ @Nullable String metaDataKey) {
+ return snapshot().queryContentProviders(processName, uid, flags, metaDataKey);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ParceledListSlice<InstrumentationInfo> queryInstrumentation(
+ @NonNull String targetPackage, int flags) {
+ return snapshot().queryInstrumentation(targetPackage, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentActivityOptions(
+ ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
+ snapshot(), caller, specifics, specificTypes, intent, resolvedType, flags,
+ userId));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
+ snapshot(), intent, resolvedType, flags, userId));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
+ snapshot(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull
+ ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return new ParceledListSlice<>(snapshot().queryIntentServicesInternal(
+ intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
+ }
+
+ @Override
+ @Deprecated
+ public final void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
+ snapshot().querySyncProviders(isSafeMode(), outNames, outInfo);
+ }
+
+ @Override
+ @Deprecated
+ public final void removePermission(String permName) {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mContext.getSystemService(PermissionManager.class).removePermission(permName);
+ }
+
+ @Override
+ @Deprecated
+ public final void replacePreferredActivity(IntentFilter filter, int match,
+ ComponentName[] set, ComponentName activity, int userId) {
+ mPreferredActivityHelper.replacePreferredActivity(snapshot(),
+ new WatchedIntentFilter(filter), match, set, activity, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ProviderInfo resolveContentProvider(String name,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return snapshot().resolveContentProvider(name, flags, userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final void resetApplicationPreferences(int userId) {
+ mPreferredActivityHelper.resetApplicationPreferences(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ return mResolveIntentHelper.resolveIntentInternal(snapshot(), intent,
+ resolvedType, flags, 0 /*privateResolveFlags*/, userId, false,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveService(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ return mResolveIntentHelper.resolveServiceInternal(snapshot(), intent,
+ resolvedType, flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final void restoreDefaultApps(byte[] backup, int userId) {
+ mPreferredActivityHelper.restoreDefaultApps(backup, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void restorePreferredActivities(byte[] backup, int userId) {
+ mPreferredActivityHelper.restorePreferredActivities(backup, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setHomeActivity(ComponentName comp, int userId) {
+ mPreferredActivityHelper.setHomeActivity(snapshot(), comp, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setLastChosenActivity(Intent intent, String resolvedType, int flags,
+ IntentFilter filter, int match, ComponentName activity) {
+ mPreferredActivityHelper.setLastChosenActivity(snapshot(), intent, resolvedType,
+ flags, new WatchedIntentFilter(filter), match, activity);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean updateIntentVerificationStatus(String packageName, int status,
+ int userId) {
+ return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
+ }
+
+ @Override
+ @Deprecated
+ public final void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
+ DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
+ id, verificationCode, failedDomains, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canPackageQuery(@NonNull String sourcePackageName,
+ @NonNull String targetPackageName, @UserIdInt int userId) {
+ return snapshot().canPackageQuery(sourcePackageName, targetPackageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void deletePreloadsFileCache() throws RemoteException {
+ mService.deletePreloadsFileCache();
+ }
+
+ @Override
+ @Deprecated
+ public final void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden)
+ throws RemoteException {
+ mService.setSystemAppHiddenUntilInstalled(snapshot(), packageName, hidden);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean setSystemAppInstallState(String packageName,
+ boolean installed, int userId) throws RemoteException {
+ return mService.setSystemAppInstallState(snapshot(), packageName, installed, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void finishPackageInstall(int token, boolean didLaunch) throws RemoteException {
+ mService.finishPackageInstall(token, didLaunch);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/IncrementalProgressListener.java b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
index fa11924..703bbda 100644
--- a/services/core/java/com/android/server/pm/IncrementalProgressListener.java
+++ b/services/core/java/com/android/server/pm/IncrementalProgressListener.java
@@ -33,7 +33,8 @@
@Override
public void onPackageLoadingProgressChanged(float progress) {
- PackageStateInternal packageState = mPm.getPackageStateInternal(mPackageName);
+ PackageStateInternal packageState = mPm.snapshotComputer()
+ .getPackageStateInternal(mPackageName);
if (packageState == null) {
return;
}
diff --git a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index 6dbe9b6..f452b29 100644
--- a/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -170,7 +170,7 @@
}
}
OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
- consumer -> mPm.forEachPackage(
+ consumer -> mPm.forEachPackage(mPm.snapshotComputer(),
pkg -> consumer.accept(pkg, pkg.isSystem(),
apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
// Prune any system packages that no longer exist.
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b5d63f3..b39b24f 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -527,8 +527,10 @@
+ android.Manifest.permission.INSTALL_PACKAGES + ".");
}
PackageSetting pkgSetting;
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
- true /* checkShell */, "installExistingPackage for user " + userId);
+ final Computer preLockSnapshot = mPm.snapshotComputer();
+ preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+ true /* requireFullPermission */, true /* checkShell */,
+ "installExistingPackage for user " + userId);
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
@@ -543,11 +545,12 @@
// writer
synchronized (mPm.mLock) {
+ final Computer snapshot = mPm.snapshotComputer();
pkgSetting = mPm.mSettings.getPackageLPr(packageName);
if (pkgSetting == null) {
return PackageManager.INSTALL_FAILED_INVALID_URI;
}
- if (!mPm.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
+ if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
// only allow the existing package to be used if it's installed as a full
// application for at least one user
boolean installAllowed = false;
@@ -597,7 +600,8 @@
mAppDataHelper.prepareAppDataAfterInstallLIF(pkgSetting.getPkg());
}
}
- mPm.sendPackageAddedForUser(packageName, pkgSetting, userId, DataLoaderType.NONE);
+ mPm.sendPackageAddedForUser(mPm.snapshotComputer(), packageName, pkgSetting, userId,
+ DataLoaderType.NONE);
synchronized (mPm.mLock) {
mPm.updateSequenceNumberLP(pkgSetting, new int[]{ userId });
}
@@ -958,10 +962,6 @@
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
- if (result.needsNewAppId()) {
- request.mInstallResult.mRemovedInfo.mNewAppId =
- result.mPkgSetting.getAppId();
- }
} catch (PackageManagerException e) {
request.mInstallResult.setError("Scanning Failed.", e);
return;
@@ -1906,8 +1906,8 @@
AndroidPackage oldPackage = mPm.mPackages.get(packageName);
// Set the update and install times
- PackageStateInternal deletedPkgSetting = mPm.getPackageStateInternal(
- oldPackage.getPackageName());
+ PackageStateInternal deletedPkgSetting = mPm.snapshotComputer()
+ .getPackageStateInternal(oldPackage.getPackageName());
reconciledPkg.mPkgSetting
.setFirstInstallTimeFromReplaced(deletedPkgSetting, request.mAllUsers)
.setLastUpdateTime(System.currentTimeMillis());
@@ -2575,9 +2575,10 @@
size = i;
mPm.mPendingBroadcasts.clear();
}
+ final Computer snapshot = mPm.snapshotComputer();
// Send broadcasts
for (int i = 0; i < size; i++) {
- mPm.sendPackageChangedBroadcast(packages[i], true /* dontKillApp */,
+ mPm.sendPackageChangedBroadcast(snapshot, packages[i], true /* dontKillApp */,
components[i], uids[i], null /* reason */);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2594,11 +2595,9 @@
final int dataLoaderType = installArgs.mDataLoaderType;
final boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
- final int previousAppId = (res.mRemovedInfo != null && res.mRemovedInfo.mNewAppId >= 0)
- ? res.mRemovedInfo.mUid : Process.INVALID_UID;
final String packageName = res.mName;
final PackageStateInternal pkgSetting =
- succeeded ? mPm.getPackageStateInternal(packageName) : null;
+ succeeded ? mPm.snapshotComputer().getPackageStateInternal(packageName) : null;
final boolean removedBeforeUpdate = (pkgSetting == null)
|| (pkgSetting.isSystem() && !pkgSetting.getPath().getPath().equals(
res.mPkg.getPath()));
@@ -2696,17 +2695,14 @@
// sendPackageAddedForNewUsers also deals with system apps
int appId = UserHandle.getAppId(res.mUid);
boolean isSystem = res.mPkg.isSystem();
- mPm.sendPackageAddedForNewUsers(packageName, isSystem || virtualPreload,
- virtualPreload /*startReceiver*/, appId, firstUserIds, firstInstantUserIds,
- dataLoaderType);
+ mPm.sendPackageAddedForNewUsers(mPm.snapshotComputer(), packageName,
+ isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId,
+ firstUserIds, firstInstantUserIds, dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, res.mUid);
- if (previousAppId != Process.INVALID_UID) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_PREVIOUS_UID, previousAppId);
- } else if (update) {
+ if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
@@ -2714,7 +2710,8 @@
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mPm.mLock) {
newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(
- mPm.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+ mPm.snapshotComputer()
+ .getPackageStateInternal(packageName, Process.SYSTEM_UID),
updateUserIds, mPm.mSettings.getPackagesLocked());
}
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
@@ -2749,27 +2746,24 @@
// Send replaced for users that don't see the package for the first time
if (update) {
- // Only send PACKAGE_REPLACED if appId has not changed
- if (previousAppId == Process.INVALID_UID) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- packageName, extras, 0 /*flags*/,
- null /*targetPackage*/, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ packageName, extras, 0 /*flags*/,
+ null /*targetPackage*/, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
+ null);
+ if (installerPackageName != null) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ installerPackageName, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/,
null);
- if (installerPackageName != null) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- installerPackageName, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/,
- null);
- }
- if (notifyVerifier) {
- mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
- extras, 0 /*flags*/,
- mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
- updateUserIds, instantUserIds, null /*broadcastAllowList*/,
- null);
- }
+ }
+ if (notifyVerifier) {
+ mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+ extras, 0 /*flags*/,
+ mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
+ updateUserIds, instantUserIds, null /*broadcastAllowList*/,
+ null);
}
mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
@@ -2819,11 +2813,12 @@
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
// No need to kill consumers if it's installation of new version static shared lib.
+ final Computer snapshot = mPm.snapshotComputer();
final boolean dontKillApp = !update && res.mPkg.getStaticSharedLibName() != null;
for (int i = 0; i < res.mLibraryConsumers.size(); i++) {
AndroidPackage pkg = res.mLibraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
- mPm.sendPackageChangedBroadcast(pkg.getPackageName(), dontKillApp,
+ mPm.sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), dontKillApp,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(), null);
}
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
index 0ffc1ed..230f555 100644
--- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.ModuleInfo;
@@ -25,6 +26,7 @@
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -58,7 +60,7 @@
private static final String MODULE_METADATA_KEY = "android.content.pm.MODULE_METADATA";
private final Context mContext;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final ApexManager mApexManager;
private final Map<String, ModuleInfo> mModuleInfo;
@@ -66,9 +68,8 @@
private volatile boolean mMetadataLoaded;
private volatile String mPackageName;
- ModuleInfoProvider(Context context, IPackageManager packageManager) {
+ ModuleInfoProvider(Context context) {
mContext = context;
- mPackageManager = packageManager;
mApexManager = ApexManager.getInstance();
mModuleInfo = new ArrayMap<>();
}
@@ -77,12 +78,20 @@
public ModuleInfoProvider(
XmlResourceParser metadata, Resources resources, ApexManager apexManager) {
mContext = null;
- mPackageManager = null;
mApexManager = apexManager;
mModuleInfo = new ArrayMap<>();
loadModuleMetadata(metadata, resources);
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
/** Called by the {@code PackageManager} when it has completed its boot sequence */
public void systemReady() {
mPackageName = mContext.getResources().getString(
@@ -95,7 +104,7 @@
final Resources packageResources;
final PackageInfo pi;
try {
- pi = mPackageManager.getPackageInfo(mPackageName,
+ pi = getPackageManager().getPackageInfo(mPackageName,
PackageManager.GET_META_DATA, UserHandle.USER_SYSTEM);
Context packageContext = mContext.createPackageContext(mPackageName, 0);
@@ -183,7 +192,7 @@
List<PackageInfo> allPackages;
try {
- allPackages = mPackageManager.getInstalledPackages(
+ allPackages = getPackageManager().getInstalledPackages(
flags | PackageManager.MATCH_APEX, UserHandle.getCallingUserId()).getList();
} catch (RemoteException e) {
Slog.w(TAG, "Unable to retrieve all package names", e);
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 5fc90b1..c5ca06c 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -57,6 +57,8 @@
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
import java.io.File;
import java.util.Objects;
@@ -77,81 +79,74 @@
final StorageManager storage = mPm.mInjector.getSystemService(StorageManager.class);
final PackageManager pm = mPm.mContext.getPackageManager();
- final String currentVolumeUuid;
- final File codeFile;
- final InstallSource installSource;
- final String packageAbiOverride;
- final int appId;
- final String seinfo;
- final String label;
- final int targetSdkVersion;
- final PackageFreezer freezer;
- final int[] installedUserIds;
- final boolean isCurrentLocationExternal;
+ Computer snapshot = mPm.snapshotComputer();
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null
+ || packageState.getPkg() == null
+ || snapshot.shouldFilterApplication(packageState, callingUid, user.getIdentifier())) {
+ throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
+ }
+ final AndroidPackage pkg = packageState.getPkg();
+ if (pkg.isSystem()) {
+ throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+ "Cannot move system application");
+ }
+
+ final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
+ final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
+ if (isInternalStorage && !allow3rdPartyOnInternal) {
+ throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
+ "3rd party apps are not allowed on internal storage");
+ }
+
+
+ final String currentVolumeUuid = packageState.getVolumeUuid();
+
+ final File probe = new File(pkg.getPath());
+ final File probeOat = new File(probe, "oat");
+ if (!probe.isDirectory() || !probeOat.isDirectory()) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Move only supported for modern cluster style installs");
+ }
+
+ if (Objects.equals(currentVolumeUuid, volumeUuid)) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Package already moved to " + volumeUuid);
+ }
+ if (!pkg.isExternalStorage()
+ && mPm.isPackageDeviceAdminOnAnyUser(snapshot, packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
+ "Device admin cannot be moved");
+ }
+
+ if (snapshot.getFrozenPackages().containsKey(packageName)) {
+ throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+ "Failed to move already frozen package");
+ }
+
+ final boolean isCurrentLocationExternal = pkg.isExternalStorage();
+ final File codeFile = new File(pkg.getPath());
+ final InstallSource installSource = packageState.getInstallSource();
+ final String packageAbiOverride = packageState.getCpuAbiOverride();
+ final int appId = UserHandle.getAppId(pkg.getUid());
+ final String seinfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
+ final String label = String.valueOf(pm.getApplicationLabel(
+ AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
+ final int targetSdkVersion = pkg.getTargetSdkVersion();
+ final int[] installedUserIds = PackageStateUtils.queryInstalledUsers(packageState,
+ mPm.mUserManager.getUserIds(), true);
final String fromCodePath;
+ if (codeFile.getParentFile().getName().startsWith(
+ PackageManagerService.RANDOM_DIR_PREFIX)) {
+ fromCodePath = codeFile.getParentFile().getAbsolutePath();
+ } else {
+ fromCodePath = codeFile.getAbsolutePath();
+ }
- // reader
+ final PackageFreezer freezer;
synchronized (mPm.mLock) {
- final AndroidPackage pkg = mPm.mPackages.get(packageName);
- final PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
- if (pkg == null
- || ps == null
- || mPm.shouldFilterApplication(ps, callingUid, user.getIdentifier())) {
- throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
- }
- if (pkg.isSystem()) {
- throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
- "Cannot move system application");
- }
-
- final boolean isInternalStorage = VolumeInfo.ID_PRIVATE_INTERNAL.equals(volumeUuid);
- final boolean allow3rdPartyOnInternal = mPm.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allow3rdPartyAppOnInternal);
- if (isInternalStorage && !allow3rdPartyOnInternal) {
- throw new PackageManagerException(MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL,
- "3rd party apps are not allowed on internal storage");
- }
-
- currentVolumeUuid = ps.getVolumeUuid();
-
- final File probe = new File(pkg.getPath());
- final File probeOat = new File(probe, "oat");
- if (!probe.isDirectory() || !probeOat.isDirectory()) {
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Move only supported for modern cluster style installs");
- }
-
- if (Objects.equals(currentVolumeUuid, volumeUuid)) {
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Package already moved to " + volumeUuid);
- }
- if (!pkg.isExternalStorage() && mPm.isPackageDeviceAdminOnAnyUser(packageName)) {
- throw new PackageManagerException(MOVE_FAILED_DEVICE_ADMIN,
- "Device admin cannot be moved");
- }
-
- if (mPm.mFrozenPackages.containsKey(packageName)) {
- throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
- "Failed to move already frozen package");
- }
-
- isCurrentLocationExternal = pkg.isExternalStorage();
- codeFile = new File(pkg.getPath());
- installSource = ps.getInstallSource();
- packageAbiOverride = ps.getCpuAbiOverride();
- appId = UserHandle.getAppId(pkg.getUid());
- seinfo = AndroidPackageUtils.getSeInfo(pkg, ps);
- label = String.valueOf(pm.getApplicationLabel(
- AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
- targetSdkVersion = pkg.getTargetSdkVersion();
freezer = mPm.freezePackage(packageName, "movePackageInternal");
- installedUserIds = ps.queryInstalledUsers(mPm.mUserManager.getUserIds(), true);
- if (codeFile.getParentFile().getName().startsWith(
- PackageManagerService.RANDOM_DIR_PREFIX)) {
- fromCodePath = codeFile.getParentFile().getAbsolutePath();
- } else {
- fromCodePath = codeFile.getAbsolutePath();
- }
}
final Bundle extras = new Bundle();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index bd00914..cc4a760 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -131,8 +131,9 @@
Predicate<PackageStateInternal> isPlatformPackage = pkgSetting ->
PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPkg().getPackageName());
// Important: the packages we need to run with ab-ota compiler-reason.
+ final Computer snapshot = mPackageManagerService.snapshotComputer();
final Collection<? extends PackageStateInternal> allPackageStates =
- mPackageManagerService.getPackageStates().values();
+ snapshot.getPackageStates().values();
important = DexOptHelper.getPackagesForDexopt(allPackageStates,mPackageManagerService,
DEBUG_DEXOPT);
// Remove Platform Package from A/B OTA b/160735835.
@@ -165,7 +166,7 @@
Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
+ DexOptHelper.packagesToString(others));
for (PackageStateInternal pkg : others) {
- mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
+ mPackageManagerService.deleteOatArtifactsOfPackage(snapshot, pkg.getPackageName());
}
}
long spaceAvailableNow = getAvailableSpace();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0a19357..4e702e2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -334,7 +334,7 @@
StagingManager.StagedSession stagedSession = session.mStagedSession;
if (!stagedSession.isInTerminalState() && stagedSession.hasParentSessionId()
&& getSession(stagedSession.getParentSessionId()) == null) {
- stagedSession.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ stagedSession.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"An orphan staged session " + stagedSession.sessionId() + " is found, "
+ "parent " + stagedSession.getParentSessionId() + " is missing");
continue;
@@ -597,8 +597,8 @@
String installerAttributionTag, int userId)
throws IOException {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(
- callingUid, userId, true, true, "createSession");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "createSession");
if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
throw new SecurityException("User restriction prevents installing");
@@ -663,7 +663,7 @@
params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0
- && !mPm.isCallerVerifier(callingUid)) {
+ && !mPm.isCallerVerifier(snapshot, callingUid)) {
params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
}
if (mContext.checkCallingOrSelfPermission(
@@ -676,7 +676,7 @@
String originatingPackageName = null;
if (params.originatingUid != SessionParams.UID_UNKNOWN
&& params.originatingUid != callingUid) {
- String[] packages = mPm.mIPackageManager.getPackagesForUid(params.originatingUid);
+ String[] packages = snapshot.getPackagesForUid(params.originatingUid);
if (packages != null && packages.length > 0) {
// Choose an arbitrary representative package in the case of a shared UID.
originatingPackageName = packages[0];
@@ -727,7 +727,7 @@
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
&& !isCalledBySystemOrShell(callingUid)
- && (mPm.mIPackageManager.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
+ && (snapshot.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM)
== 0) {
throw new SecurityException(
"Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
@@ -853,7 +853,7 @@
mSilentUpdatePolicy, mInstallThread.getLooper(), mStagingManager, sessionId,
userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid,
null, null, false, false, false, false, null, SessionInfo.INVALID_ID,
- false, false, false, SessionInfo.SESSION_NO_ERROR, "");
+ false, false, false, PackageManager.INSTALL_UNKNOWN, "");
synchronized (mSessions) {
mSessions.put(sessionId, session);
@@ -1038,11 +1038,12 @@
return "smdl" + sessionId + ".tmp";
}
- private boolean shouldFilterSession(int uid, SessionInfo info) {
+ private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, SessionInfo info) {
if (info == null) {
return false;
}
- return uid != info.getInstallerUid() && !mPm.canQueryPackage(uid, info.getAppPackageName());
+ return uid != info.getInstallerUid()
+ && !snapshot.canQueryPackage(uid, info.getAppPackageName());
}
@Override
@@ -1055,7 +1056,7 @@
? session.generateInfoForCaller(true /* includeIcon */, callingUid)
: null;
}
- return shouldFilterSession(callingUid, result) ? null : result;
+ return shouldFilterSession(mPm.snapshotComputer(), callingUid, result) ? null : result;
}
@Override
@@ -1070,15 +1071,16 @@
}
}
}
- result.removeIf(info -> shouldFilterSession(callingUid, info));
+ final Computer snapshot = mPm.snapshotComputer();
+ result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
return new ParceledListSlice<>(result);
}
@Override
public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(
- callingUid, userId, true, false, "getAllSessions");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getAllSessions");
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
@@ -1090,15 +1092,16 @@
}
}
}
- result.removeIf(info -> shouldFilterSession(callingUid, info));
+ result.removeIf(info -> shouldFilterSession(snapshot, callingUid, info));
return new ParceledListSlice<>(result);
}
@Override
public ParceledListSlice<SessionInfo> getMySessions(String installerPackageName, int userId) {
- mPm.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "getMySessions");
- mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
+ final Computer snapshot = mPm.snapshotComputer();
+ final int callingUid = Binder.getCallingUid();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, false, "getMySessions");
+ mAppOps.checkPackage(callingUid, installerPackageName);
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
@@ -1120,8 +1123,9 @@
@Override
public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,
IntentSender statusReceiver, int userId) {
+ final Computer snapshot = mPm.snapshotComputer();
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
}
@@ -1154,8 +1158,7 @@
.setAdmin(callerPackageName)
.write();
} else {
- ApplicationInfo appInfo = mPm.mIPackageManager
- .getApplicationInfo(callerPackageName, 0, userId);
+ ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId);
if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES,
null);
@@ -1174,7 +1177,8 @@
String callerPackageName, IntentSender statusReceiver, int userId) {
final int callingUid = Binder.getCallingUid();
mContext.enforceCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES, null);
- mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
}
@@ -1206,8 +1210,9 @@
@Override
public void registerCallback(IPackageInstallerCallback callback, int userId) {
- mPm.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "registerCallback");
+ final Computer snapshot = mPm.snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "registerCallback");
registerCallback(callback, eventUserId -> userId == eventUserId);
}
@@ -1295,13 +1300,13 @@
}
}
- private boolean shouldFilterSession(int uid, int sessionId) {
+ private boolean shouldFilterSession(@NonNull Computer snapshot, int uid, int sessionId) {
final PackageInstallerSession session = getSession(sessionId);
if (session == null) {
return false;
}
return uid != session.getInstallerUid()
- && !mPm.canQueryPackage(uid, session.getPackageName());
+ && !snapshot.canQueryPackage(uid, session.getPackageName());
}
static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
@@ -1454,11 +1459,12 @@
final int sessionId = msg.arg1;
final int userId = msg.arg2;
final int n = mCallbacks.beginBroadcast();
+ final Computer snapshot = mPm.snapshotComputer();
for (int i = 0; i < n; i++) {
final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i);
final BroadcastCookie cookie = (BroadcastCookie) mCallbacks.getBroadcastCookie(i);
if (cookie.userCheck.test(userId)
- && !shouldFilterSession(cookie.callingUid, sessionId)) {
+ && !shouldFilterSession(snapshot, cookie.callingUid, sessionId)) {
try {
invokeCallback(callback, msg);
} catch (RemoteException ignored) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ef7158a..68be64f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -82,7 +82,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -127,6 +126,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.ExceptionUtils;
import android.util.IntArray;
import android.util.MathUtils;
@@ -462,7 +462,7 @@
@GuardedBy("mLock")
private boolean mSessionFailed;
@GuardedBy("mLock")
- private int mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ private int mSessionErrorCode = PackageManager.INSTALL_UNKNOWN;
@GuardedBy("mLock")
private String mSessionErrorMessage;
@@ -860,7 +860,8 @@
return USER_ACTION_NOT_NEEDED;
}
- if (mPm.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, userId)) {
+ if (snapshot.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid,
+ userId)) {
// show the installer to account for device poslicy or unknown sources use cases
return USER_ACTION_REQUIRED;
}
@@ -2331,7 +2332,7 @@
}
} else {
PackageManagerException e = (PackageManagerException) t.getCause();
- setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ setSessionFailed(e.error,
PackageManager.installStatusToString(e.error, e.getMessage()));
dispatchSessionFinished(e.error, e.getMessage(), null);
maybeFinishChildSessions(e.error, e.getMessage());
@@ -2862,7 +2863,9 @@
inheritFileLocked(mResolvedBaseFile);
// Collect the requiredSplitTypes from base
CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
- } else {
+ } else if ((params.installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ EventLog.writeEvent(0x534e4554, "219044664");
+
// Installing base.apk. Make sure the app is restarted.
params.setDontKillApp(false);
}
@@ -3753,7 +3756,8 @@
};
if (!manualStartAndDestroy) {
- final PerUidReadTimeouts[] perUidReadTimeouts = mPm.getPerUidReadTimeouts();
+ final PerUidReadTimeouts[] perUidReadTimeouts =
+ mPm.getPerUidReadTimeouts(mPm.snapshotComputer());
final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams();
healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS;
@@ -4045,7 +4049,7 @@
mSessionReady = true;
mSessionApplied = false;
mSessionFailed = false;
- mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ mSessionErrorCode = PackageManager.INSTALL_UNKNOWN;
mSessionErrorMessage = "";
}
mCallback.onSessionChanged(this);
@@ -4073,7 +4077,7 @@
mSessionReady = false;
mSessionApplied = true;
mSessionFailed = false;
- mSessionErrorCode = SessionInfo.SESSION_NO_ERROR;
+ mSessionErrorCode = INSTALL_SUCCEEDED;
mSessionErrorMessage = "";
Slog.d(TAG, "Marking session " + sessionId + " as applied");
}
@@ -4103,7 +4107,6 @@
}
/** {@hide} */
- @SessionErrorCode
int getSessionErrorCode() {
synchronized (mLock) {
return mSessionErrorCode;
@@ -4592,7 +4595,7 @@
final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false);
final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false);
final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE,
- SessionInfo.SESSION_NO_ERROR);
+ PackageManager.INSTALL_UNKNOWN);
final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE);
if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
new file mode 100644
index 0000000..2b73375
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -0,0 +1,751 @@
+/*
+ * Copyright (C) 2022 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;
+
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.AuxiliaryResolveInfo;
+import android.content.pm.Checksum;
+import android.content.pm.IOnChecksumsReadyListener;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProcessInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.SuspendDialogInfo;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.DynamicCodeLogger;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.pm.pkg.AndroidPackageApi;
+import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.PackageStateUtils;
+import com.android.server.pm.pkg.SharedUserApi;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.mutate.PackageStateMutator;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Internal manager variant of {@link IPackageManagerBase}. See that class for info.
+ * {@link PackageManagerInternal} should eventually passing in a snapshot instance, deprecating
+ * this class, but that requires much larger refactor.
+ */
+abstract class PackageManagerInternalBase extends PackageManagerInternal {
+
+ @NonNull
+ private final PackageManagerService mService;
+
+ public PackageManagerInternalBase(@NonNull PackageManagerService service) {
+ mService = service;
+ }
+
+ @NonNull protected abstract Context getContext();
+ @NonNull protected abstract PermissionManagerServiceInternal getPermissionManager();
+ @NonNull protected abstract AppDataHelper getAppDataHelper();
+ @NonNull protected abstract PackageObserverHelper getPackageObserverHelper();
+ @NonNull protected abstract ResolveIntentHelper getResolveIntentHelper();
+ @NonNull protected abstract SuspendPackageHelper getSuspendPackageHelper();
+ @NonNull protected abstract ProtectedPackages getProtectedPackages();
+ @NonNull protected abstract UserNeedsBadgingCache getUserNeedsBadging();
+ @NonNull protected abstract InstantAppRegistry getInstantAppRegistry();
+ @NonNull protected abstract ApexManager getApexManager();
+ @NonNull protected abstract DexManager getDexManager();
+
+ @Override
+ public final Computer snapshot() {
+ return mService.snapshotComputer();
+ }
+
+ @Override
+ @Deprecated
+ public final List<ApplicationInfo> getInstalledApplications(
+ @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
+ return snapshot().getInstalledApplications(flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantApp(String packageName, int userId) {
+ return snapshot().isInstantApp(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getInstantAppPackageName(int uid) {
+ return snapshot().getInstantAppPackageName(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
+ return snapshot().filterAppAccess(pkg, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(String packageName, int callingUid, int userId) {
+ return snapshot().filterAppAccess(packageName, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean filterAppAccess(int uid, int callingUid) {
+ return snapshot().filterAppAccess(uid, callingUid);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
+ return snapshot().getVisibilityAllowList(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canQueryPackage(int callingUid, @Nullable String packageName) {
+ return snapshot().canQueryPackage(callingUid, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final AndroidPackage getPackage(String packageName) {
+ return snapshot().getPackage(packageName);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
+ return snapshot().getPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final AndroidPackage getPackage(int uid) {
+ return snapshot().getPackage(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<AndroidPackage> getPackagesForAppId(int appId) {
+ return snapshot().getPackagesForAppId(appId);
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final PackageStateInternal getPackageStateInternal(String packageName) {
+ return snapshot().getPackageStateInternal(packageName);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
+ return snapshot().getPackageStates();
+ }
+
+ @Override
+ @Deprecated
+ public final void removePackageListObserver(PackageListObserver observer) {
+ getPackageObserverHelper().removeObserver(observer);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
+ return snapshot().getDisabledSystemPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
+ return mService.getKnownPackageNamesInternal(snapshot(), knownPackage, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setKeepUninstalledPackages(final List<String> packageList) {
+ mService.setKeepUninstalledPackagesInternal(snapshot(), packageList);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPermissionsReviewRequired(String packageName, int userId) {
+ return getPermissionManager().isPermissionsReviewRequired(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final PackageInfo getPackageInfo(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getPackageInfoInternal(packageName,
+ PackageManager.VERSION_CODE_HIGHEST, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
+ return getSuspendPackageHelper().getSuspendedPackageLauncherExtras(snapshot(), packageName,
+ userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageSuspended(String packageName, int userId) {
+ return getSuspendPackageHelper().isPackageSuspended(snapshot(), packageName, userId,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final void removeNonSystemPackageSuspensions(String packageName, int userId) {
+ getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
+ new String[]{packageName},
+ (suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
+ suspendingPackage),
+ userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void removeDistractingPackageRestrictions(String packageName, int userId) {
+ mService.removeDistractingPackageRestrictions(snapshot(), new String[]{packageName},
+ userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void removeAllDistractingPackageRestrictions(int userId) {
+ mService.removeAllDistractingPackageRestrictions(snapshot(), userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getSuspendingPackage(String suspendedPackage, int userId) {
+ return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
+ Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
+ String suspendingPackage, int userId) {
+ return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
+ suspendingPackage, userId, Binder.getCallingUid());
+ }
+
+ @Override
+ @Deprecated
+ public final int getDistractingPackageRestrictions(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ return (packageState == null) ? RESTRICTION_NONE
+ : packageState.getUserStateOrDefault(userId).getDistractionFlags();
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageUid(String packageName,
+ @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+ return snapshot().getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
+ }
+
+ @Override
+ @Deprecated
+ public final ApplicationInfo getApplicationInfo(String packageName,
+ @PackageManager.ApplicationInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ActivityInfo getActivityInfo(ComponentName component,
+ @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
+ return snapshot().getActivityInfoInternal(component, flags, filterCallingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentActivities(
+ Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ int filterCallingUid, int userId) {
+ return snapshot().queryIntentActivitiesInternal(intent, resolvedType, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentReceivers(Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ int filterCallingUid, int userId) {
+ return getResolveIntentHelper().queryIntentReceiversInternal(
+ snapshot(), intent, resolvedType, flags, userId, filterCallingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<ResolveInfo> queryIntentServices(
+ Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
+ int userId) {
+ final String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
+ return snapshot().queryIntentServicesInternal(intent, resolvedType, flags, userId,
+ callingUid, false);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+ int userId) {
+ return snapshot().getHomeActivitiesAsUser(allHomeCandidates, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getDefaultHomeActivity(int userId) {
+ return snapshot().getDefaultHomeActivity(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ComponentName getSystemUiServiceComponent() {
+ return ComponentName.unflattenFromString(getContext().getResources().getString(
+ com.android.internal.R.string.config_systemUIServiceComponent));
+ }
+
+ @Override
+ @Deprecated
+ public final void setDeviceOwnerProtectedPackages(
+ String deviceOwnerPackageName, List<String> packageNames) {
+ getProtectedPackages().setDeviceOwnerProtectedPackages(
+ deviceOwnerPackageName, packageNames);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageDataProtected(int userId, String packageName) {
+ return getProtectedPackages().isPackageDataProtected(userId, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageStateProtected(String packageName, int userId) {
+ return getProtectedPackages().isPackageStateProtected(userId, packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageEphemeral(int userId, String packageName) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ return packageState != null
+ && packageState.getUserStateOrDefault(userId).isInstantApp();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean wasPackageEverLaunched(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+ return !packageState.getUserStateOrDefault(userId).isNotLaunched();
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
+ return PackageStateUtils.isEnabledAndMatches(
+ getPackageStateInternal(component.getPackageName()), component, flags, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean userNeedsBadging(int userId) {
+ return getUserNeedsBadging().get(userId);
+ }
+
+ @Override
+ @Deprecated
+ public final String getNameForUid(int uid) {
+ return snapshot().getNameForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ Intent origIntent, String resolvedType, String callingPackage,
+ @Nullable String callingFeatureId, boolean isRequesterInstantApp,
+ Bundle verificationBundle, int userId) {
+ mService.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
+ resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
+ verificationBundle, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct) {
+ grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+ false /* retainOnUpdate */);
+ }
+
+ @Override
+ @Deprecated
+ public final void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
+ mService.grantImplicitAccess(snapshot(), userId, intent,
+ recipientAppId, visibleUid, direct, retainOnUpdate);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isInstantAppInstallerComponent(ComponentName component) {
+ final ActivityInfo instantAppInstallerActivity = mService.mInstantAppInstallerActivity;
+ return instantAppInstallerActivity != null
+ && instantAppInstallerActivity.getComponentName().equals(component);
+ }
+
+ @Override
+ @Deprecated
+ public final void pruneInstantApps() {
+ getInstantAppRegistry().pruneInstantApps(snapshot());
+ }
+
+ @Override
+ @Deprecated
+ public final String getSetupWizardPackageName() {
+ return mService.mSetupWizardPackage;
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveIntent(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags,
+ @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
+ boolean resolveForStart, int filterCallingUid) {
+ return getResolveIntentHelper().resolveIntentInternal(snapshot(),
+ intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
+ filterCallingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final ResolveInfo resolveService(Intent intent, String resolvedType,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+ return getResolveIntentHelper().resolveServiceInternal(snapshot(), intent,
+ resolvedType, flags, userId, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final ProviderInfo resolveContentProvider(String name,
+ @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
+ return snapshot().resolveContentProvider(name, flags, userId,callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final int getUidTargetSdkVersion(int uid) {
+ return snapshot().getUidTargetSdkVersion(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int getPackageTargetSdkVersion(String packageName) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState != null && packageState.getPkg() != null) {
+ return packageState.getPkg().getTargetSdkVersion();
+ }
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canAccessInstantApps(int callingUid, @UserIdInt int userId) {
+ return snapshot().canViewInstantApps(callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
+ @UserIdInt int userId) {
+ return snapshot().canAccessComponent(callingUid, component, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean hasInstantApplicationMetadata(String packageName, int userId) {
+ return getInstantAppRegistry().hasInstantApplicationMetadata(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final SparseArray<String> getAppsWithSharedUserIds() {
+ return snapshot().getAppsWithSharedUserIds();
+ }
+
+ @Override
+ @NonNull
+ @Deprecated
+ public final String[] getSharedUserPackagesForPackage(String packageName, int userId) {
+ return snapshot().getSharedUserPackagesForPackage(packageName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+ return snapshot().getProcessesForUid(uid);
+ }
+
+ @Override
+ @Deprecated
+ public final int[] getPermissionGids(String permissionName, int userId) {
+ return getPermissionManager().getPermissionGids(permissionName, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isOnlyCoreApps() {
+ return mService.isOnlyCoreApps();
+ }
+
+ @Override
+ @Deprecated
+ public final void freeStorage(String volumeUuid, long bytes,
+ @StorageManager.AllocateFlags int flags) throws IOException {
+ mService.freeStorage(volumeUuid, bytes, flags);
+ }
+
+ @Override
+ @Deprecated
+ public final void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException {
+ mService.freeAllAppCacheAboveQuota(volumeUuid);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+ mService.forEachPackageSetting(actionLocked);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackageState(Consumer<PackageStateInternal> action) {
+ mService.forEachPackageState(snapshot(), action);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachPackage(Consumer<AndroidPackage> action) {
+ mService.forEachPackage(snapshot(), action);
+ }
+
+ @Override
+ @Deprecated
+ public final void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+ @UserIdInt int userId) {
+ mService.forEachInstalledPackage(snapshot(), action, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final ArraySet<String> getEnabledComponents(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return new ArraySet<>();
+ }
+ return packageState.getUserStateOrDefault(userId).getEnabledComponents();
+ }
+
+ @Override
+ @Deprecated
+ public final ArraySet<String> getDisabledComponents(String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return new ArraySet<>();
+ }
+ return packageState.getUserStateOrDefault(userId).getDisabledComponents();
+ }
+
+ @Override
+ @Deprecated
+ public final @PackageManager.EnabledState int getApplicationEnabledState(
+ String packageName, int userId) {
+ final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return COMPONENT_ENABLED_STATE_DEFAULT;
+ }
+ return packageState.getUserStateOrDefault(userId).getEnabledState();
+ }
+
+ @Override
+ @Deprecated
+ public final @PackageManager.EnabledState int getComponentEnabledSetting(
+ @NonNull ComponentName componentName, int callingUid, int userId) {
+ return snapshot().getComponentEnabledSettingInternal(
+ componentName, callingUid, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void setEnableRollbackCode(int token, int enableRollbackCode) {
+ mService.setEnableRollbackCode(token, enableRollbackCode);
+ }
+
+ @Override
+ @Deprecated
+ public final void finishPackageInstall(int token, boolean didLaunch) {
+ mService.finishPackageInstall(token, didLaunch);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isApexPackage(String packageName) {
+ return getApexManager().isApexPackage(packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getApksInApex(String apexPackageName) {
+ return getApexManager().getApksInApex(apexPackageName);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
+ return snapshot().isCallerInstallerOfRecord(pkg, callingUid);
+ }
+
+ @Override
+ @Deprecated
+ public final List<String> getMimeGroup(String packageName, String mimeGroup) {
+ return mService.getMimeGroupInternal(snapshot(), packageName, mimeGroup);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSystemPackage(@NonNull String packageName) {
+ return packageName.equals(mService.ensureSystemPackageName(snapshot(), packageName));
+ }
+
+ @Override
+ @Deprecated
+ public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+ mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+ return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
+ }
+
+ @Override
+ @Deprecated
+ public final void requestChecksums(@NonNull String packageName, boolean includeSplits,
+ @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+ @Nullable List trustedInstallers,
+ @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
+ @NonNull Executor executor, @NonNull Handler handler) {
+ mService.requestChecksumsInternal(snapshot(), packageName, includeSplits, optional,
+ required, trustedInstallers, onChecksumsReadyListener, userId, executor,
+ handler);
+ }
+
+ @Override
+ @Deprecated
+ public final boolean isPackageFrozen(@NonNull String packageName,
+ int callingUid, int userId) {
+ return snapshot().getPackageStartability(mService.getSafeMode(), packageName, callingUid, userId)
+ == PackageManagerService.PACKAGE_STARTABILITY_FROZEN;
+ }
+
+ @Override
+ @Deprecated
+ public final long deleteOatArtifactsOfPackage(String packageName) {
+ return mService.deleteOatArtifactsOfPackage(snapshot(), packageName);
+ }
+
+ @Override
+ @Deprecated
+ public final void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
+ boolean migrateAppsData) {
+ getAppDataHelper().reconcileAppsData(userId, flags, migrateAppsData);
+ }
+
+ @Override
+ @NonNull
+ public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
+ return snapshot().getSharedUserPackages(sharedUserAppId);
+ }
+
+ @Override
+ @Nullable
+ public SharedUserApi getSharedUserApi(int sharedUserAppId) {
+ return snapshot().getSharedUser(sharedUserAppId);
+ }
+
+ @NonNull
+ @Override
+ @Deprecated
+ public final PackageStateMutator.InitialState recordInitialState() {
+ return mService.recordInitialState();
+ }
+
+ @Nullable
+ @Override
+ @Deprecated
+ public final PackageStateMutator.Result commitPackageStateMutation(
+ @Nullable PackageStateMutator.InitialState state,
+ @NonNull Consumer<PackageStateMutator> consumer) {
+ return mService.commitPackageStateMutation(state, consumer);
+ }
+
+ @Override
+ @Deprecated
+ public final void shutdown() {
+ mService.shutdown();
+ }
+
+ @Override
+ @Deprecated
+ public final DynamicCodeLogger getDynamicCodeLogger() {
+ return getDexManager().getDynamicCodeLogger();
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e20a861..99c9c68 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -29,7 +29,6 @@
import static android.content.pm.PackageManager.MATCH_FACTORY_ONLY;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -83,21 +82,15 @@
import android.content.pm.IOnChecksumsReadyListener;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageInstallObserver2;
-import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageLoadingProgressCallback;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
-import android.content.pm.IPackageStatsObserver;
import android.content.pm.IncrementalStatesInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.InstantAppInfo;
import android.content.pm.InstantAppRequest;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
import android.content.pm.PackageChangeEvent;
import android.content.pm.PackageInfo;
@@ -109,11 +102,8 @@
import android.content.pm.PackagePartitions;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
@@ -122,7 +112,6 @@
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
-import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.PackageLite;
import android.content.res.Resources;
@@ -213,7 +202,6 @@
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.dex.ArtUtils;
import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.DynamicCodeLogger;
import com.android.server.pm.dex.ViewCompiler;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
@@ -225,10 +213,7 @@
import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import com.android.server.pm.pkg.AndroidPackageApi;
-import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SharedUserApi;
@@ -413,7 +398,8 @@
public @interface ScanFlags {}
/**
- * Used as the result code of the {@link #getPackageStartability}.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)}.
*/
@IntDef(value = {
PACKAGE_STARTABILITY_OK,
@@ -426,40 +412,43 @@
public @interface PackageStartability {}
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is allowed to start.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is allowed to start.
*/
public static final int PACKAGE_STARTABILITY_OK = 0;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's not found
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's not found
* (could be due to that package is invisible to the given user).
*/
public static final int PACKAGE_STARTABILITY_NOT_FOUND = 1;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's not a system app
- * and the system is running in safe mode.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's not a system
+ * app and the system is running in safe mode.
*/
public static final int PACKAGE_STARTABILITY_NOT_SYSTEM = 2;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it's currently frozen.
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it's currently
+ * frozen.
*/
public static final int PACKAGE_STARTABILITY_FROZEN = 3;
/**
- * Used as the result code of the {@link #getPackageStartability} to indicate
- * the given package is <b>not</b> allowed to start because it doesn't support
+ * Used as the result code of the {@link Computer#getPackageStartability(boolean, String, int,
+ * int)} to indicate the given package is <b>not</b> allowed to start because it doesn't support
* direct boot.
*/
public static final int PACKAGE_STARTABILITY_DIRECT_BOOT_UNSUPPORTED = 4;
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
- /** Extension of the compressed packages */
+ /**
+ * Extension of the compressed packages
+ */
public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
public final static String STUB_SUFFIX = "-Stub";
@@ -644,9 +633,6 @@
*/
boolean mPromoteSystemApps;
- // TODO: Make IPackageManager reference private to hide discouraged APIs
- final IPackageManagerImpl mIPackageManager;
- private final PackageManagerInternal mPmInternal;
private final TestUtilityService mTestUtilityService;
@Watched
@@ -1057,9 +1043,6 @@
// A lock-free cache for frequently called functions.
private volatile Computer mSnapshotComputer;
- // A trampoline that directs callers to either the live or snapshot computer.
- final ComputerTracker mComputer = new ComputerTracker(this);
-
// If true, the snapshot is invalid (stale). The attribute is static since it may be
// set from outside classes. The attribute may be set to true anywhere, although it
// should only be set true while holding mLock. However, the attribute id guaranteed
@@ -1088,6 +1071,8 @@
* Return the cached computer. The method will rebuild the cached computer if necessary.
* The live computer will be returned if snapshots are disabled.
*/
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ @NonNull
public Computer snapshotComputer() {
if (Thread.holdsLock(mLock)) {
// If the current thread holds mLock then it may have modified state but not
@@ -1247,15 +1232,15 @@
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
- () -> mInjector.getIncrementalManager(),
- () -> mPmInternal);
+ mInjector::getIncrementalManager,
+ () -> mInjector.getLocalService(PackageManagerInternal.class));
ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
trustedCerts, onChecksumsReadyListener, injector);
});
}
- private void requestChecksumsInternal(@NonNull String packageName, boolean includeSplits,
- @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
+ void requestChecksumsInternal(@NonNull Computer snapshot, @NonNull String packageName,
+ boolean includeSplits, @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
@Nullable List trustedInstallers,
@NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
@NonNull Executor executor, @NonNull Handler handler) {
@@ -1264,13 +1249,12 @@
Objects.requireNonNull(executor);
Objects.requireNonNull(handler);
- final ApplicationInfo applicationInfo = getApplicationInfoInternal(packageName, 0,
+ final ApplicationInfo applicationInfo = snapshot.getApplicationInfoInternal(packageName, 0,
Binder.getCallingUid(), userId);
if (applicationInfo == null) {
throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
}
- final InstallSourceInfo installSourceInfo =
- mIPackageManager.getInstallSourceInfo(packageName);
+ final InstallSourceInfo installSourceInfo = snapshot.getInstallSourceInfo(packageName);
final String installerPackageName =
installSourceInfo != null ? installSourceInfo.getInitiatingPackageName() : null;
@@ -1294,8 +1278,8 @@
ApkChecksums.Injector injector = new ApkChecksums.Injector(
() -> mContext,
() -> handler,
- () -> mInjector.getIncrementalManager(),
- () -> mPmInternal);
+ mInjector::getIncrementalManager,
+ () -> mInjector.getLocalService(PackageManagerInternal.class));
ApkChecksums.getChecksums(filesToChecksum, optional, required, installerPackageName,
trustedCerts, onChecksumsReadyListener, injector);
});
@@ -1440,15 +1424,15 @@
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
- (i, pm) -> AppsFilter.create(pm.mPmInternal, i),
+ (i, pm) -> AppsFilter.create(i, i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
- (i, pm) -> new DexManager(i.getContext(), pm.mIPackageManager,
- i.getPackageDexOptimizer(), i.getInstaller(), i.getInstallLock()),
- (i, pm) -> new ArtManagerService(i.getContext(), pm.mIPackageManager,
+ (i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
i.getInstaller(), i.getInstallLock()),
+ (i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),
+ i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
(i, pm) -> (IncrementalManager)
@@ -1470,7 +1454,7 @@
i.getContext(), pm, i::getScanningPackageParser),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
- (i, pm) -> new ModuleInfoProvider(i.getContext(), pm.mIPackageManager),
+ (i, pm) -> new ModuleInfoProvider(i.getContext()),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
@@ -1498,13 +1482,15 @@
final CompatChange.ChangeListener selinuxChangeListener = packageName -> {
synchronized (m.mInstallLock) {
- final PackageStateInternal packageState = m.getPackageStateInternal(packageName);
+ final Computer snapshot = m.snapshotComputer();
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName);
if (packageState == null) {
Slog.e(TAG, "Failed to find package setting " + packageName);
return;
}
AndroidPackage pkg = packageState.getPkg();
- SharedUserApi sharedUser = m.mComputer.getSharedUser(
+ SharedUserApi sharedUser = snapshot.getSharedUser(
packageState.getSharedUserAppId());
String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
@@ -1531,11 +1517,12 @@
selinuxChangeListener);
m.installAllowlistedSystemPackages();
- ServiceManager.addService("package", m.mIPackageManager);
+ IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
+ ServiceManager.addService("package", iPackageManager);
final PackageManagerNative pmn = new PackageManagerNative(m);
ServiceManager.addService("package_native", pmn);
LocalManagerRegistry.addManager(PackageManagerLocal.class, m.new PackageManagerLocalImpl());
- return Pair.create(m, m.mIPackageManager);
+ return Pair.create(m, iPackageManager);
}
/** Install/uninstall system packages for all users based on their user-type, as applicable. */
@@ -1641,8 +1628,6 @@
mPackageDexOptimizer = testParams.packageDexOptimizer;
mPackageParserCallback = testParams.packageParserCallback;
mPendingBroadcasts = testParams.pendingPackageBroadcasts;
- mIPackageManager = new IPackageManagerImpl();
- mPmInternal = testParams.pmInternal;
mTestUtilityService = testParams.testUtilityService;
mProcessLoggingHandler = testParams.processLoggingHandler;
mProtectedPackages = testParams.protectedPackages;
@@ -1703,7 +1688,6 @@
public PackageManagerService(PackageManagerServiceInjector injector, boolean onlyCore,
boolean factoryTest, final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
- mIPackageManager = new IPackageManagerImpl();
mIsEngBuild = isEngBuild;
mIsUserDebugBuild = isUserDebugBuild;
mSdkVersion = sdkVersion;
@@ -1734,10 +1718,9 @@
t.traceBegin("createSubComponents");
// Expose private service for system components to use.
- mPmInternal = new PackageManagerInternalImpl();
+ LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
LocalServices.addService(TestUtilityService.class, this);
mTestUtilityService = LocalServices.getService(TestUtilityService.class);
- LocalServices.addService(PackageManagerInternal.class, mPmInternal);
mUserManager = injector.getUserManagerService();
mUserNeedsBadging = new UserNeedsBadgingCache(mUserManager);
mComponentResolver = injector.getComponentResolver();
@@ -1755,7 +1738,7 @@
@Override
public boolean hasFeature(String feature) {
- return PackageManagerService.this.mIPackageManager.hasSystemFeature(feature, 0);
+ return PackageManagerService.this.hasSystemFeature(feature, 0);
}
};
@@ -1885,9 +1868,10 @@
final int dependencyCount = entry.dependencies.length;
for (int j = 0; j < dependencyCount; j++) {
final SharedLibraryInfo dependency =
- getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
+ computer.getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);
if (dependency != null) {
- getSharedLibraryInfo(name, undefinedVersion).addDependency(dependency);
+ computer.getSharedLibraryInfo(name, undefinedVersion)
+ .addDependency(dependency);
}
}
}
@@ -1899,7 +1883,7 @@
t.traceEnd();
t.traceBegin("read user settings");
- mFirstBoot = !mSettings.readLPw(mLiveComputer,
+ mFirstBoot = !mSettings.readLPw(computer,
mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
@@ -1980,19 +1964,26 @@
// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageNameImpl(computer);
- mComponentResolver.fixProtectedFilterPriorities(mPmInternal.getSetupWizardPackageName());
+ mComponentResolver.fixProtectedFilterPriorities(mSetupWizardPackage);
- mDefaultTextClassifierPackage = mIPackageManager.getDefaultTextClassifierPackageName();
- mSystemTextClassifierPackageName =
- mIPackageManager.getSystemTextClassifierPackageName();
- mConfiguratorPackage = getDeviceConfiguratorPackageName();
- mAppPredictionServicePackage = mIPackageManager.getAppPredictionServicePackageName();
- mIncidentReportApproverPackage =
- mIPackageManager.getIncidentReportApproverPackageName();
+ mDefaultTextClassifierPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_servicesExtensionPackage));
+ mSystemTextClassifierPackageName = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_defaultTextClassifierPackage));
+ mConfiguratorPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_deviceConfiguratorPackageName));
+ mAppPredictionServicePackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(R.string.config_defaultAppPredictionService));
+ mIncidentReportApproverPackage = ensureSystemPackageName(computer,
+ mContext.getString(R.string.config_incidentReportApproverPackage));
mRetailDemoPackage = getRetailDemoPackageName();
- mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
- mRecentsPackage = getRecentsPackageName();
- mAmbientContextDetectionPackage = getAmbientContextDetectionPackageName();
+ mOverlayConfigSignaturePackage = ensureSystemPackageName(computer,
+ mInjector.getSystemConfig().getOverlayConfigSignaturePackage());
+ mRecentsPackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(R.string.config_recentsComponentName));
+ mAmbientContextDetectionPackage = ensureSystemPackageName(computer,
+ getPackageFromComponentString(
+ R.string.config_defaultAmbientContextDetectionService));
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -2126,8 +2117,8 @@
mDomainVerificationManager.setProxy(domainVerificationProxy);
- mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr();
- mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(
+ mServicesExtensionPackageName = getRequiredServicesExtensionPackageLPr(computer);
+ mSharedSystemSharedLibraryPackageName = getRequiredSharedLibrary(computer,
PackageManager.SYSTEM_SHARED_LIBRARY_SHARED,
SharedLibraryInfo.VERSION_UNDEFINED);
} else {
@@ -2143,11 +2134,11 @@
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr(computer);
mSettings.setPermissionControllerVersion(
- mIPackageManager.getPackageInfo(mRequiredPermissionControllerPackage, 0,
+ computer.getPackageInfo(mRequiredPermissionControllerPackage, 0,
UserHandle.USER_SYSTEM).getLongVersionCode());
// Resolve the sdk sandbox package
- mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName();
+ mRequiredSdkSandboxPackage = getRequiredSdkSandboxPackageName(computer);
// Initialize InstantAppRegistry's Instant App list for all users.
for (AndroidPackage pkg : mPackages.values()) {
@@ -2155,7 +2146,8 @@
continue;
}
for (int userId : userIds) {
- final PackageStateInternal ps = getPackageStateInternal(pkg.getPackageName());
+ final PackageStateInternal ps =
+ computer.getPackageStateInternal(pkg.getPackageName());
if (ps == null || !ps.getUserStateOrDefault(userId).isInstantApp()
|| !ps.getUserStateOrDefault(userId).isInstalled()) {
continue;
@@ -2165,7 +2157,7 @@
}
mInstallerService = mInjector.getPackageInstallerService();
- final ComponentName instantAppResolverComponent = getInstantAppResolver();
+ final ComponentName instantAppResolverComponent = getInstantAppResolver(computer);
if (instantAppResolverComponent != null) {
if (DEBUG_INSTANT) {
Slog.d(TAG, "Set ephemeral resolver: " + instantAppResolverComponent);
@@ -2191,7 +2183,7 @@
// scanning).
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
for (int userId : userIds) {
- userPackages.put(userId, mIPackageManager.getInstalledPackages(/*flags*/ 0, userId)
+ userPackages.put(userId, computer.getInstalledPackages(/*flags*/ 0, userId)
.getList());
}
mDexManager.load(userPackages);
@@ -2202,7 +2194,7 @@
SystemClock.uptimeMillis() - startTime);
}
- // Rebild the live computer since some attributes have been rebuilt.
+ // Rebuild the live computer since some attributes have been rebuilt.
mLiveComputer = createLiveComputer();
} // synchronized (mLock)
@@ -2210,6 +2202,7 @@
// CHECKSTYLE:ON IndentationCheck
mModuleInfoProvider = mInjector.getModuleInfoProvider();
+
mInjector.getSystemWrapper().enablePackageCaches();
// Now after opening every single application zip, make sure they
@@ -2281,8 +2274,9 @@
}
@NonNull
- private String getRequiredSharedLibrary(@NonNull String name, int version) {
- SharedLibraryInfo libraryInfo = getSharedLibraryInfo(name, version);
+ private String getRequiredSharedLibrary(@NonNull Computer snapshot, @NonNull String name,
+ int version) {
+ SharedLibraryInfo libraryInfo = snapshot.getSharedLibraryInfo(name, version);
if (libraryInfo == null) {
throw new IllegalStateException("Missing required shared library:" + name);
}
@@ -2294,9 +2288,9 @@
}
@NonNull
- private String getRequiredServicesExtensionPackageLPr() {
+ private String getRequiredServicesExtensionPackageLPr(@NonNull Computer computer) {
String servicesExtensionPackage =
- ensureSystemPackageName(
+ ensureSystemPackageName(computer,
mContext.getString(R.string.config_servicesExtensionPackage));
if (TextUtils.isEmpty(servicesExtensionPackage)) {
throw new RuntimeException(
@@ -2375,7 +2369,7 @@
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
- if (mIPackageManager.checkPermission(
+ if (checkPermission(
android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, packageName,
UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
@@ -2405,7 +2399,7 @@
for (int i = 0; i < N; i++) {
final ResolveInfo cur = matches.get(i);
final String packageName = cur.getComponentInfo().packageName;
- if (mIPackageManager.checkPermission(
+ if (checkPermission(
android.Manifest.permission.DOMAIN_VERIFICATION_AGENT, packageName,
UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Domain verification agent found but does not hold permission: "
@@ -2414,7 +2408,7 @@
}
if (best == null || cur.priority > best.priority) {
- if (mComputer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
+ if (computer.isComponentEffectivelyEnabled(cur.getComponentInfo(),
UserHandle.USER_SYSTEM)) {
best = cur;
} else {
@@ -2430,7 +2424,7 @@
return null;
}
- private @Nullable ComponentName getInstantAppResolver() {
+ @Nullable ComponentName getInstantAppResolver(@NonNull Computer snapshot) {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
@@ -2446,7 +2440,7 @@
| MATCH_DIRECT_BOOT_UNAWARE
| (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE);
- List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
+ List<ResolveInfo> resolvers = snapshot.queryIntentServicesInternal(resolverIntent, null,
resolveFlags, UserHandle.USER_SYSTEM, callingUid, false /*includeInstantApps*/);
final int N = resolvers.size();
if (N == 0) {
@@ -2519,7 +2513,7 @@
Iterator<ResolveInfo> iter = matches.iterator();
while (iter.hasNext()) {
final ResolveInfo rInfo = iter.next();
- if (mIPackageManager.checkPermission(
+ if (checkPermission(
Manifest.permission.INSTALL_PACKAGES,
rInfo.activityInfo.packageName, 0) == PERMISSION_GRANTED || mIsEngBuild) {
continue;
@@ -2550,48 +2544,6 @@
return matches.get(0).getComponentInfo().getComponentName();
}
- /**
- * @see #shouldFilterApplication(PackageStateInternal, int, ComponentName, int, int)
- */
- boolean shouldFilterApplication(
- @Nullable PackageStateInternal ps, int callingUid, int userId) {
- return mComputer.shouldFilterApplication(
- ps, callingUid, userId);
- }
-
- private @PackageStartability int getPackageStartability(String packageName,
- int callingUid, int userId) {
- return mComputer.getPackageStartability(mSafeMode, packageName, callingUid, userId);
- }
-
- /**
- * Returns whether or not a full application can see an instant application.
- * <p>
- * Currently, there are four cases in which this can occur:
- * <ol>
- * <li>The calling application is a "special" process. Special processes
- * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
- * <li>The calling application has the permission
- * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
- * <li>The calling application is the default launcher on the
- * system partition.</li>
- * <li>The calling application is the default app prediction service.</li>
- * </ol>
- */
- boolean canViewInstantApps(int callingUid, int userId) {
- return mComputer.canViewInstantApps(callingUid, userId);
- }
-
- private PackageInfo generatePackageInfo(@NonNull PackageStateInternal ps,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.generatePackageInfo(ps, flags, userId);
- }
-
- int getPackageUidInternal(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId, int callingUid) {
- return mComputer.getPackageUidInternal(packageName, flags, userId, callingUid);
- }
-
public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
// Because this is accessed via the package manager service AIDL,
// go through the permission manager service AIDL
@@ -2600,19 +2552,6 @@
}
/**
- * Important: The provided filterCallingUid is used exclusively to filter out applications
- * that can be seen based on user state. It's typically the original caller uid prior
- * to clearing. Because it can only be provided by trusted code, its value can be
- * trusted and will be used as-is; unlike userId which will be validated by this method.
- */
- private ApplicationInfo getApplicationInfoInternal(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return mComputer.getApplicationInfoInternal(packageName, flags,
- filterCallingUid, userId);
- }
-
- /**
* Blocking call to clear all cached app data above quota.
*/
public void freeAllAppCacheAboveQuota(String volumeUuid) throws IOException {
@@ -2648,7 +2587,7 @@
// 2. Consider preloaded data (after 1w honeymoon, unless aggressive)
if (internalVolume && (aggressive || SystemProperties
.getBoolean("persist.sys.preloads.file_cache_expired", false))) {
- mIPackageManager.deletePreloadsFileCache();
+ deletePreloadsFileCache();
if (file.getUsableSpace() >= bytes) return;
}
@@ -2769,43 +2708,6 @@
return recommendedInstallLocation;
}
- /**
- * Update given flags when being used to request {@link ResolveInfo}.
- * <p>Instant apps are resolved specially, depending upon context. Minimally,
- * {@code}flags{@code} must have the {@link PackageManager#MATCH_INSTANT}
- * flag set. However, this flag is only honoured in three circumstances:
- * <ul>
- * <li>when called from a system process</li>
- * <li>when the caller holds the permission {@code android.permission.ACCESS_INSTANT_APPS}</li>
- * <li>when resolution occurs to start an activity with a {@code android.intent.action.VIEW}
- * action and a {@code android.intent.category.BROWSABLE} category</li>
- * </ul>
- */
- long updateFlagsForResolve(long flags, int userId, int callingUid,
- boolean wantInstantApps, boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
- return mComputer.updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, isImplicitImageCaptureIntentAndNotSetByDpc);
- }
-
- /**
- * Important: The provided filterCallingUid is used exclusively to filter out activities
- * that can be seen based on user state. It's typically the original caller uid prior
- * to clearing. Because it can only be provided by trusted code, its value can be
- * trusted and will be used as-is; unlike userId which will be validated by this method.
- */
- private ActivityInfo getActivityInfoInternal(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int filterCallingUid, int userId) {
- return mComputer.getActivityInfoInternal(component, flags,
- filterCallingUid, userId);
- }
-
- @Nullable
- List<VersionedPackage> getPackagesUsingSharedLibrary(
- SharedLibraryInfo libInfo, @PackageManager.PackageInfoFlagsBits long flags,
- int callingUid, int userId) {
- return mComputer.getPackagesUsingSharedLibrary(libInfo, flags, callingUid, userId);
- }
-
public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) {
return mModuleInfoProvider.getModuleInfo(packageName, flags);
}
@@ -2840,7 +2742,7 @@
return mRequiredInstallerPackage;
}
- private void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
+ void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
Intent origIntent, String resolvedType, String callingPackage,
@Nullable String callingFeatureId, boolean isRequesterInstantApp,
Bundle verificationBundle, int userId) {
@@ -2852,31 +2754,6 @@
mHandler.sendMessage(msg);
}
- /**
- * From Android R, camera intents have to match system apps. The only exception to this is if
- * the DPC has set the camera persistent preferred activity. This case was introduced
- * because it is important that the DPC has the ability to set both system and non-system
- * camera persistent preferred activities.
- *
- * @return {@code true} if the intent is a camera intent and the persistent preferred
- * activity was not set by the DPC.
- */
- @GuardedBy("mLock")
- boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags) {
- return mComputer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
- resolvedType, flags);
- }
-
- @GuardedBy("mLock")
- ResolveInfo findPersistentPreferredActivityLP(Intent intent,
- String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query, boolean debug,
- int userId) {
- return mComputer.findPersistentPreferredActivityLP(intent,
- resolvedType, flags, query, debug, userId);
- }
-
// findPreferredActivityBody returns two items: a "things changed" flag and a
// ResolveInfo, which is the preferred activity itself.
static class FindPreferredActivityBodyResult {
@@ -2884,24 +2761,6 @@
ResolveInfo mPreferredResolveInfo;
}
- FindPreferredActivityBodyResult findPreferredActivityInternal(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- List<ResolveInfo> query, boolean always,
- boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
- return mComputer.findPreferredActivityInternal(
- intent, resolvedType, flags,
- query, always,
- removeMatches, debug, userId, queryMayBeFiltered);
- }
-
- /**
- * Returns the package name of the calling Uid if it's an instant app. If it isn't
- * instant, returns {@code null}.
- */
- String getInstantAppPackageName(int callingUid) {
- return mComputer.getInstantAppPackageName(callingUid);
- }
-
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(@NonNull Computer snapshot,
Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
@UserIdInt int userId) {
@@ -2909,24 +2768,6 @@
snapshot, intent, resolvedType, flags, userId, Binder.getCallingUid()));
}
- @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId,
- int callingUid, boolean includeInstantApps) {
- return mComputer.queryIntentServicesInternal(intent,
- resolvedType, flags, userId, callingUid,
- includeInstantApps);
- }
-
- private boolean isInstantAppInternal(String packageName, @UserIdInt int userId,
- int callingUid) {
- return mComputer.isInstantAppInternal(packageName, userId,
- callingUid);
- }
-
- boolean isCallerSameApp(String packageName, int uid) {
- return mComputer.isCallerSameApp(packageName, uid);
- }
-
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
@@ -2943,39 +2784,6 @@
return packageName + STATIC_SHARED_LIB_DELIMITER + libraryVersion;
}
- /**
- * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
- * or INTERACT_ACROSS_USERS_FULL permissions, if the {@code userId} is not for the caller.
- *
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param message the message to log on security exception
- */
- void enforceCrossUserPermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- mComputer.enforceCrossUserPermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- }
-
- /**
- * Checks if the request is from the system or an app that has the appropriate cross-user
- * permissions defined as follows:
- * <ul>
- * <li>INTERACT_ACROSS_USERS_FULL if {@code requireFullPermission} is true.</li>
- * <li>INTERACT_ACROSS_USERS if the given {@code userId} is in a different profile group
- * to the caller.</li>
- * <li>Otherwise, INTERACT_ACROSS_PROFILES if the given {@code userId} is in the same profile
- * group as the caller.</li>
- * </ul>
- *
- * @param checkShell whether to prevent shell from access if there's a debugging restriction
- * @param message the message to log on security exception
- */
- private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
- boolean requireFullPermission, boolean checkShell, String message) {
- mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
- requireFullPermission, checkShell, message);
- }
-
public void performFstrimIfNeeded() {
PackageManagerServiceUtils.enforceSystemOrRoot("Only the system can request fstrim");
@@ -3033,17 +2841,6 @@
return mDexManager;
}
- @NonNull
- List<PackageStateInternal> findSharedNonSystemLibraries(
- @NonNull PackageStateInternal pkgSetting) {
- return mComputer.findSharedNonSystemLibraries(pkgSetting);
- }
-
- @Nullable
- SharedLibraryInfo getSharedLibraryInfo(String name, long version) {
- return mComputer.getSharedLibraryInfo(name, version);
- }
-
public void shutdown() {
mCompilerStats.writeNow();
mDexManager.writePackageDexUsageNow();
@@ -3141,14 +2938,14 @@
mPackageObserverHelper.notifyRemoved(packageName, uid);
}
- void sendPackageAddedForUser(String packageName, @NonNull PackageStateInternal packageState,
- int userId, int dataLoaderType) {
+ void sendPackageAddedForUser(@NonNull Computer snapshot, String packageName,
+ @NonNull PackageStateInternal packageState, int userId, int dataLoaderType) {
final PackageUserStateInternal userState = packageState.getUserStateOrDefault(userId);
final boolean isSystem = packageState.isSystem();
final boolean isInstantApp = userState.isInstantApp();
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- sendPackageAddedForNewUsers(packageName, isSystem /*sendBootCompleted*/,
+ sendPackageAddedForNewUsers(snapshot, packageName, isSystem /*sendBootCompleted*/,
false /*startReceiver*/, packageState.getAppId(), userIds, instantUserIds,
dataLoaderType);
@@ -3160,15 +2957,15 @@
}
@Override
- public void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, @AppIdInt int appId, int[] userIds, int[] instantUserIds,
- int dataLoaderType) {
+ public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+ boolean sendBootCompleted, boolean includeStopped, @AppIdInt int appId, int[] userIds,
+ int[] instantUserIds, int dataLoaderType) {
if (ArrayUtils.isEmpty(userIds) && ArrayUtils.isEmpty(instantUserIds)) {
return;
}
SparseArray<int[]> broadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageStateInternal(packageName, Process.SYSTEM_UID),
- userIds, getPackageStates());
+ snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID),
+ userIds, snapshot.getPackageStates());
mHandler.post(() -> mBroadcastHelper.sendPackageAddedForNewUsers(
packageName, appId, userIds, instantUserIds, dataLoaderType, broadcastAllowList));
if (sendBootCompleted && !ArrayUtils.isEmpty(userIds)) {
@@ -3202,8 +2999,8 @@
return false;
}
- private void enforceCanSetPackagesSuspendedAsUser(String callingPackage, int callingUid,
- int userId, String callingMethod) {
+ private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
+ String callingPackage, int callingUid, int userId, String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
@@ -3212,7 +3009,7 @@
final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- final int ownerUid = mIPackageManager.getPackageUid(ownerPackage, 0, userId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
if (ownerUid == callingUid) {
return;
}
@@ -3221,7 +3018,7 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
callingMethod);
- final int packageUid = mIPackageManager.getPackageUid(callingPackage, 0, userId);
+ final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
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
@@ -3242,13 +3039,9 @@
allPackages, suspendingPackage::equals, userId);
}
- private boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return mComputer.isSuspendingAnyPackages(suspendingPackage, userId);
- }
-
- void removeAllDistractingPackageRestrictions(int userId) {
- final String[] allPackages = mComputer.getAllAvailablePackageNames();
- removeDistractingPackageRestrictions(allPackages, userId);
+ void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
+ final String[] allPackages = snapshot.getAllAvailablePackageNames();
+ removeDistractingPackageRestrictions(snapshot, allPackages, userId);
}
/**
@@ -3260,11 +3053,12 @@
* @param packagesToChange The packages on which restrictions are to be removed.
* @param userId the user for which changes are taking place.
*/
- private void removeDistractingPackageRestrictions(String[] packagesToChange, int userId) {
+ void removeDistractingPackageRestrictions(@NonNull Computer snapshot,
+ String[] packagesToChange, int userId) {
final List<String> changedPackages = new ArrayList<>();
final IntArray changedUids = new IntArray();
for (String packageName : packagesToChange) {
- final PackageStateInternal ps = getPackageStateInternal(packageName);
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
if (ps != null && ps.getUserStateOrDefault(userId).getDistractionFlags() != 0) {
changedPackages.add(ps.getPackageName());
changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
@@ -3287,7 +3081,7 @@
}
}
- private void setEnableRollbackCode(int token, int enableRollbackCode) {
+ void setEnableRollbackCode(int token, int enableRollbackCode) {
final Message msg = mHandler.obtainMessage(ENABLE_ROLLBACK_STATUS);
msg.arg1 = token;
msg.arg2 = enableRollbackCode;
@@ -3334,7 +3128,7 @@
if (DEBUG_BACKUP) {
Slog.i(TAG, "Package " + packageName + " sending normal FIRST_LAUNCH");
}
- final boolean isInstantApp = isInstantAppInternal(
+ final boolean isInstantApp = snapshotComputer().isInstantAppInternal(
packageName, userId, Process.SYSTEM_UID);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
@@ -3384,30 +3178,22 @@
versionedPackage, observer, userId, deleteFlags, false);
}
- private String resolveExternalPackageName(AndroidPackage pkg) {
- return mComputer.resolveExternalPackageName(pkg);
- }
-
- String resolveInternalPackageName(String packageName, long versionCode) {
- return mComputer.resolveInternalPackageName(packageName, versionCode);
- }
-
- boolean isCallerVerifier(int callingUid) {
+ boolean isCallerVerifier(@NonNull Computer snapshot, int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
- return mRequiredVerifierPackage != null && callingUid == mIPackageManager.getPackageUid(
+ return mRequiredVerifierPackage != null && callingUid == snapshot.getPackageUid(
mRequiredVerifierPackage, 0, callingUserId);
}
- public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
+ public boolean isPackageDeviceAdminOnAnyUser(@NonNull Computer snapshot, String packageName) {
final int callingUid = Binder.getCallingUid();
- if (mIPackageManager.checkUidPermission(android.Manifest.permission.MANAGE_USERS,
- callingUid) != PERMISSION_GRANTED) {
+ if (snapshot.checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid)
+ != PERMISSION_GRANTED) {
EventLog.writeEvent(0x534e4554, "128599183", -1, "");
throw new SecurityException(android.Manifest.permission.MANAGE_USERS
+ " permission is required to call this API");
}
- if (getInstantAppPackageName(callingUid) != null
- && !isCallerSameApp(packageName, callingUid)) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null
+ && !snapshot.isCallerSameApp(packageName, callingUid)) {
return false;
}
return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
@@ -3456,14 +3242,15 @@
return mDevicePolicyManager;
}
- private boolean clearApplicationUserDataLIF(String packageName, int userId) {
+ private boolean clearApplicationUserDataLIF(@NonNull Computer snapshot, String packageName,
+ int userId) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
}
// Try finding details about the requested package
- AndroidPackage pkg = getPackage(packageName);
+ AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
return false;
@@ -3486,8 +3273,8 @@
} else {
flags = 0;
}
- mAppDataHelper.prepareAppDataContentsLIF(pkg, getPackageStateInternal(packageName), userId,
- flags);
+ mAppDataHelper.prepareAppDataContentsLIF(pkg, snapshot.getPackageStateInternal(packageName),
+ userId, flags);
return true;
}
@@ -3538,10 +3325,6 @@
}
}
- int getUidTargetSdkVersion(int uid) {
- return mComputer.getUidTargetSdkVersion(uid);
- }
-
void postPreferredActivityChangedBroadcast(int userId) {
mHandler.post(() -> mBroadcastHelper.sendPreferredActivityChangedBroadcast(userId));
}
@@ -3562,18 +3345,19 @@
// Persistent preferred activity might have came into effect due to this
// install.
- mPreferredActivityHelper.updateDefaultHomeNotLocked(userId);
+ mPreferredActivityHelper.updateDefaultHomeNotLocked(snapshotComputer(), userId);
}
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void addCrossProfileIntentFilter(WatchedIntentFilter intentFilter, String ownerPackage,
- int sourceUserId, int targetUserId, int flags) {
+ public void addCrossProfileIntentFilter(@NonNull Computer snapshot,
+ WatchedIntentFilter intentFilter, String ownerPackage, int sourceUserId,
+ int targetUserId, int flags) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
int callingUid = Binder.getCallingUid();
- enforceOwnerRights(ownerPackage, callingUid);
+ enforceOwnerRights(snapshot, ownerPackage, callingUid);
PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
if (intentFilter.countActions() == 0) {
@@ -3601,18 +3385,18 @@
}
// Enforcing that callingUid is owning pkg on userId
- private void enforceOwnerRights(String pkg, int callingUid) {
+ private void enforceOwnerRights(@NonNull Computer snapshot, String pkg, int callingUid) {
// The system owns everything.
if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return;
}
- final String[] callerPackageNames = mIPackageManager.getPackagesForUid(callingUid);
+ final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
if (!ArrayUtils.contains(callerPackageNames, pkg)) {
throw new SecurityException("Calling uid " + callingUid
+ " does not own package " + pkg);
}
final int callingUserId = UserHandle.getUserId(callingUid);
- PackageInfo pi = mIPackageManager.getPackageInfo(pkg, 0, callingUserId);
+ PackageInfo pi = snapshot.getPackageInfo(pkg, 0, callingUserId);
if (pi == null) {
throw new IllegalArgumentException("Unknown package " + pkg + " on user "
+ callingUserId);
@@ -3626,29 +3410,13 @@
}
final UserInfo parent = ums.getProfileParent(userId);
final int launcherUid = (parent != null) ? parent.id : userId;
- final ComponentName launcherComponent = getDefaultHomeActivity(launcherUid);
+ // TODO: Should this snapshot be moved further up?
+ final ComponentName launcherComponent = snapshotComputer()
+ .getDefaultHomeActivity(launcherUid);
mBroadcastHelper.sendSessionCommitBroadcast(sessionInfo, userId, launcherUid,
launcherComponent, mAppPredictionServicePackage);
}
- /**
- * Report the 'Home' activity which is currently set as "always use this one". If non is set
- * then reports the most likely home activity or null if there are more than one.
- */
- private ComponentName getDefaultHomeActivity(int userId) {
- return mComputer.getDefaultHomeActivity(userId);
- }
-
- Intent getHomeIntent() {
- return mComputer.getHomeIntent();
- }
-
- ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- return mComputer.getHomeActivitiesAsUser(allHomeCandidates,
- userId);
- }
-
private @Nullable String getSetupWizardPackageNameImpl(@NonNull Computer computer) {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_SETUP_WIZARD);
@@ -3682,10 +3450,11 @@
}
}
- private @NonNull String getRequiredSdkSandboxPackageName() {
+ @NonNull
+ private static String getRequiredSdkSandboxPackageName(@NonNull Computer computer) {
final Intent intent = new Intent(SdkSandboxManagerLocal.SERVICE_INTERFACE);
- final List<ResolveInfo> matches = queryIntentServicesInternal(
+ final List<ResolveInfo> matches = computer.queryIntentServicesInternal(
intent,
/* resolvedType= */ null,
MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
@@ -3701,22 +3470,6 @@
}
@Nullable
- private String getDeviceConfiguratorPackageName() {
- return ensureSystemPackageName(mContext.getString(
- R.string.config_deviceConfiguratorPackageName));
- }
-
- public @Nullable String getAmbientContextDetectionPackageName() {
- return ensureSystemPackageName(getPackageFromComponentString(
- R.string.config_defaultAmbientContextDetectionService));
- }
-
- public String getOverlayConfigSignaturePackageName() {
- return ensureSystemPackageName(mInjector.getSystemConfig()
- .getOverlayConfigSignaturePackage());
- }
-
- @Nullable
private String getRetailDemoPackageName() {
final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
final String predefinedSignature = mContext.getString(
@@ -3752,14 +3505,7 @@
}
@Nullable
- private String getRecentsPackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_recentsComponentName));
-
- }
-
- @Nullable
- private String getPackageFromComponentString(@StringRes int stringResId) {
+ String getPackageFromComponentString(@StringRes int stringResId) {
final String componentString = mContext.getString(stringResId);
if (TextUtils.isEmpty(componentString)) {
return null;
@@ -3772,16 +3518,17 @@
}
@Nullable
- private String ensureSystemPackageName(@Nullable String packageName) {
+ String ensureSystemPackageName(@NonNull Computer snapshot,
+ @Nullable String packageName) {
if (packageName == null) {
return null;
}
final long token = Binder.clearCallingIdentity();
try {
- if (mIPackageManager.getPackageInfo(packageName, MATCH_FACTORY_ONLY,
+ if (snapshot.getPackageInfo(packageName, MATCH_FACTORY_ONLY,
UserHandle.USER_SYSTEM) == null) {
PackageInfo packageInfo =
- mIPackageManager.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
+ snapshot.getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
if (packageInfo != null) {
EventLog.writeEvent(0x534e4554, "145981139", packageInfo.applicationInfo.uid,
"");
@@ -3863,8 +3610,10 @@
private void setEnabledSettings(List<ComponentEnabledSetting> settings, int userId,
String callingPackage) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
- true /* checkShell */, "set enabled");
+ // TODO: This method is not properly snapshotified beyond this call
+ final Computer preLockSnapshot = snapshotComputer();
+ preLockSnapshot.enforceCrossUserPermission(callingUid, userId,
+ false /* requireFullPermission */, true /* checkShell */, "set enabled");
final int targetSize = settings.size();
for (int i = 0; i < targetSize; i++) {
@@ -3920,6 +3669,7 @@
final Map<String, PackageSetting> pkgSettings = new ArrayMap<>(targetSize);
// reader
synchronized (mLock) {
+ final Computer snapshot = snapshotComputer();
// Checks for target packages
for (int i = 0; i < targetSize; i++) {
final ComponentEnabledSetting setting = settings.get(i);
@@ -3929,13 +3679,13 @@
continue;
}
final boolean isCallerTargetApp = ArrayUtils.contains(
- mIPackageManager.getPackagesForUid(callingUid), packageName);
+ snapshot.getPackagesForUid(callingUid), packageName);
final PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
// Limit who can change which apps
if (!isCallerTargetApp) {
// Don't allow apps that don't have permission to modify other apps
if (!allowedByPermission
- || shouldFilterApplication(pkgSetting, callingUid, userId)) {
+ || snapshot.shouldFilterApplication(pkgSetting, callingUid, userId)) {
throw new SecurityException("Attempt to change component state; "
+ "pid=" + Binder.getCallingPid()
+ ", uid=" + callingUid
@@ -4108,12 +3858,13 @@
final long callingId = Binder.clearCallingIdentity();
try {
+ final Computer newSnapshot = snapshotComputer();
for (int i = 0; i < sendNowBroadcasts.size(); i++) {
final String packageName = sendNowBroadcasts.keyAt(i);
final ArrayList<String> components = sendNowBroadcasts.valueAt(i);
final int packageUid = UserHandle.getUid(
userId, pkgSettings.get(packageName).getAppId());
- sendPackageChangedBroadcast(packageName, false /* dontKillApp */,
+ sendPackageChangedBroadcast(newSnapshot, packageName, false /* dontKillApp */,
components, packageUid, null /* reason */);
}
} finally {
@@ -4137,13 +3888,13 @@
pkgSetting.setEnabled(newState, userId, callingPackage);
if ((newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED)
- && mIPackageManager.checkPermission(Manifest.permission.SUSPEND_APPS,
- packageName, userId) == PERMISSION_GRANTED) {
+ && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
+ == PERMISSION_GRANTED) {
// This app should not generally be allowed to get disabled by the UI, but
// if it ever does, we don't want to end up with some of the user's apps
// permanently suspended.
unsuspendForSuspendingPackage(computer, packageName, userId);
- removeAllDistractingPackageRestrictions(userId);
+ removeAllDistractingPackageRestrictions(computer, userId);
}
success = true;
} else {
@@ -4194,25 +3945,20 @@
}
}
- void sendPackageChangedBroadcast(String packageName,
+ void sendPackageChangedBroadcast(@NonNull Computer snapshot, String packageName,
boolean dontKillApp, ArrayList<String> componentNames, int packageUid, String reason) {
final int userId = UserHandle.getUserId(packageUid);
- final boolean isInstantApp = isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
+ final boolean isInstantApp =
+ snapshot.isInstantAppInternal(packageName, userId, Process.SYSTEM_UID);
final int[] userIds = isInstantApp ? EMPTY_INT_ARRAY : new int[] { userId };
final int[] instantUserIds = isInstantApp ? new int[] { userId } : EMPTY_INT_ARRAY;
- final SparseArray<int[]> broadcastAllowList = getBroadcastAllowList(
+ final SparseArray<int[]> broadcastAllowList = snapshot.getBroadcastAllowList(
packageName, userIds, isInstantApp);
mHandler.post(() -> mBroadcastHelper.sendPackageChangedBroadcast(
packageName, dontKillApp, componentNames, packageUid, reason, userIds,
instantUserIds, broadcastAllowList));
}
- @Nullable
- private SparseArray<int[]> getBroadcastAllowList(@NonNull String packageName,
- @UserIdInt int[] userIds, boolean isInstantApp) {
- return mComputer.getBroadcastAllowList(packageName, userIds, isInstantApp);
- }
-
/**
* Used by SystemServer
*/
@@ -4296,7 +4042,7 @@
// Now that we're mostly running, clean up stale users and apps
mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
- storageEventHelper.reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
+ storageEventHelper.reconcileApps(snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.onSystemReady();
@@ -4308,7 +4054,7 @@
final int livingUserCount = livingUsers.size();
for (int i = 0; i < livingUserCount; i++) {
final int userId = livingUsers.get(i).id;
- if (mPmInternal.isPermissionUpgradeNeeded(userId)) {
+ if (mSettings.isPermissionUpgradeNeeded(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
@@ -4350,11 +4096,12 @@
if (packageName == null) {
return;
}
- AndroidPackage pkg = mPackages.get(packageName);
+ final Computer snapshot = snapshotComputer();
+ AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
return;
}
- sendPackageChangedBroadcast(pkg.getPackageName(),
+ sendPackageChangedBroadcast(snapshot, pkg.getPackageName(),
true /* dontKillApp */,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(),
@@ -4407,14 +4154,6 @@
mSnapshotStatistics.dump(pw, " ", now, hits, -1, isBrief);
}
- /**
- * Dump package manager states to the file according to a given dumping type of
- * {@link DumpState}.
- */
- void dumpComputer(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState) {
- mComputer.dump(type, fd, pw, dumpState);
- }
-
//TODO: b/111402650
private void disableSkuSpecificApps() {
String[] apkList = mContext.getResources().getStringArray(
@@ -4428,10 +4167,11 @@
if (!TextUtils.isEmpty(sku) && ArrayUtils.contains(skuArray, sku)) {
return;
}
+ final Computer snapshot = snapshotComputer();
for (String packageName : apkList) {
- mIPackageManager.setSystemAppHiddenUntilInstalled(packageName, true);
+ setSystemAppHiddenUntilInstalled(snapshot, packageName, true);
for (UserInfo user : mInjector.getUserManagerInternal().getUsers(false)) {
- mIPackageManager.setSystemAppInstallState(packageName, false, user.id);
+ setSystemAppInstallState(snapshot, packageName, false, user.id);
}
}
}
@@ -4524,7 +4264,7 @@
mPermissionManager.writeLegacyPermissionStateTEMP();
mSettings.readPermissionStateForUserSyncLPr(userId);
mPermissionManager.readLegacyPermissionStateTEMP();
- return mPmInternal.isPermissionUpgradeNeeded(userId);
+ return mSettings.isPermissionUpgradeNeeded(userId);
}
}
@@ -4544,12 +4284,8 @@
}
}
- boolean userNeedsBadging(int userId) {
- return mUserNeedsBadging.get(userId);
- }
-
- private void deletePackageIfUnused(final String packageName) {
- PackageStateInternal ps = getPackageStateInternal(packageName);
+ private void deletePackageIfUnused(@NonNull Computer snapshot, final String packageName) {
+ PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
if (ps == null) {
return;
}
@@ -4567,41 +4303,101 @@
0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/));
}
- private AndroidPackage getPackage(String packageName) {
- return mComputer.getPackage(packageName);
+ void deletePreloadsFileCache() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
+ "deletePreloadsFileCache");
+ File dir = Environment.getDataPreloadsFileCacheDirectory();
+ Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir);
+ FileUtils.deleteContents(dir);
}
- private AndroidPackage getPackage(int uid) {
- return mComputer.getPackage(uid);
+ void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
+ boolean hidden) {
+ final int callingUid = Binder.getCallingUid();
+ final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+ || callingUid == Process.SYSTEM_UID;
+ if (!calledFromSystemOrPhone) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ "setSystemAppHiddenUntilInstalled");
+ }
+
+ final PackageStateInternal stateRead = snapshot.getPackageStateInternal(packageName);
+ if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
+ return;
+ }
+ if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+ throw new SecurityException("Only system or phone callers can modify core apps");
+ }
+
+ commitPackageStateMutation(null, mutator -> {
+ mutator.forPackage(packageName)
+ .setHiddenUntilInstalled(hidden);
+ mutator.forDisabledSystemPackage(packageName)
+ .setHiddenUntilInstalled(hidden);
+ });
}
- private SigningDetails getSigningDetails(@NonNull String packageName) {
- return mComputer.getSigningDetails(packageName);
+ boolean setSystemAppInstallState(@NonNull Computer snapshot, String packageName,
+ boolean installed, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
+ || callingUid == Process.SYSTEM_UID;
+ if (!calledFromSystemOrPhone) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
+ "setSystemAppHiddenUntilInstalled");
+ }
+
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ // The target app should always be in system
+ if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
+ return false;
+ }
+ if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
+ throw new SecurityException("Only system or phone callers can modify core apps");
+ }
+ // Check if the install state is the same
+ if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
+ return false;
+ }
+
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ if (installed) {
+ // install the app from uninstalled state
+ mInstallPackageHelper.installExistingPackageAsUser(
+ packageName,
+ userId,
+ PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
+ PackageManager.INSTALL_REASON_DEVICE_SETUP,
+ null,
+ null);
+ return true;
+ }
+
+ // uninstall the app from installed state
+ deletePackageVersioned(
+ new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+ new PackageManager.LegacyPackageDeleteObserver(null).getBinder(),
+ userId,
+ PackageManager.DELETE_SYSTEM_APP);
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
- private SigningDetails getSigningDetails(int uid) {
- return mComputer.getSigningDetails(uid);
- }
+ void finishPackageInstall(int token, boolean didLaunch) {
+ PackageManagerServiceUtils.enforceSystemOrRoot(
+ "Only the system is allowed to finish installs");
- private boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- return mComputer.filterAppAccess(pkg, callingUid, userId);
- }
+ if (PackageManagerService.DEBUG_INSTALL) {
+ Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token);
+ }
+ Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
- private boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return mComputer.filterAppAccess(packageName, callingUid, userId);
- }
-
- private boolean filterAppAccess(int uid, int callingUid) {
- return mComputer.filterAppAccess(uid, callingUid);
- }
-
- @Nullable
- private int[] getVisibilityAllowList(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getVisibilityAllowList(packageName, userId);
- }
-
- boolean canQueryPackage(int callingUid, @Nullable String targetPackageName) {
- return mComputer.canQueryPackage(callingUid, targetPackageName);
+ final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token,
+ didLaunch ? 1 : 0);
+ mHandler.sendMessage(msg);
}
void checkPackageStartable(@NonNull Computer snapshot, @NonNull String packageName,
@@ -4689,71 +4485,15 @@
}
}
- public class IPackageManagerImpl extends IPackageManager.Stub {
+ public class IPackageManagerImpl extends IPackageManagerBase {
- @Override
- public boolean activitySupportsIntent(ComponentName component, Intent intent,
- String resolvedType) {
- return mComputer.activitySupportsIntent(mResolveComponentName, component, intent,
- resolvedType);
- }
-
- @Override
- public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
- int sourceUserId, int targetUserId, int flags) {
- PackageManagerService.this.addCrossProfileIntentFilter(
- new WatchedIntentFilter(intentFilter), ownerPackage, sourceUserId, targetUserId,
- flags);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public boolean addPermission(PermissionInfo info) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- return mContext.getSystemService(PermissionManager.class).addPermission(info, false);
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public boolean addPermissionAsync(PermissionInfo info) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- return mContext.getSystemService(PermissionManager.class).addPermission(info, true);
- }
-
- @Override
- public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
- int userId) {
- mPreferredActivityHelper.addPersistentPreferredActivity(new WatchedIntentFilter(filter),
- activity, userId);
- }
-
- @Override
- public void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
- mPreferredActivityHelper.addPreferredActivity(new WatchedIntentFilter(filter), match,
- set, activity, true, userId, "Adding preferred", removeExisting);
- }
-
- /*
- * Returns if intent can be forwarded from the sourceUserId to the targetUserId
- */
- @Override
- public boolean canForwardTo(@NonNull Intent intent, @Nullable String resolvedType,
- @UserIdInt int sourceUserId, @UserIdInt int targetUserId) {
- return mComputer.canForwardTo(intent, resolvedType, sourceUserId, targetUserId);
- }
-
- @Override
- public boolean canRequestPackageInstalls(String packageName, int userId) {
- return mComputer.canRequestPackageInstalls(packageName, Binder.getCallingUid(), userId,
- true /* throwIfPermNotDeclared*/);
- }
-
- @Override
- public String[] canonicalToCurrentPackageNames(String[] names) {
- return mComputer.canonicalToCurrentPackageNames(names);
+ public IPackageManagerImpl() {
+ super(PackageManagerService.this, mContext, mDexOptHelper, mModuleInfoProvider,
+ mPreferredActivityHelper, mResolveIntentHelper, mDomainVerificationManager,
+ mDomainVerificationConnection, mInstallerService, mPackageProperty,
+ mResolveComponentName, mInstantAppResolverSettingsComponent,
+ mRequiredSdkSandboxPackage, mServicesExtensionPackageName,
+ mSharedSystemSharedLibraryPackageName);
}
@Override
@@ -4762,33 +4502,13 @@
.checkPackageStartable(snapshotComputer(), packageName, userId);
}
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public int checkPermission(String permName, String pkgName, int userId) {
- return PackageManagerService.this.checkPermission(permName, pkgName, userId);
- }
-
- @Override
- public int checkSignatures(@NonNull String pkg1, @NonNull String pkg2) {
- return mComputer.checkSignatures(pkg1, pkg2);
- }
-
- @Override
- public int checkUidPermission(String permName, int uid) {
- return mComputer.checkUidPermission(permName, uid);
- }
-
- @Override
- public int checkUidSignatures(int uid1, int uid2) {
- return mComputer.checkUidSignatures(uid1, uid2);
- }
-
@Override
public void clearApplicationProfileData(String packageName) {
PackageManagerServiceUtils.enforceSystemOrRoot(
"Only the system can clear all profile data");
- final AndroidPackage pkg = getPackage(packageName);
+ final Computer snapshot = snapshotComputer();
+ final AndroidPackage pkg = snapshot.getPackage(packageName);
try (PackageFreezer ignored = freezePackage(packageName, "clearApplicationProfileData")) {
synchronized (mInstallLock) {
mAppDataHelper.clearAppProfilesLIF(pkg);
@@ -4803,10 +4523,11 @@
android.Manifest.permission.CLEAR_APP_USER_DATA, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "clear application data");
- if (mComputer.getPackageStateFiltered(packageName, callingUid, userId) == null) {
+ if (snapshot.getPackageStateFiltered(packageName, callingUid, userId) == null) {
if (observer != null) {
mHandler.post(() -> {
try {
@@ -4831,7 +4552,8 @@
try (PackageFreezer freezer = freezePackage(packageName,
"clearApplicationUserData")) {
synchronized (mInstallLock) {
- succeeded = clearApplicationUserDataLIF(packageName, userId);
+ succeeded = clearApplicationUserDataLIF(snapshotComputer(), packageName,
+ userId);
}
mInstantAppRegistry.deleteInstantApplicationMetadata(packageName, userId);
synchronized (mLock) {
@@ -4849,8 +4571,9 @@
}
if (checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
== PERMISSION_GRANTED) {
- unsuspendForSuspendingPackage(snapshotComputer(), packageName, userId);
- removeAllDistractingPackageRestrictions(userId);
+ final Computer snapshot = snapshotComputer();
+ unsuspendForSuspendingPackage(snapshot, packageName, userId);
+ removeAllDistractingPackageRestrictions(snapshot, userId);
flushPackageRestrictionsAsUserInternalLocked(userId);
}
}
@@ -4870,7 +4593,8 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
final int callingUid = Binder.getCallingUid();
- enforceOwnerRights(ownerPackage, callingUid);
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, ownerPackage, callingUid);
PackageManagerServiceUtils.enforceShellRestriction(mInjector.getUserManagerInternal(),
UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, sourceUserId);
synchronized (mLock) {
@@ -4888,22 +4612,7 @@
}
@Override
- public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
- mPreferredActivityHelper.clearPackagePersistentPreferredActivities(packageName, userId);
- }
-
- @Override
- public void clearPackagePreferredActivities(String packageName) {
- mPreferredActivityHelper.clearPackagePreferredActivities(packageName);
- }
-
- @Override
- public String[] currentToCanonicalPackageNames(String[] names) {
- return mComputer.currentToCanonicalPackageNames(names);
- }
-
- @Override
- public void deleteApplicationCacheFiles(final String packageName,
+ public final void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
final int userId = UserHandle.getCallingUserId();
deleteApplicationCacheFilesAsUser(packageName, userId, observer);
@@ -4928,17 +4637,18 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
}
- enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, /* requireFullPermission= */ true,
/* checkShell= */ false, "delete application cache files");
final int hasAccessInstantApps = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.ACCESS_INSTANT_APPS);
- final AndroidPackage pkg = getPackage(packageName);
-
// Queue up an async operation since the package deletion may take a little while.
mHandler.post(() -> {
- final PackageStateInternal ps =
- pkg == null ? null : getPackageStateInternal(pkg.getPackageName());
+ // Snapshot in the Handler Runnable since this may be deferred quite a bit
+ // TODO: Is this and the later mInstallLock re-snapshot necessary?
+ final Computer newSnapshot = snapshotComputer();
+ final PackageStateInternal ps = newSnapshot.getPackageStateInternal(packageName);
boolean doClearData = true;
if (ps != null) {
final boolean targetIsInstantApp =
@@ -4949,6 +4659,8 @@
if (doClearData) {
synchronized (mInstallLock) {
final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
+ // Snapshot again after mInstallLock?
+ final AndroidPackage pkg = snapshotComputer().getPackage(packageName);
// We're only clearing cache files, so we don't care if the
// app is unfrozen and still able to run
mAppDataHelper.clearAppDataLIF(pkg, userId,
@@ -4968,47 +4680,18 @@
}
@Override
- public void deleteExistingPackageAsUser(VersionedPackage versionedPackage,
- final IPackageDeleteObserver2 observer, final int userId) {
- PackageManagerService.this.deleteExistingPackageAsUser(versionedPackage, observer,
- userId);
- }
-
- @Override
- public void deletePackageAsUser(String packageName, int versionCode,
- IPackageDeleteObserver observer, int userId, int flags) {
- deletePackageVersioned(new VersionedPackage(packageName, versionCode),
- new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId, flags);
- }
-
- @Override
- public void deletePackageVersioned(VersionedPackage versionedPackage,
- final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
- PackageManagerService.this.deletePackageVersioned(versionedPackage, observer,
- userId, deleteFlags);
- }
-
- @Override
- public void deletePreloadsFileCache() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CLEAR_APP_CACHE,
- "deletePreloadsFileCache");
- File dir = Environment.getDataPreloadsFileCacheDirectory();
- Slog.i(PackageManagerService.TAG, "Deleting preloaded file cache " + dir);
- FileUtils.deleteContents(dir);
- }
-
- @Override
public void dumpProfiles(String packageName) {
/* Only the shell, root, or the app user should be able to dump profiles. */
final int callingUid = Binder.getCallingUid();
- final String[] callerPackageNames = getPackagesForUid(callingUid);
+ final Computer snapshot = snapshotComputer();
+ final String[] callerPackageNames = snapshot.getPackagesForUid(callingUid);
if (callingUid != Process.SHELL_UID
&& callingUid != Process.ROOT_UID
&& !ArrayUtils.contains(callerPackageNames, packageName)) {
throw new SecurityException("dumpProfiles");
}
- AndroidPackage pkg = mComputer.getPackage(packageName);
+ AndroidPackage pkg = snapshot.getPackage(packageName);
if (pkg == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -5062,46 +4745,25 @@
});
}
- @Override
- public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
- return mPreferredActivityHelper.findPersistentPreferredActivity(intent, userId);
- }
-
- @Override
- public void finishPackageInstall(int token, boolean didLaunch) {
- PackageManagerServiceUtils.enforceSystemOrRoot(
- "Only the system is allowed to finish installs");
-
- if (PackageManagerService.DEBUG_INSTALL) {
- Slog.v(PackageManagerService.TAG, "BM finishing package install for " + token);
- }
- Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
-
- final Message msg = mHandler.obtainMessage(PackageManagerService.POST_INSTALL, token, didLaunch ? 1 : 0);
- mHandler.sendMessage(msg);
- }
-
@WorkerThread
@Override
public void flushPackageRestrictionsAsUser(int userId) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final Computer snapshot = snapshotComputer();
+ final int callingUid = Binder.getCallingUid();
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return;
}
if (!mUserManager.exists(userId)) {
return;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
- false /* checkShell */, "flushPackageRestrictions");
+ snapshot.enforceCrossUserPermission(callingUid, userId,
+ false /* requireFullPermission*/, false /* checkShell */,
+ "flushPackageRestrictions");
synchronized (mLock) {
flushPackageRestrictionsAsUserInternalLocked(userId);
}
}
- @Override
- public void forceDexOpt(String packageName) {
- mDexOptHelper.forceDexOpt(packageName);
- }
-
@Override
public void freeStorage(final String volumeUuid, final long freeStorageSize,
@@ -5150,83 +4812,17 @@
}
@Override
- public ActivityInfo getActivityInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- return mComputer.getActivityInfo(component, flags, userId);
- }
-
- @NonNull
- @Override
- public ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName) {
- return mComputer.getAllIntentFilters(packageName);
- }
-
- @Override
- public List<String> getAllPackages() {
- return mComputer.getAllPackages();
- }
-
- // NOTE: Can't remove due to unsupported app usage
- @NonNull
- @Override
- public String[] getAppOpPermissionPackages(@NonNull String permissionName) {
- return mComputer.getAppOpPermissionPackages(permissionName);
- }
-
- @Override
- public String getAppPredictionServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultAppPredictionService));
- }
-
- @PackageManager.EnabledState
- @Override
- public int getApplicationEnabledSetting(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getApplicationEnabledSetting(packageName, userId);
- }
-
- /**
- * Returns true if application is not found or there was an error. Otherwise it returns
- * the hidden state of the package for the given user.
- */
- @Override
- public boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
- @UserIdInt int userId) {
- return mComputer.getApplicationHiddenSettingAsUser(packageName, userId);
- }
-
- @Override
- public ApplicationInfo getApplicationInfo(String packageName,
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- return mComputer.getApplicationInfo(packageName, flags, userId);
- }
-
- @Override
- public IArtManager getArtManager() {
- return mArtManagerService;
- }
-
- @Override
- public @Nullable String getAttentionServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultAttentionService));
- }
-
- @Override
- public boolean getBlockUninstallForUser(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getBlockUninstallForUser(packageName, userId);
- }
-
- @Override
public ChangedPackages getChangedPackages(int sequenceNumber, int userId) {
final int callingUid = Binder.getCallingUid();
- if (getInstantAppPackageName(callingUid) != null) {
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return null;
}
if (!mUserManager.exists(userId)) {
return null;
}
- enforceCrossUserPermission(callingUid, userId, false, false, "getChangedPackages");
+ snapshot.enforceCrossUserPermission(callingUid, userId, false, false,
+ "getChangedPackages");
final ChangedPackages changedPackages = mChangedPackagesTracker.getChangedPackages(
sequenceNumber, userId);
@@ -5234,8 +4830,9 @@
final List<String> packageNames = changedPackages.getPackageNames();
for (int index = packageNames.size() - 1; index >= 0; index--) {
// Filter out the changes if the calling package should not be able to see it.
- final PackageSetting ps = mSettings.getPackageLPr(packageNames.get(index));
- if (shouldFilterApplication(ps, callingUid, userId)) {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageNames.get(index));
+ if (snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
packageNames.remove(index);
}
}
@@ -5245,41 +4842,6 @@
}
@Override
- public int getComponentEnabledSetting(@NonNull ComponentName component, int userId) {
- return mComputer.getComponentEnabledSetting(component, Binder.getCallingUid(), userId);
- }
-
- @Override
- public String getContentCaptureServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultContentCaptureService));
- }
-
- @Nullable
- @Override
- public ParceledListSlice<SharedLibraryInfo> getDeclaredSharedLibraries(
- @NonNull String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- @NonNull int userId) {
- return mComputer.getDeclaredSharedLibraries(packageName, flags, userId);
- }
-
- /**
- * Non-Binder method, support for the backup/restore mechanism: write the
- * default browser (etc) settings in its canonical XML format. Returns the default
- * browser XML representation as a byte array, or null if there is none.
- */
- @Override
- public byte[] getDefaultAppsBackup(int userId) {
- return mPreferredActivityHelper.getDefaultAppsBackup(userId);
- }
-
- @Override
- public String getDefaultTextClassifierPackageName() {
- return ensureSystemPackageName(
- mContext.getString(R.string.config_servicesExtensionPackage));
- }
-
- @Override
public byte[] getDomainVerificationBackup(int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Only the system may call getDomainVerificationBackup()");
@@ -5301,17 +4863,6 @@
}
@Override
- public int getFlagsForUid(int uid) {
- return mComputer.getFlagsForUid(uid);
- }
-
- @Nullable
- @Override
- public CharSequence getHarmfulAppWarning(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getHarmfulAppWarning(packageName, userId);
- }
-
- @Override
public IBinder getHoldLockToken() {
if (!Build.IS_DEBUGGABLE) {
throw new SecurityException("getHoldLockToken requires a debuggable build");
@@ -5327,72 +4878,15 @@
}
@Override
- public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
- }
-
- public String getIncidentReportApproverPackageName() {
- return ensureSystemPackageName(mContext.getString(
- R.string.config_incidentReportApproverPackage));
- }
-
- @Override
- public int getInstallLocation() {
- // allow instant app access
- return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
- InstallLocationUtils.APP_INSTALL_AUTO);
- }
-
- @PackageManager.InstallReason
- @Override
- public int getInstallReason(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.getInstallReason(packageName, userId);
- }
-
- @Override
- @Nullable
- public InstallSourceInfo getInstallSourceInfo(@NonNull String packageName) {
- return mComputer.getInstallSourceInfo(packageName);
- }
-
- @Override
- public ParceledListSlice<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return new ParceledListSlice<>(
- mComputer.getInstalledApplications(flags, userId, callingUid));
- }
-
- @Override
- public List<ModuleInfo> getInstalledModules(int flags) {
- return mModuleInfoProvider.getInstalledModules(flags);
- }
-
- @Override
- public ParceledListSlice<PackageInfo> getInstalledPackages(
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getInstalledPackages(flags, userId);
- }
-
- @Nullable
- @Override
- public String getInstallerPackageName(@NonNull String packageName) {
- return mComputer.getInstallerPackageName(packageName);
- }
-
- @Override
public String getInstantAppAndroidId(String packageName, int userId) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS,
- "getInstantAppAndroidId");
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS, "getInstantAppAndroidId");
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppAndroidId");
// Make sure the target is an Instant App.
- if (!isInstantApp(packageName, userId)) {
+ if (!snapshot.isInstantApp(packageName, userId)) {
return null;
}
return mInstantAppRegistry.getInstantAppAndroidId(packageName, userId);
@@ -5404,13 +4898,14 @@
return null;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppCookie");
- if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
+ if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
return null;
}
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return null;
}
@@ -5423,11 +4918,12 @@
return null;
}
- if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
+ final Computer snapshot = snapshotComputer();
+ if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getInstantAppIcon");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getInstantAppIcon");
@@ -5435,76 +4931,31 @@
}
@Override
- public ComponentName getInstantAppInstallerComponent() {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return mInstantAppInstallerActivity == null
- ? null : mInstantAppInstallerActivity.getComponentName();
- }
-
- @Override
- public @Nullable ComponentName getInstantAppResolverComponent() {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return getInstantAppResolver();
- }
-
- @Override
- public ComponentName getInstantAppResolverSettingsComponent() {
- return mInstantAppResolverSettingsComponent;
- }
-
- @Override
public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
- if (PackageManagerService.HIDE_EPHEMERAL_APIS) {
+ if (HIDE_EPHEMERAL_APIS) {
return null;
}
- if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
+
+ final Computer snapshot = snapshotComputer();
+ if (!snapshot.canViewInstantApps(Binder.getCallingUid(), userId)) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_INSTANT_APPS,
"getEphemeralApplications");
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, false /* checkShell */,
"getEphemeralApplications");
- Computer computer = snapshotComputer();
- List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(computer, userId);
+ List<InstantAppInfo> instantApps = mInstantAppRegistry.getInstantApps(snapshot, userId);
if (instantApps != null) {
return new ParceledListSlice<>(instantApps);
}
return null;
}
- @Nullable
- @Override
- public InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName component, int flags) {
- return mComputer.getInstrumentationInfo(component, flags);
- }
-
- @Deprecated
- @Override
- public @NonNull ParceledListSlice<IntentFilterVerificationInfo> getIntentFilterVerifications(
- String packageName) {
- return ParceledListSlice.emptyList();
- }
-
- @Deprecated
- @Override
- public int getIntentVerificationStatus(String packageName, int userId) {
- return mDomainVerificationManager.getLegacyState(packageName, userId);
- }
-
- @Nullable
- @Override
- public KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias) {
- return mComputer.getKeySetByAlias(packageName, alias);
- }
-
@Override
public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
- return mPreferredActivityHelper.getLastChosenActivity(intent, resolvedType, flags);
+ return mPreferredActivityHelper.getLastChosenActivity(snapshotComputer(), intent,
+ resolvedType, flags);
}
@Override
@@ -5516,13 +4967,9 @@
@Override
public List<String> getMimeGroup(String packageName, String mimeGroup) {
- enforceOwnerRights(packageName, Binder.getCallingUid());
- return getMimeGroupInternal(packageName, mimeGroup);
- }
-
- @Override
- public ModuleInfo getModuleInfo(String packageName, @PackageManager.ModuleInfoFlags int flags) {
- return PackageManagerService.this.getModuleInfo(packageName, flags);
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
+ return getMimeGroupInternal(snapshot, packageName, mimeGroup);
}
@Override
@@ -5532,99 +4979,11 @@
return mMoveCallbacks.mLastStatus.get(moveId);
}
- @Nullable
- @Override
- public String getNameForUid(int uid) {
- return mComputer.getNameForUid(uid);
- }
-
- @Nullable
- @Override
- public String[] getNamesForUids(@NonNull int[] uids) {
- return mComputer.getNamesForUids(uids);
- }
-
- @Override
- public int[] getPackageGids(String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- int userId) {
- return mComputer.getPackageGids(packageName, flags, userId);
- }
-
- @Override
- public PackageInfo getPackageInfo(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getPackageInfo(packageName, flags, userId);
- }
-
- @Override
- public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getPackageInfoInternal(versionedPackage.getPackageName(),
- versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
- }
-
- @Override
- public IPackageInstaller getPackageInstaller() {
- // Return installer service for internal calls.
- if (PackageManagerServiceUtils.isSystemOrRoot()) {
- return mInstallerService;
- }
- // Return null for InstantApps.
- if (snapshotComputer().getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- return mInstallerService;
- }
-
- @Override
- public void getPackageSizeInfo(final String packageName, int userId,
- final IPackageStatsObserver observer) {
- throw new UnsupportedOperationException(
- "Shame on you for calling the hidden API getPackageSizeInfo(). Shame!");
- }
-
- @Override
- public int getPackageUid(@NonNull String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getPackageUid(packageName, flags, userId);
- }
-
- /**
- * <em>IMPORTANT:</em> Not all packages returned by this method may be known
- * to the system. There are two conditions in which this may occur:
- * <ol>
- * <li>The package is on adoptable storage and the device has been removed</li>
- * <li>The package is being removed and the internal structures are partially updated</li>
- * </ol>
- * The second is an artifact of the current data structures and should be fixed. See
- * b/111075456 for one such instance.
- * This binder API is cached. If the algorithm in this method changes,
- * or if the underlying objecs (as returned by getSettingLPr()) change
- * then the logic that invalidates the cache must be revisited. See
- * calls to invalidateGetPackagesForUidCache() to locate the points at
- * which the cache is invalidated.
- */
- @Override
- public String[] getPackagesForUid(int uid) {
- final int callingUid = Binder.getCallingUid();
- final int userId = UserHandle.getUserId(uid);
- mComputer.enforceCrossUserOrProfilePermission(callingUid, userId,
- /* requireFullPermission */ false,
- /* checkShell */ false, "getPackagesForUid");
- return mComputer.getPackagesForUid(uid);
- }
-
- @Override
- public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
- @NonNull String[] permissions, @PackageManager.PackageInfoFlagsBits long flags,
- @UserIdInt int userId) {
- return mComputer.getPackagesHoldingPermissions(permissions, flags, userId);
- }
-
@Override
public String getPermissionControllerPackageName() {
final int callingUid = Binder.getCallingUid();
- if (mComputer.getPackageStateFiltered(mRequiredPermissionControllerPackage,
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getPackageStateFiltered(mRequiredPermissionControllerPackage,
callingUid, UserHandle.getUserId(callingUid)) != null) {
return mRequiredPermissionControllerPackage;
}
@@ -5632,73 +4991,6 @@
throw new IllegalStateException("PermissionController is not found");
}
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
- return PackageManagerService.this.getPermissionGroupInfo(groupName, flags);
- }
-
- @Override
- public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return ParceledListSlice.emptyList();
- }
- return new ParceledListSlice<>(mComputer.getPersistentApplications(mSafeMode, flags));
- }
-
- @Override
- public int getPreferredActivities(List<IntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName) {
- return mPreferredActivityHelper.getPreferredActivities(outFilters, outActivities,
- packageName, snapshotComputer());
- }
-
- /**
- * Non-Binder method, support for the backup/restore mechanism: write the
- * full set of preferred activities in its canonical XML format. Returns the
- * XML output as a byte array, or null if there is none.
- */
- @Override
- public byte[] getPreferredActivityBackup(int userId) {
- return mPreferredActivityHelper.getPreferredActivityBackup(userId);
- }
-
- @Override
- public int getPrivateFlagsForUid(int uid) {
- return mComputer.getPrivateFlagsForUid(uid);
- }
-
- @Override
- public PackageManager.Property getProperty(String propertyName, String packageName, String className) {
- Objects.requireNonNull(propertyName);
- Objects.requireNonNull(packageName);
- PackageStateInternal packageState = mComputer.getPackageStateFiltered(packageName,
- Binder.getCallingUid(), UserHandle.getCallingUserId());
- if (packageState == null) {
- return null;
- }
- return mPackageProperty.getProperty(propertyName, packageName, className);
- }
-
- @Nullable
- @Override
- public ProviderInfo getProviderInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getProviderInfo(component, flags, userId);
- }
-
- @Override
- public ActivityInfo getReceiverInfo(ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
- return mComputer.getReceiverInfo(component, flags, userId);
- }
-
- @Override
- public @Nullable String getRotationResolverPackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultRotationResolverService));
- }
-
@Override
public int getRuntimePermissionsVersion(@UserIdInt int userId) {
Preconditions.checkArgumentNonnegative(userId);
@@ -5707,65 +4999,25 @@
return mSettings.getDefaultRuntimePermissionsVersion(userId);
}
- @Nullable
- @Override
- public ServiceInfo getServiceInfo(@NonNull ComponentName component,
- @PackageManager.ComponentInfoFlagsBits long flags, @UserIdInt int userId) {
- return mComputer.getServiceInfo(component, flags, userId);
- }
-
- @Override
- public @NonNull String getServicesSystemSharedLibraryPackageName() {
- return mServicesExtensionPackageName;
- }
-
- @Override
- public String getSetupWizardPackageName() {
- if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("Non-system caller");
- }
- return mPmInternal.getSetupWizardPackageName();
- }
-
- @Override
- public ParceledListSlice<SharedLibraryInfo> getSharedLibraries(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return mComputer.getSharedLibraries(packageName, flags, userId);
- }
-
- @Override
- public @NonNull String getSharedSystemSharedLibraryPackageName() {
- return mSharedSystemSharedLibraryPackageName;
- }
-
- @Nullable
- @Override
- public KeySet getSigningKeySet(@NonNull String packageName) {
- return mComputer.getSigningKeySet(packageName);
- }
-
@Override
public String getSplashScreenTheme(@NonNull String packageName, int userId) {
- PackageStateInternal packageState =
- getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
+ final Computer snapshot = snapshotComputer();
+ PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, Binder.getCallingUid(), userId);
return packageState == null ? null
: packageState.getUserStateOrDefault(userId).getSplashScreenTheme();
}
@Override
- public String getSdkSandboxPackageName() {
- return mRequiredSdkSandboxPackage;
- }
-
- @Override
public Bundle getSuspendedPackageAppExtras(String packageName, int userId) {
final int callingUid = Binder.getCallingUid();
- if (getPackageUid(packageName, 0, userId) != callingUid) {
+ final Computer snapshot = snapshot();
+ if (snapshot.getPackageUid(packageName, 0, userId) != callingUid) {
throw new SecurityException("Calling package " + packageName
+ " does not belong to calling uid " + callingUid);
}
- return mSuspendPackageHelper.getSuspendedPackageAppExtras(
- packageName, userId, callingUid);
+ return mSuspendPackageHelper
+ .getSuspendedPackageAppExtras(snapshot, packageName, userId, callingUid);
}
@Override
@@ -5785,34 +5037,6 @@
}
@Override
- public String getSystemCaptionsServicePackageName() {
- return ensureSystemPackageName(
- getPackageFromComponentString(R.string.config_defaultSystemCaptionsService));
- }
-
- @Nullable
- @Override
- public String[] getSystemSharedLibraryNames() {
- return mComputer.getSystemSharedLibraryNames();
- }
-
- @Override
- public String getSystemTextClassifierPackageName() {
- return ensureSystemPackageName(
- mContext.getString(R.string.config_defaultTextClassifierPackage));
- }
-
- @Override
- public int getTargetSdkVersion(@NonNull String packageName) {
- return mComputer.getTargetSdkVersion(packageName);
- }
-
- @Override
- public int getUidForSharedUser(@NonNull String sharedUserName) {
- return mComputer.getUidForSharedUser(sharedUserName);
- }
-
- @Override
public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
Objects.requireNonNull(packageNames, "packageNames cannot be null");
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
@@ -5838,18 +5062,6 @@
}
@Override
- public String getWellbeingPackageName() {
- final long identity = Binder.clearCallingIdentity();
- try {
- return CollectionUtils.firstOrNull(
- mContext.getSystemService(RoleManager.class).getRoleHolders(
- RoleManager.ROLE_SYSTEM_WELLBEING));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- @Override
public void grantImplicitAccess(int recipientUid, @NonNull String visibleAuthority) {
final Computer snapshot = snapshotComputer();
final int recipientUserId = UserHandle.getUserId(recipientUid);
@@ -5864,38 +5076,6 @@
false /*direct*/, false /* retainOnUpdate */);
}
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public void grantRuntimePermission(String packageName, String permName, final int userId) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- mContext.getSystemService(PermissionManager.class)
- .grantRuntimePermission(packageName, permName, UserHandle.of(userId));
- }
-
- @Override
- public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
- @PackageManager.CertificateInputType int type) {
- return mComputer.hasSigningCertificate(packageName, certificate, type);
- }
-
- @Override
- public boolean hasSystemFeature(String name, int version) {
- return PackageManagerService.this.hasSystemFeature(name, version);
- }
-
- @Override
- public boolean hasSystemUidErrors() {
- // allow instant applications
- return false;
- }
-
- @Override
- public boolean hasUidSigningCertificate(int uid, @NonNull byte[] certificate,
- @PackageManager.CertificateInputType int type) {
- return mComputer.hasUidSigningCertificate(uid, certificate, type);
- }
-
@Override
public void holdLock(IBinder token, int durationMs) {
mTestUtilityService.verifyHoldLockToken(token);
@@ -5924,55 +5104,17 @@
}
@Override
- public boolean isDeviceUpgrading() {
- return PackageManagerService.this.isDeviceUpgrading();
- }
-
- @Override
- public boolean isFirstBoot() {
- return PackageManagerService.this.isFirstBoot();
- }
-
- @Override
- public boolean isInstantApp(String packageName, int userId) {
- return mComputer.isInstantApp(packageName, userId);
- }
-
- @Override
- public boolean isOnlyCoreApps() {
- return PackageManagerService.this.isOnlyCoreApps();
- }
-
- @Override
- public boolean isPackageAvailable(String packageName, int userId) {
- return mComputer.isPackageAvailable(packageName, userId);
- }
-
- @Override
- public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
- return PackageManagerService.this.isPackageDeviceAdminOnAnyUser(packageName);
- }
-
- @Override
- public boolean isPackageSignedByKeySet(@NonNull String packageName, @NonNull KeySet ks) {
- return mComputer.isPackageSignedByKeySet(packageName, ks);
- }
-
- @Override
- public boolean isPackageSignedByKeySetExactly(@NonNull String packageName, @NonNull KeySet ks) {
- return mComputer.isPackageSignedByKeySetExactly(packageName, ks);
- }
-
- @Override
public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
final int callingUid = Binder.getCallingUid();
final int callingAppId = UserHandle.getAppId(callingUid);
- enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
true /*checkShell*/, "isPackageStateProtected");
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID
- && checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid) != PERMISSION_GRANTED) {
+ && snapshot.checkUidPermission(MANAGE_DEVICE_ADMINS, callingUid)
+ != PERMISSION_GRANTED) {
throw new SecurityException("Caller must have the "
+ MANAGE_DEVICE_ADMINS + " permission.");
}
@@ -5981,11 +5123,6 @@
}
@Override
- public boolean isPackageSuspendedForUser(@NonNull String packageName, @UserIdInt int userId) {
- return mComputer.isPackageSuspendedForUser(packageName, userId);
- }
-
- @Override
public boolean isProtectedBroadcast(String actionName) {
if (actionName != null) {
// TODO: remove these terrible hacks
@@ -6002,22 +5139,6 @@
}
}
- @Override
- public boolean isSafeMode() {
- // allow instant applications
- return mSafeMode;
- }
-
- @Override
- public boolean isStorageLow() {
- return PackageManagerService.this.isStorageLow();
- }
-
- @Override
- public boolean isUidPrivileged(int uid) {
- return mComputer.isUidPrivileged(uid);
- }
-
/**
* Logs process start information (including base APK hash) to the security log.
* @hide
@@ -6025,13 +5146,15 @@
@Override
public void logAppProcessStartIfNeeded(String packageName, String processName, int uid,
String seinfo, String apkFile, int pid) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
if (!SecurityLog.isLoggingEnabled()) {
return;
}
- mProcessLoggingHandler.logAppProcessStart(mContext, mPmInternal, apkFile, packageName,
+ mProcessLoggingHandler.logAppProcessStart(mContext,
+ LocalServices.getService(PackageManagerInternal.class), apkFile, packageName,
processName, uid, seinfo, pid);
}
@@ -6083,25 +5206,29 @@
}
@Override
- public void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap,
+ public void notifyDexLoad(String loadingPackageName,
+ Map<String, String> classLoaderContextMap,
String loaderIsa) {
int callingUid = Binder.getCallingUid();
- if (PackageManagerService.PLATFORM_PACKAGE_NAME.equals(loadingPackageName) && callingUid != Process.SYSTEM_UID) {
- Slog.w(PackageManagerService.TAG, "Non System Server process reporting dex loads as system server. uid="
- + callingUid);
+ if (PackageManagerService.PLATFORM_PACKAGE_NAME.equals(loadingPackageName)
+ && callingUid != Process.SYSTEM_UID) {
+ Slog.w(PackageManagerService.TAG,
+ "Non System Server process reporting dex loads as system server. uid="
+ + callingUid);
// Do not record dex loads from processes pretending to be system server.
// Only the system server should be assigned the package "android", so reject calls
// that don't satisfy the constraint.
//
// notifyDexLoad is a PM API callable from the app process. So in theory, apps could
- // craft calls to this API and pretend to be system server. Doing so poses no particular
- // danger for dex load reporting or later dexopt, however it is a sensible check to do
- // in order to verify the expectations.
+ // craft calls to this API and pretend to be system server. Doing so poses no
+ // particular danger for dex load reporting or later dexopt, however it is a
+ // sensible check to do in order to verify the expectations.
return;
}
int userId = UserHandle.getCallingUserId();
- ApplicationInfo ai = getApplicationInfo(loadingPackageName, /*flags*/ 0, userId);
+ ApplicationInfo ai = snapshot().getApplicationInfo(loadingPackageName, /*flags*/ 0,
+ userId);
if (ai == null) {
Slog.w(PackageManagerService.TAG, "Loading a package that does not exist for the calling user. package="
+ loadingPackageName + ", user=" + userId);
@@ -6115,11 +5242,13 @@
public void notifyPackageUse(String packageName, int reason) {
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
+ Computer snapshot = snapshotComputer();
final boolean notify;
- if (getInstantAppPackageName(callingUid) != null) {
- notify = isCallerSameApp(packageName, callingUid);
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
+ notify = snapshot.isCallerSameApp(packageName, callingUid);
} else {
- notify = !isInstantAppInternal(packageName, callingUserId, Process.SYSTEM_UID);
+ notify = !snapshot.isInstantAppInternal(packageName, callingUserId,
+ Process.SYSTEM_UID);
}
if (!notify) {
return;
@@ -6137,102 +5266,18 @@
updateComponentLabelIcon(componentName, nonLocalizedLabel, icon, userId);
}
- /**
- * Ask the package manager to perform a dex-opt with the given compiler filter.
- *
- * Note: exposed only for the shell command to allow moving packages explicitly to a
- * definite state.
- */
- @Override
- public boolean performDexOptMode(String packageName,
- boolean checkProfiles, String targetCompilerFilter, boolean force,
- boolean bootComplete, String splitName) {
- return mDexOptHelper.performDexOptMode(packageName, checkProfiles, targetCompilerFilter,
- force, bootComplete, splitName);
- }
-
- /**
- * Ask the package manager to perform a dex-opt with the given compiler filter on the
- * secondary dex files belonging to the given package.
- *
- * Note: exposed only for the shell command to allow moving packages explicitly to a
- * definite state.
- */
- @Override
- public boolean performDexOptSecondary(String packageName, String compilerFilter,
- boolean force) {
- return mDexOptHelper.performDexOptSecondary(packageName, compilerFilter, force);
- }
-
- @NonNull
- @Override
- public ParceledListSlice<ProviderInfo> queryContentProviders(@Nullable String processName,
- int uid, @PackageManager.ComponentInfoFlagsBits long flags,
- @Nullable String metaDataKey) {
- return mComputer.queryContentProviders(processName, uid, flags, metaDataKey);
- }
-
- @NonNull
- @Override
- public ParceledListSlice<InstrumentationInfo> queryInstrumentation(
- @NonNull String targetPackage, int flags) {
- return mComputer.queryInstrumentation(targetPackage, flags);
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- try {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
-
- return new ParceledListSlice<>(snapshotComputer().queryIntentActivitiesInternal(intent,
- resolvedType, flags, userId));
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
- Intent[] specifics, String[] specificTypes, Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentActivityOptionsInternal(
- snapshotComputer(), caller, specifics, specificTypes, intent, resolvedType, flags,
- userId));
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentContentProvidersInternal(
- snapshotComputer(), intent, resolvedType, flags, userId));
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
- snapshotComputer(), intent, resolvedType, flags, userId, Binder.getCallingUid()));
- }
-
- @Override
- public @NonNull ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return new ParceledListSlice<>(snapshotComputer().queryIntentServicesInternal(
- intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/));
- }
-
@Override
public ParceledListSlice<PackageManager.Property> queryProperty(
String propertyName, @PackageManager.PropertyLocation int componentType) {
Objects.requireNonNull(propertyName);
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getCallingUserId();
+ final Computer snapshot = snapshotComputer();
final List<PackageManager.Property> result =
mPackageProperty.queryProperty(propertyName, componentType, packageName -> {
- final PackageStateInternal ps = getPackageStateInternal(packageName);
- return shouldFilterApplication(ps, callingUid, callingUserId);
+ final PackageStateInternal ps =
+ snapshot.getPackageStateInternal(packageName);
+ return snapshot.shouldFilterApplication(ps, callingUid, callingUserId);
});
if (result == null) {
return ParceledListSlice.emptyList();
@@ -6240,11 +5285,6 @@
return new ParceledListSlice<>(result);
}
- @Deprecated
- public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) {
- mComputer.querySyncProviders(mSafeMode, outNames, outInfo);
- }
-
/**
* Reconcile the information we have about the secondary dex files belonging to
* {@code packageName} and the actual dex files. For all dex files that were
@@ -6252,9 +5292,10 @@
*/
@Override
public void reconcileSecondaryDexFiles(String packageName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ final Computer snapshot = snapshotComputer();
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
- } else if (isInstantAppInternal(
+ } else if (snapshot.isInstantAppInternal(
packageName, UserHandle.getCallingUserId(), Process.SYSTEM_UID)) {
return;
}
@@ -6262,14 +5303,16 @@
}
@Override
- public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule,
+ public void registerDexModule(String packageName, String dexModulePath,
+ boolean isSharedModule,
IDexModuleRegisterCallback callback) {
int userId = UserHandle.getCallingUserId();
- ApplicationInfo ai = getApplicationInfo(packageName, /*flags*/ 0, userId);
+ ApplicationInfo ai = snapshot().getApplicationInfo(packageName, /*flags*/ 0, userId);
DexManager.RegisterDexModuleResult result;
if (ai == null) {
- Slog.w(PackageManagerService.TAG, "Registering a dex module for a package that does not exist for the" +
- " calling user. package=" + packageName + ", user=" + userId);
+ Slog.w(PackageManagerService.TAG,
+ "Registering a dex module for a package that does not exist for the" +
+ " calling user. package=" + packageName + ", user=" + userId);
result = new DexManager.RegisterDexModuleResult(false, "Package not installed");
} else {
result = mDexManager.registerDexModule(ai, dexModulePath, isSharedModule, userId);
@@ -6278,9 +5321,11 @@
if (callback != null) {
mHandler.post(() -> {
try {
- callback.onDexModuleRegistered(dexModulePath, result.success, result.message);
+ callback.onDexModuleRegistered(dexModulePath, result.success,
+ result.message);
} catch (RemoteException e) {
- Slog.w(PackageManagerService.TAG, "Failed to callback after module registration " + dexModulePath, e);
+ Slog.w(PackageManagerService.TAG,
+ "Failed to callback after module registration " + dexModulePath, e);
}
});
}
@@ -6293,52 +5338,6 @@
mMoveCallbacks.register(callback);
}
- // NOTE: Can't remove due to unsupported app usage
- @Override
- public void removePermission(String permName) {
- // Because this is accessed via the package manager service AIDL,
- // go through the permission manager service AIDL
- mContext.getSystemService(PermissionManager.class).removePermission(permName);
- }
-
- @Override
- public void replacePreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
- mPreferredActivityHelper.replacePreferredActivity(new WatchedIntentFilter(filter),
- match, set, activity, userId);
- }
-
- @Override
- public void resetApplicationPreferences(int userId) {
- mPreferredActivityHelper.resetApplicationPreferences(userId);
- }
-
- @Override
- public ProviderInfo resolveContentProvider(String name,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return mComputer.resolveContentProvider(name, flags, userId, Binder.getCallingUid());
- }
-
- @Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(), intent, resolvedType,
- flags, 0 /*privateResolveFlags*/, userId, false, Binder.getCallingUid());
- }
-
- @Override
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId) {
- final int callingUid = Binder.getCallingUid();
- return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent, resolvedType,
- flags, userId, callingUid);
- }
-
- @Override
- public void restoreDefaultApps(byte[] backup, int userId) {
- mPreferredActivityHelper.restoreDefaultApps(backup, userId);
- }
-
@Override
public void restoreDomainVerification(byte[] backup, int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -6366,11 +5365,6 @@
}
@Override
- public void restorePreferredActivities(byte[] backup, int userId) {
- mPreferredActivityHelper.restorePreferredActivities(backup, userId);
- }
-
- @Override
public void sendDeviceCustomizationReadyBroadcast() {
mContext.enforceCallingPermission(Manifest.permission.SEND_DEVICE_CUSTOMIZATION_READY,
"sendDeviceCustomizationReadyBroadcast");
@@ -6386,16 +5380,17 @@
@Override
public void setApplicationCategoryHint(String packageName, int categoryHint,
String callerPackageName) {
- if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- mInjector.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
- callerPackageName);
-
final PackageStateMutator.InitialState initialState = recordInitialState();
final FunctionalUtils.ThrowingFunction<Computer, PackageStateMutator.Result>
implementation = computer -> {
+ if (computer.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ throw new SecurityException(
+ "Instant applications don't have access to this method");
+ }
+ mInjector.getSystemService(AppOpsManager.class)
+ .checkPackage(Binder.getCallingUid(), callerPackageName);
+
PackageStateInternal packageState = computer.getPackageStateFiltered(packageName,
Binder.getCallingUid(), UserHandle.getCallingUserId());
if (packageState == null) {
@@ -6447,7 +5442,8 @@
int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
true /* checkShell */, "setApplicationHiddenSetting for user " + userId);
if (hidden && isPackageDeviceAdmin(packageName, userId)) {
@@ -6464,7 +5460,7 @@
final long callingId = Binder.clearCallingIdentity();
try {
final PackageStateInternal packageState =
- mComputer.getPackageStateFiltered(packageName, callingUid, userId);
+ snapshot.getPackageStateFiltered(packageName, callingUid, userId);
if (packageState == null) {
return false;
}
@@ -6505,13 +5501,16 @@
commitPackageStateMutation(null, packageName, packageState1 ->
packageState1.userState(userId).setHidden(hidden));
- final PackageStateInternal newPackageState = getPackageStateInternal(packageName);
+ final Computer newSnapshot = snapshotComputer();
+ final PackageStateInternal newPackageState =
+ newSnapshot.getPackageStateInternal(packageName);
if (hidden) {
killApplication(packageName, newPackageState.getAppId(), userId, "hiding pkg");
sendApplicationHiddenForUser(packageName, newPackageState, userId);
} else {
- sendPackageAddedForUser(packageName, newPackageState, userId, DataLoaderType.NONE);
+ sendPackageAddedForUser(newSnapshot, packageName, newPackageState, userId,
+ DataLoaderType.NONE);
}
scheduleWritePackageRestrictions(userId);
@@ -6526,7 +5525,8 @@
int userId) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.DELETE_PACKAGES, null);
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final Computer snapshot = snapshotComputer();
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState != null && packageState.getPkg() != null) {
AndroidPackage pkg = packageState.getPkg();
// Cannot block uninstall SDK libs as they are controlled by SDK manager.
@@ -6584,8 +5584,10 @@
+ userId);
}
Objects.requireNonNull(packageNames, "packageNames cannot be null");
+ final Computer snapshot = snapshotComputer();
if (restrictionFlags != 0
- && !mSuspendPackageHelper.isSuspendAllowedForUser(userId, callingUid)) {
+ && !mSuspendPackageHelper.isSuspendAllowedForUser(snapshot, userId,
+ callingUid)) {
Slog.w(PackageManagerService.TAG, "Cannot restrict packages due to restrictions on user " + userId);
return packageNames;
}
@@ -6595,16 +5597,15 @@
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
ArraySet<String> changesToCommit = new ArraySet<>();
- Computer computer = snapshotComputer();
final boolean[] canRestrict = (restrictionFlags != 0)
- ? mSuspendPackageHelper.canSuspendPackageForUser(computer, packageNames, userId,
+ ? mSuspendPackageHelper.canSuspendPackageForUser(snapshot, packageNames, userId,
callingUid) : null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
final PackageStateInternal packageState =
- computer.getPackageStateInternal(packageName);
+ snapshot.getPackageStateInternal(packageName);
if (packageState == null
- || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
Slog.w(PackageManagerService.TAG, "Could not find package setting for package: " + packageName
+ ". Skipping...");
unactionedPackages.add(packageName);
@@ -6648,11 +5649,13 @@
final int callingUid = Binder.getCallingUid();
final int callingAppId = UserHandle.getAppId(callingUid);
- enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /*requireFullPermission*/,
true /*checkShell*/, "setHarmfulAppInfo");
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.ROOT_UID &&
- checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid) != PERMISSION_GRANTED) {
+ snapshot.checkUidPermission(SET_HARMFUL_APP_WARNINGS, callingUid)
+ != PERMISSION_GRANTED) {
throw new SecurityException("Caller must have the "
+ SET_HARMFUL_APP_WARNINGS + " permission.");
}
@@ -6667,11 +5670,6 @@
}
@Override
- public void setHomeActivity(ComponentName comp, int userId) {
- mPreferredActivityHelper.setHomeActivity(comp, userId);
- }
-
- @Override
public boolean setInstallLocation(int loc) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS,
null);
@@ -6693,24 +5691,24 @@
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
final FunctionalUtils.ThrowingCheckedFunction<Computer, Boolean, RuntimeException>
- implementation = computer -> {
- if (computer.getInstantAppPackageName(callingUid) != null) {
+ implementation = snapshot -> {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return false;
}
PackageStateInternal targetPackageState =
- computer.getPackageStateInternal(targetPackage);
+ snapshot.getPackageStateInternal(targetPackage);
if (targetPackageState == null
- || computer.shouldFilterApplication(targetPackageState, callingUid,
+ || snapshot.shouldFilterApplication(targetPackageState, callingUid,
callingUserId)) {
throw new IllegalArgumentException("Unknown target package: " + targetPackage);
}
PackageStateInternal installerPackageState = null;
if (installerPackageName != null) {
- installerPackageState = computer.getPackageStateInternal(installerPackageName);
+ installerPackageState = snapshot.getPackageStateInternal(installerPackageName);
if (installerPackageState == null
- || shouldFilterApplication(
+ || snapshot.shouldFilterApplication(
installerPackageState, callingUid, callingUserId)) {
throw new IllegalArgumentException("Unknown installer package: "
+ installerPackageName);
@@ -6720,7 +5718,7 @@
Signature[] callerSignature;
final int appId = UserHandle.getAppId(callingUid);
Pair<PackageStateInternal, SharedUserApi> either =
- computer.getPackageOrSharedUser(appId);
+ snapshot.getPackageOrSharedUser(appId);
if (either != null) {
if (either.first != null) {
callerSignature = either.first.getSigningDetails().getSignatures();
@@ -6748,7 +5746,7 @@
String targetInstallerPackageName =
targetPackageState.getInstallSource().installerPackageName;
PackageStateInternal targetInstallerPkgSetting = targetInstallerPackageName == null
- ? null : computer.getPackageStateInternal(targetInstallerPackageName);
+ ? null : snapshot.getPackageStateInternal(targetInstallerPackageName);
if (targetInstallerPkgSetting != null) {
if (compareSignatures(callerSignature,
@@ -6804,7 +5802,7 @@
}
}
}
- targetPackageState = getPackageStateInternal(targetPackage);
+ targetPackageState = snapshotComputer().getPackageStateInternal(targetPackage);
mSettings.addInstallerPackageNames(targetPackageState.getInstallSource());
}
mAppsFilter.addPackage(targetPackageState);
@@ -6818,14 +5816,15 @@
return true;
}
- enforceCrossUserPermission(Binder.getCallingUid(), userId,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId,
true /* requireFullPermission */, true /* checkShell */,
"setInstantAppCookie");
- if (!isCallerSameApp(packageName, Binder.getCallingUid())) {
+ if (!snapshot.isCallerSameApp(packageName, Binder.getCallingUid())) {
return false;
}
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return false;
}
@@ -6840,21 +5839,15 @@
"setKeepUninstalledPackages requires KEEP_UNINSTALLED_PACKAGES permission");
Objects.requireNonNull(packageList);
- setKeepUninstalledPackagesInternal(packageList);
- }
-
- @Override
- public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
- IntentFilter filter, int match, ComponentName activity) {
- mPreferredActivityHelper.setLastChosenActivity(intent, resolvedType, flags,
- new WatchedIntentFilter(filter), match, activity);
+ setKeepUninstalledPackagesInternal(snapshot(), packageList);
}
@Override
public void setMimeGroup(String packageName, String mimeGroup, List<String> mimeTypes) {
- enforceOwnerRights(packageName, Binder.getCallingUid());
+ final Computer snapshot = snapshotComputer();
+ enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
if (existingMimeTypes == null) {
throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
@@ -6889,11 +5882,11 @@
PersistableBundle appExtras, PersistableBundle launcherExtras,
SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
final int callingUid = Binder.getCallingUid();
- enforceCanSetPackagesSuspendedAsUser(callingPackage, callingUid, userId,
+ final Computer snapshot = snapshotComputer();
+ enforceCanSetPackagesSuspendedAsUser(snapshot, callingPackage, callingUid, userId,
"setPackagesSuspendedAsUser");
- return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
- suspended, appExtras, launcherExtras, dialogInfo, callingPackage, userId,
- callingUid);
+ return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
+ appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid);
}
@Override
@@ -6924,12 +5917,13 @@
public void setSplashScreenTheme(@NonNull String packageName, @Nullable String themeId,
int userId) {
final int callingUid = Binder.getCallingUid();
- enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
+ final Computer snapshot = snapshotComputer();
+ snapshot.enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
false /* checkShell */, "setSplashScreenTheme");
- enforceOwnerRights(packageName, callingUid);
+ enforceOwnerRights(snapshot, packageName, callingUid);
- PackageStateInternal packageState = getPackageStateInstalledFiltered(packageName,
- callingUid, userId);
+ PackageStateInternal packageState = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, callingUid, userId);
if (packageState == null) {
return;
}
@@ -6939,80 +5933,6 @@
}
@Override
- public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) {
- final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
- if (!calledFromSystemOrPhone) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setSystemAppHiddenUntilInstalled");
- }
-
- final PackageStateInternal stateRead = getPackageStateInternal(packageName);
- if (stateRead == null || !stateRead.isSystem() || stateRead.getPkg() == null) {
- return;
- }
- if (stateRead.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
- throw new SecurityException("Only system or phone callers can modify core apps");
- }
-
- commitPackageStateMutation(null, mutator -> {
- mutator.forPackage(packageName)
- .setHiddenUntilInstalled(hidden);
- mutator.forDisabledSystemPackage(packageName)
- .setHiddenUntilInstalled(hidden);
- });
- }
-
- @Override
- public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
- final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
- if (!calledFromSystemOrPhone) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
- "setSystemAppHiddenUntilInstalled");
- }
-
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- // The target app should always be in system
- if (packageState == null || !packageState.isSystem() || packageState.getPkg() == null) {
- return false;
- }
- if (packageState.getPkg().isCoreApp() && !calledFromSystemOrPhone) {
- throw new SecurityException("Only system or phone callers can modify core apps");
- }
- // Check if the install state is the same
- if (packageState.getUserStateOrDefault(userId).isInstalled() == installed) {
- return false;
- }
-
- final long callingId = Binder.clearCallingIdentity();
- try {
- if (installed) {
- // install the app from uninstalled state
- installExistingPackageAsUser(
- packageName,
- userId,
- PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
- PackageManager.INSTALL_REASON_DEVICE_SETUP,
- null);
- return true;
- }
-
- // uninstall the app from installed state
- deletePackageVersioned(
- new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
- new PackageManager.LegacyPackageDeleteObserver(null).getBinder(),
- userId,
- PackageManager.DELETE_SYSTEM_APP);
- return true;
- } finally {
- Binder.restoreCallingIdentity(callingId);
- }
- }
-
- @Override
public void setUpdateAvailable(String packageName, boolean updateAvailable) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
commitPackageStateMutation(null, packageName, state ->
@@ -7026,19 +5946,6 @@
mMoveCallbacks.unregister(callback);
}
- @Deprecated
- @Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
- return mDomainVerificationManager.setLegacyUserState(packageName, userId, status);
- }
-
- @Deprecated
- @Override
- public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
- DomainVerificationProxyV1.queueLegacyVerifyResult(mContext, mDomainVerificationConnection,
- id, verificationCode, failedDomains, Binder.getCallingUid());
- }
-
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
@@ -7059,9 +5966,9 @@
@Checksum.TypeMask int optional, @Checksum.TypeMask int required,
@Nullable List trustedInstallers,
@NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId) {
- requestChecksumsInternal(packageName, includeSplits, optional, required, trustedInstallers,
- onChecksumsReadyListener, userId, mInjector.getBackgroundExecutor(),
- mInjector.getBackgroundHandler());
+ requestChecksumsInternal(snapshotComputer(), packageName, includeSplits, optional,
+ required, trustedInstallers, onChecksumsReadyListener, userId,
+ mInjector.getBackgroundExecutor(), mInjector.getBackgroundHandler());
}
@Override
@@ -7074,12 +5981,6 @@
}
@Override
- public boolean canPackageQuery(@NonNull String sourcePackageName,
- @NonNull String targetPackageName, @UserIdInt int userId) {
- return mComputer.canPackageQuery(sourcePackageName, targetPackageName, userId);
- }
-
- @Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
@@ -7097,8 +5998,8 @@
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new PackageManagerShellCommand(mIPackageManager,
- mContext,mDomainVerificationManager.getShell()))
+ (new PackageManagerShellCommand(this, mContext,
+ mDomainVerificationManager.getShell()))
.exec(this, in, out, err, args, callback, resultReceiver);
}
@@ -7113,17 +6014,81 @@
private class PackageManagerLocalImpl implements PackageManagerLocal {
}
- private class PackageManagerInternalImpl extends PackageManagerInternal {
+ private class PackageManagerInternalImpl extends PackageManagerInternalBase {
+
+ public PackageManagerInternalImpl() {
+ super(PackageManagerService.this);
+ }
+
+ @NonNull
@Override
- public List<ApplicationInfo> getInstalledApplications(
- @PackageManager.ApplicationInfoFlagsBits long flags, int userId, int callingUid) {
- return PackageManagerService.this.mComputer.getInstalledApplications(flags, userId,
- callingUid);
+ protected Context getContext() {
+ return mContext;
+ }
+
+ @NonNull
+ @Override
+ protected PermissionManagerServiceInternal getPermissionManager() {
+ return mPermissionManager;
+ }
+
+ @NonNull
+ @Override
+ protected AppDataHelper getAppDataHelper() {
+ return mAppDataHelper;
+ }
+
+ @NonNull
+ @Override
+ protected PackageObserverHelper getPackageObserverHelper() {
+ return mPackageObserverHelper;
+ }
+
+ @NonNull
+ @Override
+ protected ResolveIntentHelper getResolveIntentHelper() {
+ return mResolveIntentHelper;
+ }
+
+ @NonNull
+ @Override
+ protected SuspendPackageHelper getSuspendPackageHelper() {
+ return mSuspendPackageHelper;
+ }
+
+ @NonNull
+ @Override
+ protected ProtectedPackages getProtectedPackages() {
+ return mProtectedPackages;
+ }
+
+ @NonNull
+ @Override
+ protected UserNeedsBadgingCache getUserNeedsBadging() {
+ return mUserNeedsBadging;
+ }
+
+ @NonNull
+ @Override
+ protected InstantAppRegistry getInstantAppRegistry() {
+ return mInstantAppRegistry;
+ }
+
+ @NonNull
+ @Override
+ protected ApexManager getApexManager() {
+ return mApexManager;
+ }
+
+ @NonNull
+ @Override
+ protected DexManager getDexManager() {
+ return mDexManager;
}
@Override
public boolean isPlatformSigned(String packageName) {
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ PackageStateInternal packageState = snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
return false;
}
@@ -7135,7 +6100,8 @@
@Override
public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
- SigningDetails sd = getSigningDetails(packageName);
+ final Computer snapshot = snapshot();
+ SigningDetails sd = snapshot.getSigningDetails(packageName);
if (sd == null) {
return false;
}
@@ -7145,7 +6111,8 @@
@Override
public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
- SigningDetails sd = getSigningDetails(packageName);
+ final Computer snapshot = snapshot();
+ SigningDetails sd = snapshot.getSigningDetails(packageName);
if (sd == null) {
return false;
}
@@ -7156,100 +6123,17 @@
@Override
public boolean hasSignatureCapability(int serverUid, int clientUid,
@SigningDetails.CertCapabilities int capability) {
- SigningDetails serverSigningDetails = getSigningDetails(serverUid);
- SigningDetails clientSigningDetails = getSigningDetails(clientUid);
+ final Computer snapshot = snapshot();
+ SigningDetails serverSigningDetails = snapshot.getSigningDetails(serverUid);
+ SigningDetails clientSigningDetails = snapshot.getSigningDetails(clientUid);
return serverSigningDetails.checkCapability(clientSigningDetails, capability)
|| clientSigningDetails.hasAncestorOrSelf(serverSigningDetails);
-
- }
-
- private SigningDetails getSigningDetails(@NonNull String packageName) {
- return PackageManagerService.this.getSigningDetails(packageName);
- }
-
- private SigningDetails getSigningDetails(int uid) {
- return PackageManagerService.this.getSigningDetails(uid);
- }
-
- @Override
- public boolean isInstantApp(String packageName, int userId) {
- return PackageManagerService.this.mIPackageManager.isInstantApp(packageName, userId);
- }
-
- @Override
- public String getInstantAppPackageName(int uid) {
- return PackageManagerService.this.getInstantAppPackageName(uid);
- }
-
- @Override
- public boolean filterAppAccess(AndroidPackage pkg, int callingUid, int userId) {
- return PackageManagerService.this.filterAppAccess(pkg, callingUid, userId);
- }
-
- @Override
- public boolean filterAppAccess(String packageName, int callingUid, int userId) {
- return PackageManagerService.this.filterAppAccess(packageName, callingUid, userId);
- }
-
- @Override
- public boolean filterAppAccess(int uid, int callingUid) {
- return PackageManagerService.this.filterAppAccess(uid, callingUid);
- }
-
- @Nullable
- @Override
- public int[] getVisibilityAllowList(@NonNull String packageName, int userId) {
- return PackageManagerService.this.getVisibilityAllowList(packageName, userId);
- }
-
- @Override
- public boolean canQueryPackage(int callingUid, @Nullable String packageName) {
- return PackageManagerService.this.canQueryPackage(callingUid, packageName);
- }
-
- @Override
- public AndroidPackage getPackage(String packageName) {
- return PackageManagerService.this.getPackage(packageName);
- }
-
- @Nullable
- @Override
- public AndroidPackageApi getAndroidPackage(@NonNull String packageName) {
- return PackageManagerService.this.getPackage(packageName);
- }
-
- @Override
- public AndroidPackage getPackage(int uid) {
- return PackageManagerService.this.getPackage(uid);
- }
-
- @Override
- public List<AndroidPackage> getPackagesForAppId(int appId) {
- return mComputer.getPackagesForAppId(appId);
- }
-
- @Nullable
- @Override
- public PackageStateInternal getPackageStateInternal(String packageName) {
- return PackageManagerService.this.getPackageStateInternal(packageName);
- }
-
- @Nullable
- @Override
- public PackageState getPackageState(@NonNull String packageName) {
- return PackageManagerService.this.getPackageState(packageName);
- }
-
- @NonNull
- @Override
- public ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- return PackageManagerService.this.getPackageStates();
}
@Override
public PackageList getPackageList(@Nullable PackageListObserver observer) {
final ArrayList<String> list = new ArrayList<>();
- forEachPackageState(packageState -> {
+ PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
AndroidPackage pkg = packageState.getPkg();
if (pkg != null) {
list.add(pkg.getPackageName());
@@ -7263,19 +6147,9 @@
}
@Override
- public void removePackageListObserver(PackageListObserver observer) {
- mPackageObserverHelper.removeObserver(observer);
- }
-
- @Override
- public PackageStateInternal getDisabledSystemPackage(@NonNull String packageName) {
- return snapshotComputer().getDisabledSystemPackage(packageName);
- }
-
- @Override
public @Nullable
String getDisabledSystemPackageName(@NonNull String packageName) {
- PackageStateInternal disabledPkgSetting = getDisabledSystemPackage(
+ PackageStateInternal disabledPkgSetting = snapshot().getDisabledSystemPackage(
packageName);
AndroidPackage disabledPkg = disabledPkgSetting == null
? null : disabledPkgSetting.getPkg();
@@ -7283,51 +6157,15 @@
}
@Override
- public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) {
- return PackageManagerService.this.getKnownPackageNamesInternal(knownPackage, userId);
- }
-
- @Override
- public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
- if (packageName == null) {
- return false;
- }
-
- if (Process.isSdkSandboxUid(callingUid)) {
- return packageName.equals(getSdkSandboxPackageName());
- }
- int uid = getPackageUid(packageName, 0, userId);
- return UserHandle.isSameApp(uid, callingUid);
- }
-
- @Override
public boolean isResolveActivityComponent(ComponentInfo component) {
return mResolveActivity.packageName.equals(component.packageName)
&& mResolveActivity.name.equals(component.name);
}
@Override
- public void setKeepUninstalledPackages(final List<String> packageList) {
- PackageManagerService.this.setKeepUninstalledPackagesInternal(packageList);
- }
-
- @Override
- public boolean isPermissionsReviewRequired(String packageName, int userId) {
- return mPermissionManager.isPermissionsReviewRequired(packageName, userId);
- }
-
- @Override
- public PackageInfo getPackageInfo(
- String packageName, @PackageManager.PackageInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this.mComputer
- .getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
- flags, filterCallingUid, userId);
- }
-
- @Override
public long getCeDataInode(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
return 0;
} else {
@@ -7336,18 +6174,6 @@
}
@Override
- public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
- return mSuspendPackageHelper.getSuspendedPackageLauncherExtras(
- packageName, userId, Binder.getCallingUid());
- }
-
- @Override
- public boolean isPackageSuspended(String packageName, int userId) {
- return mSuspendPackageHelper.isPackageSuspended(
- packageName, userId, Binder.getCallingUid());
- }
-
- @Override
public void removeAllNonSystemPackageSuspensions(int userId) {
final Computer computer = snapshotComputer();
final String[] allPackages = computer.getAllAvailablePackageNames();
@@ -7357,14 +6183,6 @@
}
@Override
- public void removeNonSystemPackageSuspensions(String packageName, int userId) {
- mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(snapshotComputer(),
- new String[]{packageName},
- (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
- userId);
- }
-
- @Override
public void flushPackageRestrictions(int userId) {
synchronized (mLock) {
PackageManagerService.this.flushPackageRestrictionsAsUserInternalLocked(userId);
@@ -7372,103 +6190,6 @@
}
@Override
- public void removeDistractingPackageRestrictions(String packageName, int userId) {
- PackageManagerService.this.removeDistractingPackageRestrictions(
- new String[]{packageName}, userId);
- }
-
- @Override
- public void removeAllDistractingPackageRestrictions(int userId) {
- PackageManagerService.this.removeAllDistractingPackageRestrictions(userId);
- }
-
- @Override
- public String getSuspendingPackage(String suspendedPackage, int userId) {
- return mSuspendPackageHelper.getSuspendingPackage(
- suspendedPackage, userId, Binder.getCallingUid());
- }
-
- @Override
- public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- String suspendingPackage, int userId) {
- return mSuspendPackageHelper.getSuspendedDialogInfo(
- suspendedPackage, suspendingPackage, userId, Binder.getCallingUid());
- }
-
- @Override
- public int getDistractingPackageRestrictions(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- return (packageState == null) ? RESTRICTION_NONE
- : packageState.getUserStateOrDefault(userId).getDistractionFlags();
- }
-
- @Override
- public int getPackageUid(String packageName,
- @PackageManager.PackageInfoFlagsBits long flags, int userId) {
- return PackageManagerService.this
- .getPackageUidInternal(packageName, flags, userId, Process.SYSTEM_UID);
- }
-
- @Override
- public ApplicationInfo getApplicationInfo(
- String packageName, @PackageManager.ApplicationInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getApplicationInfoInternal(packageName, flags, filterCallingUid, userId);
- }
-
- @Override
- public ActivityInfo getActivityInfo(
- ComponentName component, @PackageManager.ComponentInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this
- .getActivityInfoInternal(component, flags, filterCallingUid, userId);
- }
-
- @Override
- public List<ResolveInfo> queryIntentActivities(
- Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return snapshotComputer().queryIntentActivitiesInternal(intent, resolvedType, flags,
- userId);
- }
-
- @Override
- public List<ResolveInfo> queryIntentReceivers(Intent intent,
- String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
- int filterCallingUid, int userId) {
- return PackageManagerService.this.mResolveIntentHelper.queryIntentReceiversInternal(
- snapshotComputer(), intent, resolvedType, flags, userId, filterCallingUid);
- }
-
- @Override
- public List<ResolveInfo> queryIntentServices(
- Intent intent, @PackageManager.ResolveInfoFlagsBits long flags, int callingUid,
- int userId) {
- final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
- return PackageManagerService.this
- .queryIntentServicesInternal(intent, resolvedType, flags, userId, callingUid,
- false);
- }
-
- @Override
- public ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
- return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
- }
-
- @Override
- public ComponentName getDefaultHomeActivity(int userId) {
- return PackageManagerService.this.getDefaultHomeActivity(userId);
- }
-
- @Override
- public ComponentName getSystemUiServiceComponent() {
- return ComponentName.unflattenFromString(mContext.getResources().getString(
- com.android.internal.R.string.config_systemUIServiceComponent));
- }
-
- @Override
public void setDeviceAndProfileOwnerPackages(
int deviceOwnerUserId, String deviceOwnerPackage,
SparseArray<String> profileOwnerPackages) {
@@ -7487,118 +6208,6 @@
}
@Override
- public void setDeviceOwnerProtectedPackages(
- String deviceOwnerPackageName, List<String> packageNames) {
- mProtectedPackages.setDeviceOwnerProtectedPackages(
- deviceOwnerPackageName, packageNames);
- }
-
- @Override
- public boolean isPackageDataProtected(int userId, String packageName) {
- return mProtectedPackages.isPackageDataProtected(userId, packageName);
- }
-
- @Override
- public boolean isPackageStateProtected(String packageName, int userId) {
- return mProtectedPackages.isPackageStateProtected(userId, packageName);
- }
-
- @Override
- public boolean isPackageEphemeral(int userId, String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- return packageState != null
- && packageState.getUserStateOrDefault(userId).isInstantApp();
- }
-
- @Override
- public boolean wasPackageEverLaunched(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return !packageState.getUserStateOrDefault(userId).isNotLaunched();
- }
-
- @Override
- public boolean isEnabledAndMatches(ParsedMainComponent component, long flags, int userId) {
- return PackageStateUtils.isEnabledAndMatches(
- getPackageStateInternal(component.getPackageName()), component, flags, userId);
- }
-
- @Override
- public boolean userNeedsBadging(int userId) {
- synchronized (mLock) {
- return PackageManagerService.this.userNeedsBadging(userId);
- }
- }
-
- @Override
- public String getNameForUid(int uid) {
- return mIPackageManager.getNameForUid(uid);
- }
-
- @Override
- public void requestInstantAppResolutionPhaseTwo(AuxiliaryResolveInfo responseObj,
- Intent origIntent, String resolvedType, String callingPackage,
- @Nullable String callingFeatureId, boolean isRequesterInstantApp,
- Bundle verificationBundle, int userId) {
- PackageManagerService.this.requestInstantAppResolutionPhaseTwo(responseObj, origIntent,
- resolvedType, callingPackage, callingFeatureId, isRequesterInstantApp,
- verificationBundle, userId);
- }
-
- @Override
- public void grantImplicitAccess(int userId, Intent intent,
- int recipientAppId, int visibleUid, boolean direct) {
- grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
- false /* retainOnUpdate */);
- }
-
- @Override
- public void grantImplicitAccess(int userId, Intent intent,
- int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
- Computer computer = snapshotComputer();
- final AndroidPackage visiblePackage = computer.getPackage(visibleUid);
- final int recipientUid = UserHandle.getUid(userId, recipientAppId);
- if (visiblePackage == null || computer.getPackage(recipientUid) == null) {
- return;
- }
-
- final boolean instantApp = computer.isInstantAppInternal(
- visiblePackage.getPackageName(), userId, visibleUid);
- final boolean accessGranted;
- if (instantApp) {
- if (!direct) {
- // if the interaction that lead to this granting access to an instant app
- // was indirect (i.e.: URI permission grant), do not actually execute the
- // grant.
- return;
- }
- accessGranted = mInstantAppRegistry.grantInstantAccess(userId, intent,
- recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
- } else {
- accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
- retainOnUpdate);
- }
-
- if (accessGranted) {
- ApplicationPackageManager.invalidateGetPackagesForUidCache();
- }
- }
-
- @Override
- public boolean isInstantAppInstallerComponent(ComponentName component) {
- final ActivityInfo instantAppInstallerActivity = mInstantAppInstallerActivity;
- return instantAppInstallerActivity != null
- && instantAppInstallerActivity.getComponentName().equals(component);
- }
-
- @Override
- public void pruneInstantApps() {
- mInstantAppRegistry.pruneInstantApps(snapshotComputer());
- }
-
- @Override
public void pruneCachedApksInApex(@NonNull List<PackageInfo> apexPackages) {
if (mCacheDir == null) {
return;
@@ -7606,11 +6215,12 @@
final PackageCacher cacher = new PackageCacher(mCacheDir);
synchronized (mLock) {
+ final Computer snapshot = snapshot();
for (int i = 0, size = apexPackages.size(); i < size; i++) {
final List<String> apkNames =
mApexManager.getApksInApex(apexPackages.get(i).packageName);
for (int j = 0, apksInApex = apkNames.size(); j < apksInApex; j++) {
- final AndroidPackage pkg = getPackage(apkNames.get(j));
+ final AndroidPackage pkg = snapshot.getPackage(apkNames.get(j));
cacher.cleanCachedResult(new File(pkg.getPath()));
}
}
@@ -7618,10 +6228,6 @@
}
@Override
- public String getSetupWizardPackageName() {
- return mSetupWizardPackage;
- }
-
public void setExternalSourcesPolicy(ExternalSourcesPolicy policy) {
if (policy != null) {
mExternalSourcesPolicy = policy;
@@ -7630,7 +6236,8 @@
@Override
public boolean isPackagePersistent(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
return false;
}
@@ -7641,16 +6248,20 @@
@Override
public List<PackageInfo> getOverlayPackages(int userId) {
+ final Computer snapshot = snapshotComputer();
final ArrayList<PackageInfo> overlayPackages = new ArrayList<>();
- forEachPackageState(packageState -> {
+ final ArrayMap<String, ? extends PackageStateInternal> packageStates =
+ snapshot.getPackageStates();
+ for (int index = 0; index < packageStates.size(); index++) {
+ final PackageStateInternal packageState = packageStates.valueAt(index);
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && pkg.getOverlayTarget() != null) {
- PackageInfo pkgInfo = generatePackageInfo(packageState, 0, userId);
+ PackageInfo pkgInfo = snapshot.generatePackageInfo(packageState, 0, userId);
if (pkgInfo != null) {
overlayPackages.add(pkgInfo);
}
}
- });
+ }
return overlayPackages;
}
@@ -7658,7 +6269,7 @@
@Override
public List<String> getTargetPackageNames(int userId) {
List<String> targetPackages = new ArrayList<>();
- forEachPackageState(packageState -> {
+ PackageManagerService.this.forEachPackageState(snapshot(), packageState -> {
final AndroidPackage pkg = packageState.getPkg();
if (pkg != null && !pkg.isOverlay()) {
targetPackages.add(pkg.getPackageName());
@@ -7676,30 +6287,6 @@
}
@Override
- public ResolveInfo resolveIntent(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags,
- @PackageManagerInternal.PrivateResolveFlags long privateResolveFlags, int userId,
- boolean resolveForStart, int filterCallingUid) {
- return mResolveIntentHelper.resolveIntentInternal(snapshotComputer(),
- intent, resolvedType, flags, privateResolveFlags, userId, resolveForStart,
- filterCallingUid);
- }
-
- @Override
- public ResolveInfo resolveService(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
- return mResolveIntentHelper.resolveServiceInternal(snapshotComputer(), intent,
- resolvedType, flags, userId, callingUid);
- }
-
- @Override
- public ProviderInfo resolveContentProvider(String name,
- @PackageManager.ResolveInfoFlagsBits long flags, int userId, int callingUid) {
- return PackageManagerService.this.mComputer
- .resolveContentProvider(name, flags, userId,callingUid);
- }
-
- @Override
public void addIsolatedUid(int isolatedUid, int ownerUid) {
synchronized (mLock) {
mIsolatedOwners.put(isolatedUid, ownerUid);
@@ -7714,146 +6301,12 @@
}
@Override
- public int getUidTargetSdkVersion(int uid) {
- return PackageManagerService.this.getUidTargetSdkVersion(uid);
- }
-
- @Override
- public int getPackageTargetSdkVersion(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState != null && packageState.getPkg() != null) {
- return packageState.getPkg().getTargetSdkVersion();
- }
- return Build.VERSION_CODES.CUR_DEVELOPMENT;
- }
-
- @Override
- public boolean canAccessInstantApps(int callingUid, int userId) {
- return PackageManagerService.this.canViewInstantApps(callingUid, userId);
- }
-
- @Override
- public boolean canAccessComponent(int callingUid, @NonNull ComponentName component,
- @UserIdInt int userId) {
- return mComputer.canAccessComponent(callingUid, component, userId);
- }
-
- @Override
- public boolean hasInstantApplicationMetadata(String packageName, int userId) {
- return mInstantAppRegistry.hasInstantApplicationMetadata(packageName, userId);
- }
-
- @Override
public void notifyPackageUse(String packageName, int reason) {
synchronized (mLock) {
PackageManagerService.this.notifyPackageUseInternal(packageName, reason);
}
}
- @Override
- public void onPackageProcessKilledForUninstall(String packageName) {
- mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
- true /* killApp */));
- }
-
- @Override
- public SparseArray<String> getAppsWithSharedUserIds() {
- return mComputer.getAppsWithSharedUserIds();
- }
-
- @Override
- @NonNull
- public String[] getSharedUserPackagesForPackage(String packageName, int userId) {
- return mComputer.getSharedUserPackagesForPackage(packageName, userId);
- }
-
- @Override
- public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
- return mComputer.getProcessesForUid(uid);
- }
-
- @Override
- public int[] getPermissionGids(String permissionName, int userId) {
- return mPermissionManager.getPermissionGids(permissionName, userId);
- }
-
- @Override
- public boolean isOnlyCoreApps() {
- return mIPackageManager.isOnlyCoreApps();
- }
-
- @Override
- public void freeStorage(String volumeUuid, long bytes,
- @StorageManager.AllocateFlags int flags) throws IOException {
- PackageManagerService.this.freeStorage(volumeUuid, bytes, flags);
- }
-
- @Override
- public void freeAllAppCacheAboveQuota(@NonNull String volumeUuid) throws IOException {
- PackageManagerService.this.freeAllAppCacheAboveQuota(volumeUuid);
- }
-
- @Override
- public void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
- PackageManagerService.this.forEachPackageSetting(actionLocked);
- }
-
- @Override
- public void forEachPackageState(Consumer<PackageStateInternal> action) {
- PackageManagerService.this.forEachPackageState(action);
- }
-
- @Override
- public void forEachPackage(Consumer<AndroidPackage> action) {
- PackageManagerService.this.forEachPackage(action);
- }
-
- @Override
- public void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
- @UserIdInt int userId) {
- PackageManagerService.this.forEachInstalledPackage(action, userId);
- }
-
- @Override
- public ArraySet<String> getEnabledComponents(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return new ArraySet<>();
- }
- return packageState.getUserStateOrDefault(userId).getEnabledComponents();
- }
-
- @Override
- public ArraySet<String> getDisabledComponents(String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return new ArraySet<>();
- }
- return packageState.getUserStateOrDefault(userId).getDisabledComponents();
- }
-
- @Override
- public @PackageManager.EnabledState int getApplicationEnabledState(
- String packageName, int userId) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
- if (packageState == null) {
- return COMPONENT_ENABLED_STATE_DEFAULT;
- }
- return packageState.getUserStateOrDefault(userId).getEnabledState();
- }
-
- @Override
- public @PackageManager.EnabledState int getComponentEnabledSetting(
- @NonNull ComponentName componentName, int callingUid, int userId) {
- return PackageManagerService.this.mComputer.getComponentEnabledSettingInternal(
- componentName, callingUid, userId);
- }
-
- @Override
- public void setEnableRollbackCode(int token, int enableRollbackCode) {
- PackageManagerService.this.setEnableRollbackCode(token, enableRollbackCode);
- }
-
/**
* Ask the package manager to compile layouts in the given package.
*/
@@ -7869,11 +6322,6 @@
return mArtManagerService.compileLayouts(pkg);
}
- @Override
- public void finishPackageInstall(int token, boolean didLaunch) {
- mIPackageManager.finishPackageInstall(token, didLaunch);
- }
-
@Nullable
@Override
public String removeLegacyDefaultBrowserPackageName(int userId) {
@@ -7883,16 +6331,6 @@
}
@Override
- public boolean isApexPackage(String packageName) {
- return PackageManagerService.this.mApexManager.isApexPackage(packageName);
- }
-
- @Override
- public List<String> getApksInApex(String apexPackageName) {
- return PackageManagerService.this.mApexManager.getApksInApex(apexPackageName);
- }
-
- @Override
public void uninstallApex(String packageName, long versionCode, int userId,
IntentSender intentSender, int flags) {
final int callerUid = Binder.getCallingUid();
@@ -7967,11 +6405,6 @@
}
@Override
- public boolean isCallerInstallerOfRecord(@NonNull AndroidPackage pkg, int callingUid) {
- return mComputer.isCallerInstallerOfRecord(pkg, callingUid);
- }
-
- @Override
public boolean isPermissionUpgradeNeeded(int userId) {
return mSettings.isPermissionUpgradeNeeded(userId);
}
@@ -7985,13 +6418,9 @@
}
@Override
- public List<String> getMimeGroup(String packageName, String mimeGroup) {
- return PackageManagerService.this.getMimeGroupInternal(packageName, mimeGroup);
- }
-
- @Override
public void setVisibilityLogging(String packageName, boolean enable) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ final PackageStateInternal packageState =
+ snapshot().getPackageStateInternal(packageName);
if (packageState == null) {
throw new IllegalStateException("No package found for " + packageName);
}
@@ -7999,12 +6428,6 @@
}
@Override
- public boolean isSystemPackage(@NonNull String packageName) {
- return packageName.equals(
- PackageManagerService.this.ensureSystemPackageName(packageName));
- }
-
- @Override
public void clearBlockUninstallForUser(@UserIdInt int userId) {
synchronized (mLock) {
mSettings.clearBlockUninstallLPw(userId);
@@ -8013,21 +6436,11 @@
}
@Override
- public void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
- PackageManagerService.this.unsuspendForSuspendingPackage(snapshotComputer(),
- packageName, affectedUser);
- }
-
- @Override
- public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
- return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
- }
-
- @Override
public boolean registerInstalledLoadingProgressCallback(String packageName,
PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
- final PackageStateInternal ps =
- getPackageStateInstalledFiltered(packageName, Binder.getCallingUid(), userId);
+ final Computer snapshot = snapshotComputer();
+ final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, Binder.getCallingUid(), userId);
if (ps == null) {
return false;
}
@@ -8048,8 +6461,9 @@
@Override
public IncrementalStatesInfo getIncrementalStatesInfo(
@NonNull String packageName, int filterCallingUid, int userId) {
- final PackageStateInternal ps =
- getPackageStateInstalledFiltered(packageName, filterCallingUid, userId);
+ final Computer snapshot = snapshotComputer();
+ final PackageStateInternal ps = filterPackageStateForInstalledAndFiltered(snapshot,
+ packageName, filterCallingUid, userId);
if (ps == null) {
return null;
}
@@ -8057,74 +6471,23 @@
}
@Override
- public void requestChecksums(@NonNull String packageName, boolean includeSplits,
- @Checksum.TypeMask int optional, @Checksum.TypeMask int required,
- @Nullable List trustedInstallers,
- @NonNull IOnChecksumsReadyListener onChecksumsReadyListener, int userId,
- @NonNull Executor executor, @NonNull Handler handler) {
- requestChecksumsInternal(packageName, includeSplits, optional, required,
- trustedInstallers, onChecksumsReadyListener, userId, executor, handler);
+ public boolean isSameApp(@Nullable String packageName, int callingUid, int userId) {
+ if (packageName == null) {
+ return false;
+ }
+
+ if (Process.isSdkSandboxUid(callingUid)) {
+ return packageName.equals(mRequiredSdkSandboxPackage);
+ }
+ Computer snapshot = snapshot();
+ int uid = snapshot.getPackageUid(packageName, 0, userId);
+ return UserHandle.isSameApp(uid, callingUid);
}
@Override
- public boolean isPackageFrozen(@NonNull String packageName,
- int callingUid, int userId) {
- return PackageManagerService.this.getPackageStartability(
- packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
- }
-
- @Override
- public long deleteOatArtifactsOfPackage(String packageName) {
- return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
- }
-
- @Override
- public void reconcileAppsData(int userId, @StorageManager.StorageFlags int flags,
- boolean migrateAppsData) {
- PackageManagerService.this.mAppDataHelper.reconcileAppsData(userId, flags,
- migrateAppsData);
- }
-
- @Override
- @NonNull
- public ArraySet<PackageStateInternal> getSharedUserPackages(int sharedUserAppId) {
- return PackageManagerService.this.mComputer.getSharedUserPackages(sharedUserAppId);
- }
-
- @Override
- @Nullable
- public SharedUserApi getSharedUserApi(int sharedUserAppId) {
- return mComputer.getSharedUser(sharedUserAppId);
- }
-
- @NonNull
- @Override
- public PackageStateMutator.InitialState recordInitialState() {
- return PackageManagerService.this.recordInitialState();
- }
-
- @Nullable
- @Override
- public PackageStateMutator.Result commitPackageStateMutation(
- @Nullable PackageStateMutator.InitialState state,
- @NonNull Consumer<PackageStateMutator> consumer) {
- return PackageManagerService.this.commitPackageStateMutation(state, consumer);
- }
-
- @NonNull
- @Override
- public Computer snapshot() {
- return snapshotComputer();
- }
-
- @Override
- public void shutdown() {
- PackageManagerService.this.shutdown();
- }
-
- @Override
- public DynamicCodeLogger getDynamicCodeLogger() {
- return PackageManagerService.this.getDexManager().getDynamicCodeLogger();
+ public void onPackageProcessKilledForUninstall(String packageName) {
+ mHandler.post(() -> PackageManagerService.this.notifyInstallObserver(packageName,
+ true /* killApp */));
}
}
@@ -8239,24 +6602,6 @@
return mSettings.getDisabledSystemPkgLPr(packageName);
}
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- @Nullable
- PackageStateInternal getPackageStateInternal(String packageName) {
- return mComputer.getPackageStateInternal(packageName);
- }
-
- @Nullable
- PackageStateInternal getPackageStateInternal(String packageName, int callingUid) {
- return mComputer.getPackageStateInternal(packageName, callingUid);
- }
-
- @Nullable
- PackageStateInternal getPackageStateInstalledFiltered(@NonNull String packageName,
- int callingUid, @UserIdInt int userId) {
- return filterPackageStateForInstalledAndFiltered(mComputer, packageName, callingUid,
- userId);
- }
-
@Nullable
private PackageStateInternal filterPackageStateForInstalledAndFiltered(
@NonNull Computer computer, @NonNull String packageName, int callingUid,
@@ -8272,22 +6617,8 @@
}
}
- @Nullable
- private PackageState getPackageState(String packageName) {
- return mComputer.getPackageStateCopied(packageName);
- }
-
- @NonNull
- ArrayMap<String, ? extends PackageStateInternal> getPackageStates() {
- Computer computer = snapshotComputer();
- if (computer == mLiveComputer) {
- return new ArrayMap<>(computer.getPackageStates());
- } else {
- return computer.getPackageStates();
- }
- }
-
- private void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
+ @Deprecated
+ void forEachPackageSetting(Consumer<PackageSetting> actionLocked) {
synchronized (mLock) {
int size = mSettings.getPackagesLocked().size();
for (int index = 0; index < size; index++) {
@@ -8296,13 +6627,13 @@
}
}
- void forEachPackageState(Consumer<PackageStateInternal> consumer) {
- forEachPackageState(mComputer.getPackageStates(), consumer);
+ void forEachPackageState(@NonNull Computer snapshot, Consumer<PackageStateInternal> consumer) {
+ forEachPackageState(snapshot.getPackageStates(), consumer);
}
- void forEachPackage(Consumer<AndroidPackage> consumer) {
+ void forEachPackage(@NonNull Computer snapshot, Consumer<AndroidPackage> consumer) {
final ArrayMap<String, ? extends PackageStateInternal> packageStates =
- mComputer.getPackageStates();
+ snapshot.getPackageStates();
int size = packageStates.size();
for (int index = 0; index < size; index++) {
PackageStateInternal packageState = packageStates.valueAt(index);
@@ -8322,7 +6653,7 @@
}
}
- void forEachInstalledPackage(@NonNull Consumer<AndroidPackage> action,
+ void forEachInstalledPackage(@NonNull Computer snapshot, @NonNull Consumer<AndroidPackage> action,
@UserIdInt int userId) {
Consumer<PackageStateInternal> actionWrapped = packageState -> {
if (packageState.getPkg() != null
@@ -8330,7 +6661,7 @@
action.accept(packageState.getPkg());
}
};
- forEachPackageState(mComputer.getPackageStates(), actionWrapped);
+ forEachPackageState(snapshot.getPackageStates(), actionWrapped);
}
boolean isHistoricalPackageUsageAvailable() {
@@ -8345,15 +6676,7 @@
return mCompilerStats.getOrCreatePackageStats(pkgName);
}
- /**
- * Returns true if the system or user is explicitly preventing an otherwise valid installer to
- * complete an install. This includes checks like unknown sources and user restrictions.
- */
- public boolean isInstallDisabledForPackage(String packageName, int uid, int userId) {
- return mComputer.isInstallDisabledForPackage(packageName, uid, userId);
- }
-
- private void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId,
+ void grantImplicitAccess(@NonNull Computer snapshot, @UserIdInt int userId,
Intent intent, @AppIdInt int recipientAppId, int visibleUid, boolean direct,
boolean retainOnUpdate) {
final AndroidPackage visiblePackage = snapshot.getPackage(visibleUid);
@@ -8384,8 +6707,8 @@
}
}
- boolean canHaveOatDir(String packageName) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ boolean canHaveOatDir(@NonNull Computer snapshot, String packageName) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return false;
}
@@ -8393,8 +6716,8 @@
packageState.getTransientState().isUpdatedSystemApp());
}
- long deleteOatArtifactsOfPackage(String packageName) {
- PackageStateInternal packageState = getPackageStateInternal(packageName);
+ long deleteOatArtifactsOfPackage(@NonNull Computer snapshot, String packageName) {
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null || packageState.getPkg() == null) {
return -1; // error code of deleteOptimizedFiles
}
@@ -8402,13 +6725,9 @@
ArtUtils.createArtPackageInfo(packageState.getPkg(), packageState));
}
- @NonNull
- Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) {
- return mComputer.getUnusedPackages(downgradeTimeThresholdMillis);
- }
-
- private List<String> getMimeGroupInternal(String packageName, String mimeGroup) {
- final PackageStateInternal packageState = getPackageStateInternal(packageName);
+ List<String> getMimeGroupInternal(@NonNull Computer snapshot, String packageName,
+ String mimeGroup) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
if (packageState == null) {
return Collections.emptyList();
}
@@ -8473,16 +6792,16 @@
* Returns the array containing per-uid timeout configuration.
* This is derived from DeviceConfig flags.
*/
- public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts() {
+ public @NonNull PerUidReadTimeouts[] getPerUidReadTimeouts(@NonNull Computer snapshot) {
PerUidReadTimeouts[] result = mPerUidReadTimeoutsCache;
if (result == null) {
- result = parsePerUidReadTimeouts();
+ result = parsePerUidReadTimeouts(snapshot);
mPerUidReadTimeoutsCache = result;
}
return result;
}
- private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts() {
+ private @NonNull PerUidReadTimeouts[] parsePerUidReadTimeouts(@NonNull Computer snapshot) {
final String defaultTimeouts = getDefaultTimeouts();
final String knownDigestersList = getKnownDigestersList();
final List<PerPackageReadTimeouts> perPackageReadTimeouts =
@@ -8496,7 +6815,8 @@
final List<PerUidReadTimeouts> result = new ArrayList<>(perPackageReadTimeouts.size());
for (int i = 0, size = perPackageReadTimeouts.size(); i < size; ++i) {
final PerPackageReadTimeouts perPackage = perPackageReadTimeouts.get(i);
- final PackageStateInternal ps = getPackageStateInternal(perPackage.packageName);
+ final PackageStateInternal ps =
+ snapshot.getPackageStateInternal(perPackage.packageName);
if (ps == null) {
if (DEBUG_PER_UID_READ_TIMEOUTS) {
Slog.i(TAG, "PerUidReadTimeouts: package not found = "
@@ -8546,7 +6866,7 @@
return result.toArray(new PerUidReadTimeouts[result.size()]);
}
- private void setKeepUninstalledPackagesInternal(List<String> packageList) {
+ void setKeepUninstalledPackagesInternal(@NonNull Computer snapshot, List<String> packageList) {
Preconditions.checkNotNull(packageList);
synchronized (mKeepUninstalledPackages) {
List<String> toRemove = new ArrayList<>(mKeepUninstalledPackages);
@@ -8556,7 +6876,7 @@
mKeepUninstalledPackages.addAll(packageList);
for (int i = 0; i < toRemove.size(); i++) {
- deletePackageIfUnused(toRemove.get(i));
+ deletePackageIfUnused(snapshot, toRemove.get(i));
}
}
}
@@ -8603,43 +6923,44 @@
mInstrumentation.put(name, instrumentation);
}
- String[] getKnownPackageNamesInternal(int knownPackage, int userId) {
+ String[] getKnownPackageNamesInternal(@NonNull Computer snapshot, int knownPackage,
+ int userId) {
switch (knownPackage) {
case PackageManagerInternal.PACKAGE_BROWSER:
return new String[] { mDefaultAppProvider.getDefaultBrowser(userId) };
case PackageManagerInternal.PACKAGE_INSTALLER:
- return mComputer.filterOnlySystemPackages(mRequiredInstallerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredInstallerPackage);
case PackageManagerInternal.PACKAGE_UNINSTALLER:
- return mComputer.filterOnlySystemPackages(mRequiredUninstallerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredUninstallerPackage);
case PackageManagerInternal.PACKAGE_SETUP_WIZARD:
- return mComputer.filterOnlySystemPackages(mSetupWizardPackage);
+ return snapshot.filterOnlySystemPackages(mSetupWizardPackage);
case PackageManagerInternal.PACKAGE_SYSTEM:
return new String[]{"android"};
case PackageManagerInternal.PACKAGE_VERIFIER:
- return mComputer.filterOnlySystemPackages(mRequiredVerifierPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredVerifierPackage);
case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER:
- return mComputer.filterOnlySystemPackages(
+ return snapshot.filterOnlySystemPackages(
mDefaultTextClassifierPackage, mSystemTextClassifierPackageName);
case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER:
- return mComputer.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
+ return snapshot.filterOnlySystemPackages(mRequiredPermissionControllerPackage);
case PackageManagerInternal.PACKAGE_CONFIGURATOR:
- return mComputer.filterOnlySystemPackages(mConfiguratorPackage);
+ return snapshot.filterOnlySystemPackages(mConfiguratorPackage);
case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER:
- return mComputer.filterOnlySystemPackages(mIncidentReportApproverPackage);
+ return snapshot.filterOnlySystemPackages(mIncidentReportApproverPackage);
case PackageManagerInternal.PACKAGE_AMBIENT_CONTEXT_DETECTION:
- return mComputer.filterOnlySystemPackages(mAmbientContextDetectionPackage);
+ return snapshot.filterOnlySystemPackages(mAmbientContextDetectionPackage);
case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
- return mComputer.filterOnlySystemPackages(mAppPredictionServicePackage);
+ return snapshot.filterOnlySystemPackages(mAppPredictionServicePackage);
case PackageManagerInternal.PACKAGE_COMPANION:
- return mComputer.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
+ return snapshot.filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
return TextUtils.isEmpty(mRetailDemoPackage)
? ArrayUtils.emptyArray(String.class)
: new String[] {mRetailDemoPackage};
case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
- return mComputer.filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
+ return snapshot.filterOnlySystemPackages(mOverlayConfigSignaturePackage);
case PackageManagerInternal.PACKAGE_RECENTS:
- return mComputer.filterOnlySystemPackages(mRecentsPackage);
+ return snapshot.filterOnlySystemPackages(mRecentsPackage);
default:
return ArrayUtils.emptyArray(String.class);
}
@@ -8659,10 +6980,6 @@
mDefaultAppProvider.setDefaultBrowser(packageName, async, userId);
}
- ResolveInfo getInstantAppInstallerInfo() {
- return mInstantAppInstallerInfo;
- }
-
PackageUsage getPackageUsage() {
return mPackageUsage;
}
@@ -8754,10 +7071,6 @@
}
}
- ResolveInfo getResolveInfo() {
- return mResolveInfo;
- }
-
ApplicationInfo getCoreAndroidApplication() {
return mAndroidApplication;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 8d3fbf7..2a1a990 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -850,6 +850,8 @@
ret.recommendedInstallLocation = recommendedInstallLocation;
ret.multiArch = pkg.isMultiArch();
ret.debuggable = pkg.isDebuggable();
+ ret.isSdkLibrary = pkg.isIsSdkLibrary();
+
return ret;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index b92f51b..62e9d37 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -131,6 +131,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
@@ -144,6 +145,10 @@
private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
private static final int DEFAULT_STAGED_READY_TIMEOUT_MS = 60 * 1000;
private static final String TAG = "PackageManagerShellCommand";
+ private static final Set<String> UNSUPPORTED_INSTALL_CMD_OPTS = Set.of(
+ "--multi-package"
+ );
+ private static final Set<String> UNSUPPORTED_SESSION_CREATE_OPTS = Collections.emptySet();
final IPackageManager mInterface;
final LegacyPermissionManagerInternal mLegacyPermissionManager;
@@ -1330,7 +1335,7 @@
}
private int runStreamingInstall() throws RemoteException {
- final InstallParams params = makeInstallParams();
+ final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
if (params.sessionParams.dataLoaderParams == null) {
params.sessionParams.setDataLoaderParams(
PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
@@ -1339,7 +1344,7 @@
}
private int runIncrementalInstall() throws RemoteException {
- final InstallParams params = makeInstallParams();
+ final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
if (params.sessionParams.dataLoaderParams == null) {
params.sessionParams.setDataLoaderParams(
PackageManagerShellCommandDataLoader.getIncrementalDataLoaderParams(this));
@@ -1348,7 +1353,7 @@
}
private int runInstall() throws RemoteException {
- return doRunInstall(makeInstallParams());
+ return doRunInstall(makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS));
}
private int doRunInstall(final InstallParams params) throws RemoteException {
@@ -1500,7 +1505,7 @@
private int runInstallCreate() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final InstallParams installParams = makeInstallParams();
+ final InstallParams installParams = makeInstallParams(UNSUPPORTED_SESSION_CREATE_OPTS);
final int sessionId = doCreateSession(installParams.sessionParams,
installParams.installerPackageName, installParams.userId);
@@ -2896,7 +2901,7 @@
long stagedReadyTimeoutMs = DEFAULT_STAGED_READY_TIMEOUT_MS;
}
- private InstallParams makeInstallParams() {
+ private InstallParams makeInstallParams(Set<String> unsupportedOptions) {
final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
final InstallParams params = new InstallParams();
@@ -2910,6 +2915,9 @@
boolean replaceExisting = true;
boolean forceNonStaged = false;
while ((opt = getNextOption()) != null) {
+ if (unsupportedOptions.contains(opt)) {
+ throw new IllegalArgumentException("Unsupported option " + opt);
+ }
switch (opt) {
case "-r": // ignore
break;
@@ -3817,7 +3825,7 @@
pw.println(" [--user USER_ID] INTENT");
pw.println(" Prints all broadcast receivers that can handle the given INTENT.");
pw.println("");
- pw.println(" install [-rtfdgw] [-i PACKAGE] [--user USER_ID|all|current]");
+ pw.println(" install [-rtfdg] [-i PACKAGE] [--user USER_ID|all|current]");
pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
pw.println(" [--install-reason 0/1/2/3/4] [--originating-uri URI]");
pw.println(" [--referrer URI] [--abi ABI_NAME] [--force-sdk]");
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index fdad833..28ad4b6 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -38,8 +38,6 @@
String mInstallerPackageName;
int mUid = -1;
int mRemovedAppId = -1;
- // If not -1, the app is going through an appId change
- int mNewAppId = -1;
int[] mOrigUsers;
int[] mRemovedUsers = null;
int[] mBroadcastUsers = null;
@@ -67,22 +65,16 @@
sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
}
- void sendSystemPackageUpdatedBroadcasts(int newAppId) {
+ void sendSystemPackageUpdatedBroadcasts() {
if (mIsRemovedPackageSystemUpdate) {
- sendSystemPackageUpdatedBroadcastsInternal(newAppId);
+ sendSystemPackageUpdatedBroadcastsInternal();
}
}
- private void sendSystemPackageUpdatedBroadcastsInternal(int newAppId) {
+ private void sendSystemPackageUpdatedBroadcastsInternal() {
Bundle extras = new Bundle(2);
- extras.putInt(Intent.EXTRA_UID, newAppId);
- // When appId changes, do not set the replacing extra
- if (mNewAppId >= 0) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_PREVIOUS_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
- } else {
- extras.putBoolean(Intent.EXTRA_REPLACING, true);
- }
+ extras.putInt(Intent.EXTRA_UID, mRemovedAppId >= 0 ? mRemovedAppId : mUid);
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, mRemovedPackage, extras,
0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
if (mInstallerPackageName != null) {
@@ -90,17 +82,13 @@
mRemovedPackage, extras, 0 /*flags*/,
mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
null);
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
+ mRemovedPackage, extras, 0 /*flags*/,
+ mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
+ null);
}
- if (mNewAppId < 0) {
- mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
- extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
- if (mInstallerPackageName != null) {
- mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
- mRemovedPackage, extras, 0 /*flags*/,
- mInstallerPackageName, null, null, null, null /* broadcastAllowList */,
- null);
- }
- }
+ mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, mRemovedPackage,
+ extras, 0, null /*targetPackage*/, null, null, null, mBroadcastAllowList, null);
mPackageSender.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, 0,
mRemovedPackage, null, null, null, null /* broadcastAllowList */,
getTemporaryAppAllowlistBroadcastOptions(REASON_PACKAGE_REPLACED).toBundle());
@@ -134,15 +122,10 @@
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
-
- // When appId changes, do not set the replacing extra
- if (mNewAppId >= 0) {
- extras.putBoolean(Intent.EXTRA_UID_CHANGING, true);
- extras.putInt(Intent.EXTRA_NEW_UID, mNewAppId);
- } else if (mIsUpdate || mIsRemovedPackageSystemUpdate) {
+ final boolean isReplace = mIsUpdate || mIsRemovedPackageSystemUpdate;
+ if (isReplace) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
-
extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, mRemovedForAllUsers);
if (mRemovedPackage != null) {
mPackageSender.sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED,
@@ -165,9 +148,9 @@
}
}
if (mRemovedAppId >= 0) {
- // If the package is not actually removed, some services need to know the
- // package name affected.
- if (mNewAppId >= 0 || mIsUpdate || mIsRemovedPackageSystemUpdate) {
+ // 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) {
extras.putString(Intent.EXTRA_PACKAGE_NAME, mRemovedPackage);
}
diff --git a/services/core/java/com/android/server/pm/PackageSender.java b/services/core/java/com/android/server/pm/PackageSender.java
index d380098..656d596 100644
--- a/services/core/java/com/android/server/pm/PackageSender.java
+++ b/services/core/java/com/android/server/pm/PackageSender.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IIntentReceiver;
import android.os.Bundle;
@@ -30,9 +31,9 @@
Bundle extras, int flags, String targetPkg,
IIntentReceiver finishedReceiver, int[] userIds, int[] instantUserIds,
@Nullable SparseArray<int[]> broadcastAllowList, @Nullable Bundle bOptions);
- void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
- boolean includeStopped, int appId, int[] userIds, int[] instantUserIds,
- int dataLoaderType);
+ void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
+ boolean sendBootCompleted, boolean includeStopped, int appId, int[] userIds,
+ int[] instantUserIds, int dataLoaderType);
void notifyPackageAdded(String packageName, int uid);
void notifyPackageChanged(String packageName, int uid);
void notifyPackageRemoved(String packageName, int uid);
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index 6b57deb..2016fc3 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -24,7 +24,6 @@
import android.content.Intent;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
@@ -110,7 +109,7 @@
verifyAPK(session, callback);
} catch (PackageManagerException e) {
String errorMessage = PackageManager.installStatusToString(e.error, e.getMessage());
- session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
+ session.setSessionFailed(e.error, errorMessage);
callback.onResult(e.error, e.getMessage());
}
});
@@ -137,7 +136,7 @@
}
if (returnCode != PackageManager.INSTALL_SUCCEEDED) {
String errorMessage = PackageManager.installStatusToString(returnCode, msg);
- session.setSessionFailed(SessionInfo.SESSION_VERIFICATION_FAILED, errorMessage);
+ session.setSessionFailed(returnCode, errorMessage);
callback.onResult(returnCode, msg);
} else {
session.setSessionReady();
@@ -220,7 +219,7 @@
}
private void onVerificationFailure(StagingManager.StagedSession session, Callback callback,
- @SessionInfo.SessionErrorCode int errorCode, String errorMessage) {
+ int errorCode, String errorMessage) {
if (!ensureActiveApexSessionIsAborted(session)) {
Slog.e(TAG, "Failed to abort apex session " + session.sessionId());
// Safe to ignore active apex session abortion failure since session will be marked
@@ -312,7 +311,7 @@
// Failed to get hold of StorageManager
Slog.e(TAG, "Failed to get hold of StorageManager", e);
throw new PackageManagerException(
- SessionInfo.SESSION_UNKNOWN_ERROR,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Failed to get hold of StorageManager");
}
// Proactively mark session as ready before calling apexd. Although this call order
@@ -350,7 +349,7 @@
final ParseResult<SigningDetails> newResult = ApkSignatureVerifier.verify(
input.reset(), apexPath, minSignatureScheme);
if (newResult.isError()) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + apexPath + " : "
+ newResult.getException(), newResult.getException());
}
@@ -369,7 +368,7 @@
input.reset(), existingApexPkg.applicationInfo.sourceDir,
SigningDetails.SignatureSchemeVersion.JAR);
if (existingResult.isError()) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + existingApexPkg.applicationInfo.sourceDir
+ " : " + existingResult.getException(), existingResult.getException());
}
@@ -383,7 +382,7 @@
return;
}
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"APK-container signature of APEX package " + packageName + " with version "
+ newApexPkg.versionCodeMajor + " and path " + apexPath + " is not"
+ " compatible with the one currently installed on device");
@@ -426,11 +425,12 @@
packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags);
if (packageInfo == null) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Unable to generate package info: " + apexInfo.modulePath);
}
} catch (PackageManagerException e) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Failed to parse APEX package " + apexInfo.modulePath + " : " + e, e);
}
result.add(packageInfo);
@@ -452,7 +452,7 @@
}
}
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Could not find rollback id for commit session: " + sessionId);
}
@@ -560,7 +560,7 @@
try {
checkActiveSessions(InstallLocationUtils.getStorageManager().supportsCheckpoint());
} catch (RemoteException e) {
- throw new PackageManagerException(SessionInfo.SESSION_VERIFICATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Can't query fs-checkpoint status : " + e);
}
}
@@ -576,7 +576,7 @@
}
if (!supportsCheckpoint && activeSessions > 1) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support");
}
}
@@ -607,13 +607,13 @@
// will be deleted.
}
stagedSession.setSessionFailed(
- SessionInfo.SESSION_CONFLICT,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Session was failed by rollback session: " + session.sessionId());
Slog.i(TAG, "Session " + stagedSession.sessionId() + " is marked failed due to "
+ "rollback session: " + session.sessionId());
} else if (!isRollback(session) && isRollback(stagedSession)) {
throw new PackageManagerException(
- SessionInfo.SESSION_CONFLICT,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Session was failed by rollback session: " + stagedSession.sessionId());
}
@@ -636,7 +636,7 @@
final String packageName = child.getPackageName();
if (packageName == null) {
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"Cannot stage session " + child.sessionId() + " with package name null");
}
for (StagingManager.StagedSession stagedSession : mStagedSessions) {
@@ -648,14 +648,14 @@
if (stagedSession.getCommittedMillis() < parent.getCommittedMillis()) {
// Fail the session committed later when there are overlapping packages
throw new PackageManagerException(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Package: " + packageName + " in session: "
+ child.sessionId()
+ " has been staged already by session: "
+ stagedSession.sessionId());
} else {
stagedSession.setSessionFailed(
- SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Package: " + packageName + " in session: "
+ stagedSession.sessionId()
+ " has been staged already by session: "
diff --git a/services/core/java/com/android/server/pm/PreferredActivityHelper.java b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
index 7253ae4..9befd6e 100644
--- a/services/core/java/com/android/server/pm/PreferredActivityHelper.java
+++ b/services/core/java/com/android/server/pm/PreferredActivityHelper.java
@@ -25,6 +25,7 @@
import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -74,17 +75,18 @@
mPm = pm;
}
- private ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType,
- @PackageManager.ResolveInfoFlagsBits long flags, List<ResolveInfo> query,
- boolean always, boolean removeMatches, boolean debug, int userId) {
- return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, always, removeMatches, debug, userId,
+ private ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
+ List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
+ @UserIdInt int userId) {
+ return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId,
UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
}
// TODO: handle preferred activities missing while user has amnesia
/** <b>must not hold {@link PackageManagerService.mLock}</b> */
- public ResolveInfo findPreferredActivityNotLocked(
+ public ResolveInfo findPreferredActivityNotLocked(@NonNull Computer snapshot,
Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
List<ResolveInfo> query, boolean always, boolean removeMatches, boolean debug,
int userId, boolean queryMayBeFiltered) {
@@ -95,7 +97,7 @@
if (!mPm.mUserManager.exists(userId)) return null;
PackageManagerService.FindPreferredActivityBodyResult body =
- mPm.findPreferredActivityInternal(
+ snapshot.findPreferredActivityInternal(
intent, resolvedType, flags, query, always,
removeMatches, debug, userId, queryMayBeFiltered);
if (body.mChanged) {
@@ -117,7 +119,7 @@
mPm.clearPackagePreferredActivitiesLPw(packageName, changedUsers, userId);
}
if (changedUsers.size() > 0) {
- updateDefaultHomeNotLocked(changedUsers);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), changedUsers);
mPm.postPreferredActivityChangedBroadcast(userId);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -128,7 +130,7 @@
*
* @return Whether the ACTION_PREFERRED_ACTIVITY_CHANGED broadcast has been scheduled.
*/
- public boolean updateDefaultHomeNotLocked(int userId) {
+ public boolean updateDefaultHomeNotLocked(@NonNull Computer snapshot, @UserIdInt int userId) {
if (Thread.holdsLock(mPm.mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
@@ -139,10 +141,10 @@
// before that.
return false;
}
- final Intent intent = mPm.getHomeIntent();
- final List<ResolveInfo> resolveInfos = mPm.snapshotComputer().queryIntentActivitiesInternal(
+ final Intent intent = snapshot.getHomeIntent();
+ final List<ResolveInfo> resolveInfos = snapshot.queryIntentActivitiesInternal(
intent, null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
- final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(
+ final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked(snapshot,
intent, null, 0, resolveInfos, true, false, false, userId);
final String packageName = preferredResolveInfo != null
&& preferredResolveInfo.activityInfo != null
@@ -151,8 +153,7 @@
if (TextUtils.equals(currentPackageName, packageName)) {
return false;
}
- final String[] callingPackages = mPm.mIPackageManager
- .getPackagesForUid(Binder.getCallingUid());
+ final String[] callingPackages = snapshot.getPackagesForUid(Binder.getCallingUid());
if (callingPackages != null && ArrayUtils.contains(callingPackages,
mPm.mRequiredPermissionControllerPackage)) {
// PermissionController manages default home directly.
@@ -174,23 +175,21 @@
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void addPreferredActivity(WatchedIntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, boolean always, int userId,
+ public void addPreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity, boolean always, int userId,
String opname, boolean removeExisting) {
// writer
int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "add preferred activity");
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- synchronized (mPm.mLock) {
- if (mPm.getUidTargetSdkVersion(callingUid)
- < Build.VERSION_CODES.FROYO) {
- Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
- + callingUid);
- return;
- }
+ if (snapshot.getUidTargetSdkVersion(callingUid)
+ < Build.VERSION_CODES.FROYO) {
+ Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
+ + callingUid);
+ return;
}
mPm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -214,7 +213,8 @@
new PreferredActivity(filter, match, set, activity, always));
mPm.scheduleWritePackageRestrictions(userId);
}
- if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(userId))) {
+ // Re-snapshot after mLock
+ if (!(isHomeFilter(filter) && updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId))) {
mPm.postPreferredActivityChangedBroadcast(userId);
}
}
@@ -222,8 +222,8 @@
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void replacePreferredActivity(WatchedIntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
+ public void replacePreferredActivity(@NonNull Computer snapshot, WatchedIntentFilter filter,
+ int match, ComponentName[] set, ComponentName activity, int userId) {
if (filter.countActions() != 1) {
throw new IllegalArgumentException(
"replacePreferredActivity expects filter to have only 1 action.");
@@ -238,13 +238,14 @@
}
final int callingUid = Binder.getCallingUid();
- mPm.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
+ snapshot.enforceCrossUserPermission(callingUid, userId, true /* requireFullPermission */,
false /* checkShell */, "replace preferred activity");
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
synchronized (mPm.mLock) {
- if (mPm.getUidTargetSdkVersion(callingUid)
+ // TODO: Remove lock?
+ if (mPm.snapshotComputer().getUidTargetSdkVersion(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
+ Binder.getCallingUid());
@@ -296,21 +297,23 @@
}
}
}
- addPreferredActivity(filter, match, set, activity, true, userId,
+
+ // Retake a snapshot after editing with lock held
+ addPreferredActivity(mPm.snapshotComputer(), filter, match, set, activity, true, userId,
"Replacing preferred", false);
}
- public void clearPackagePreferredActivities(String packageName) {
+ public void clearPackagePreferredActivities(@NonNull Computer snapshot, String packageName) {
final int callingUid = Binder.getCallingUid();
- if (mPm.getInstantAppPackageName(callingUid) != null) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return;
}
- final PackageStateInternal packageState = mPm.getPackageStateInternal(packageName);
- if (packageState == null || !mPm.isCallerSameApp(packageName, callingUid)) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
+ if (packageState == null || !snapshot.isCallerSameApp(packageName, callingUid)) {
if (mPm.mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
- if (mPm.getUidTargetSdkVersion(callingUid)
+ if (snapshot.getUidTargetSdkVersion(callingUid)
< Build.VERSION_CODES.FROYO) {
Slog.w(TAG, "Ignoring clearPackagePreferredActivities() from uid "
+ callingUid);
@@ -320,7 +323,7 @@
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
}
- if (packageState != null && mPm.shouldFilterApplication(packageState, callingUid,
+ if (packageState != null && snapshot.shouldFilterApplication(packageState, callingUid,
UserHandle.getUserId(callingUid))) {
return;
}
@@ -329,23 +332,23 @@
}
/** <b>must not hold {@link #PackageManagerService.mLock}</b> */
- void updateDefaultHomeNotLocked(SparseBooleanArray userIds) {
+ void updateDefaultHomeNotLocked(@NonNull Computer snapshot, SparseBooleanArray userIds) {
if (Thread.holdsLock(mPm.mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
}
for (int i = userIds.size() - 1; i >= 0; --i) {
final int userId = userIds.keyAt(i);
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(snapshot, userId);
}
}
- public void setHomeActivity(ComponentName comp, int userId) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public void setHomeActivity(@NonNull Computer snapshot, ComponentName comp, int userId) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
- mPm.getHomeActivitiesAsUser(homeActivities, userId);
+ snapshot.getHomeActivitiesAsUser(homeActivities, userId);
boolean found = false;
@@ -364,7 +367,7 @@
throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
+ userId);
}
- replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
+ replacePreferredActivity(snapshot, getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
set, comp, userId);
}
@@ -401,7 +404,7 @@
mPm.scheduleWritePackageRestrictions(userId);
}
if (isHomeFilter(filter)) {
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
}
mPm.postPreferredActivityChangedBroadcast(userId);
}
@@ -417,7 +420,7 @@
changed = mPm.mSettings.clearPackagePersistentPreferredActivities(packageName, userId);
}
if (changed) {
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
mPm.postPreferredActivityChangedBroadcast(userId);
mPm.scheduleWritePackageRestrictions(userId);
}
@@ -506,7 +509,7 @@
synchronized (mPm.mLock) {
mPm.mSettings.readPreferredActivitiesLPw(readParser, readUserId);
}
- updateDefaultHomeNotLocked(readUserId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), readUserId);
});
} catch (Exception e) {
if (DEBUG_BACKUP) {
@@ -598,7 +601,7 @@
mPm.mPermissionManager.resetRuntimePermissions(pkg, userId);
}
}
- updateDefaultHomeNotLocked(userId);
+ updateDefaultHomeNotLocked(mPm.snapshotComputer(), userId);
resetNetworkPolicies(userId);
mPm.scheduleWritePackageRestrictions(userId);
} finally {
@@ -610,12 +613,11 @@
mPm.mInjector.getLocalService(NetworkPolicyManagerInternal.class).resetUserState(userId);
}
- // TODO: This method should not touch the Computer directly
- public int getPreferredActivities(List<IntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName, Computer computer) {
+ public int getPreferredActivities(@NonNull Computer snapshot, List<IntentFilter> outFilters,
+ List<ComponentName> outActivities, String packageName) {
List<WatchedIntentFilter> temp =
WatchedIntentFilter.toWatchedIntentFilterList(outFilters);
- int result = getPreferredActivitiesInternal(temp, outActivities, packageName, computer);
+ int result = getPreferredActivitiesInternal(snapshot, temp, outActivities, packageName);
outFilters.clear();
for (int i = 0; i < temp.size(); i++) {
outFilters.add(temp.get(i).getIntentFilter());
@@ -626,16 +628,17 @@
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- private int getPreferredActivitiesInternal(List<WatchedIntentFilter> outFilters,
- List<ComponentName> outActivities, String packageName, Computer computer) {
+ private int getPreferredActivitiesInternal(@NonNull Computer snapshot,
+ List<WatchedIntentFilter> outFilters, List<ComponentName> outActivities,
+ String packageName) {
final int callingUid = Binder.getCallingUid();
- if (mPm.getInstantAppPackageName(callingUid) != null) {
+ if (snapshot.getInstantAppPackageName(callingUid) != null) {
return 0;
}
int num = 0;
final int userId = UserHandle.getCallingUserId();
- PreferredIntentResolver pir = computer.getPreferredActivities(userId);
+ PreferredIntentResolver pir = snapshot.getPreferredActivities(userId);
if (pir != null) {
final Iterator<PreferredActivity> it = pir.filterIterator();
while (it.hasNext()) {
@@ -643,8 +646,9 @@
final String prefPackageName = pa.mPref.mComponent.getPackageName();
if (packageName == null
|| (prefPackageName.equals(packageName) && pa.mPref.mAlways)) {
- if (mPm.shouldFilterApplication(
- mPm.getPackageStateInternal(prefPackageName), callingUid, userId)) {
+ if (snapshot.shouldFilterApplication(
+ snapshot.getPackageStateInternal(prefPackageName), callingUid,
+ userId)) {
continue;
}
if (outFilters != null) {
@@ -660,7 +664,8 @@
return num;
}
- public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) {
+ public ResolveInfo findPersistentPreferredActivity(@NonNull Computer snapshot, Intent intent,
+ int userId) {
if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.SYSTEM_UID)) {
throw new SecurityException(
"findPersistentPreferredActivity can only be run by the system");
@@ -671,24 +676,23 @@
final int callingUid = Binder.getCallingUid();
intent = PackageManagerServiceUtils.updateIntentForResolve(intent);
final String resolvedType = intent.resolveTypeIfNeeded(mPm.mContext.getContentResolver());
- final long flags = mPm.updateFlagsForResolve(
+ final long flags = snapshot.updateFlagsForResolve(
0, userId, callingUid, false /*includeInstantApps*/,
- mPm.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ snapshot.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId, resolvedType,
0));
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
- synchronized (mPm.mLock) {
- return mPm.findPersistentPreferredActivityLP(intent, resolvedType, flags, query, false,
- userId);
- }
+ return snapshot.findPersistentPreferredActivity(intent, resolvedType, flags, query, false,
+ userId);
}
/**
* Variant that takes a {@link WatchedIntentFilter}
*/
- public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
- WatchedIntentFilter filter, int match, ComponentName activity) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public void setLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, int flags, WatchedIntentFilter filter, int match,
+ ComponentName activity) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
final int userId = UserHandle.getCallingUserId();
@@ -702,25 +706,26 @@
filter.dump(new PrintStreamPrinter(System.out), " ");
}
intent.setComponent(null);
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
// Find any earlier preferred or last chosen entries and nuke them
- findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, false, true, false, userId);
+ findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false, true,
+ false, userId);
// Add the new activity as the last chosen for this filter
- addPreferredActivity(filter, match, null, activity, false, userId,
+ addPreferredActivity(snapshot, filter, match, null, activity, false, userId,
"Setting last chosen", false);
}
- public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags) {
- if (mPm.getInstantAppPackageName(Binder.getCallingUid()) != null) {
+ public ResolveInfo getLastChosenActivity(@NonNull Computer snapshot, Intent intent,
+ String resolvedType, int flags) {
+ if (snapshot.getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
final int userId = UserHandle.getCallingUserId();
if (DEBUG_PREFERRED) Log.v(TAG, "Querying last chosen activity for " + intent);
- final List<ResolveInfo> query = mPm.snapshotComputer().queryIntentActivitiesInternal(intent,
+ final List<ResolveInfo> query = snapshot.queryIntentActivitiesInternal(intent,
resolvedType, flags, userId);
- return findPreferredActivityNotLocked(
- intent, resolvedType, flags, query, false, false, false, userId);
+ return findPreferredActivityNotLocked(snapshot, intent, resolvedType, flags, query, false,
+ false, false, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 4ec042f..2a1ca2c 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -57,7 +57,6 @@
private String mParseError;
private final Callbacks mCallbacks;
- private final String mSetupWizardPackageName;
public interface Callbacks {
public boolean onReadTag(String tagName, TypedXmlPullParser parser)
@@ -72,7 +71,6 @@
mAlways = always;
mShortComponent = component.flattenToShortString();
mParseError = null;
- mSetupWizardPackageName = null;
if (set != null) {
final int N = set.length;
String[] myPackages = new String[N];
@@ -174,8 +172,6 @@
mSetPackages = myPackages;
mSetClasses = myClasses;
mSetComponents = myComponents;
- final PackageManagerInternal packageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mSetupWizardPackageName = packageManagerInternal.getSetupWizardPackageName();
}
public String getParseError() {
@@ -209,6 +205,7 @@
final int NQ = query.size();
final int NS = mSetPackages.length;
final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ String setupWizardPackageName = pmi.getSetupWizardPackageName();
int numMatch = 0;
for (int i=0; i<NQ; i++) {
ResolveInfo ri = query.get(i);
@@ -217,7 +214,7 @@
// ignore SetupWizard package's launcher capability because it is only existed
// during SetupWizard is running
- if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+ if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
continue;
}
@@ -307,6 +304,8 @@
if (!excludeSetupWizardPackage && NS < NQ) {
return false;
}
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ String setupWizardPackageName = pmi.getSetupWizardPackageName();
for (int i=0; i<NQ; i++) {
ResolveInfo ri = query.get(i);
ActivityInfo ai = ri.activityInfo;
@@ -314,7 +313,7 @@
// ignore SetupWizard package's launcher capability because it is only existed
// during SetupWizard is running
- if (excludeSetupWizardPackage && ai.packageName.equals(mSetupWizardPackageName)) {
+ if (excludeSetupWizardPackage && ai.packageName.equals(setupWizardPackageName)) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index 88df843..b181cdd 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -118,7 +118,8 @@
public void removePackageLI(AndroidPackage pkg, boolean chatty) {
// Remove the parent package setting
- PackageStateInternal ps = mPm.getPackageStateInternal(pkg.getPackageName());
+ PackageStateInternal ps = mPm.snapshotComputer()
+ .getPackageStateInternal(pkg.getPackageName());
if (ps != null) {
removePackageLI(ps.getPackageName(), chatty);
} else if (DEBUG_REMOVE && chatty) {
@@ -271,8 +272,8 @@
synchronized (mPm.mLock) {
mPm.mDomainVerificationManager.clearPackage(deletedPs.getPackageName());
mPm.mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mPm.mAppsFilter.removePackage(mPm.getPackageStateInternal(packageName),
- false /* isReplace */);
+ mPm.mAppsFilter.removePackage(mPm.snapshotComputer()
+ .getPackageStateInternal(packageName), false /* isReplace */);
removedAppId = mPm.mSettings.removePackageLPw(packageName);
if (outInfo != null) {
outInfo.mRemovedAppId = removedAppId;
@@ -298,7 +299,8 @@
if (changedUsers.size() > 0) {
final PreferredActivityHelper preferredActivityHelper =
new PreferredActivityHelper(mPm);
- preferredActivityHelper.updateDefaultHomeNotLocked(changedUsers);
+ preferredActivityHelper.updateDefaultHomeNotLocked(mPm.snapshotComputer(),
+ changedUsers);
mPm.postPreferredActivityChangedBroadcast(UserHandle.USER_ALL);
}
}
diff --git a/services/core/java/com/android/server/pm/ResolveIntentHelper.java b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
index 25356a4..b74670b 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -115,7 +115,7 @@
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "resolve intent");
@@ -170,9 +170,9 @@
}
// If we have saved a preference for a preferred activity for
// this Intent, use that.
- ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(intent,
- resolvedType, flags, query, true, false, debug, userId,
- queryMayBeFiltered);
+ ResolveInfo ri = mPreferredActivityHelper.findPreferredActivityNotLocked(computer,
+ intent, resolvedType, flags, query, true, false, debug,
+ userId, queryMayBeFiltered);
if (ri != null) {
return ri;
}
@@ -317,7 +317,7 @@
final String instantAppPkgName = computer.getInstantAppPackageName(filterCallingUid);
flags = computer.updateFlagsForResolve(flags, userId, filterCallingUid,
false /*includeInstantApps*/,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
Intent originalIntent = null;
ComponentName comp = intent.getComponent();
@@ -562,7 +562,7 @@
final int callingUid = Binder.getCallingUid();
flags = computer.updateFlagsForResolve(flags, userId, callingUid,
false /*includeInstantApps*/,
- computer.isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ computer.isImplicitImageCaptureIntentAndNotSetByDpc(intent, userId,
resolvedType, flags));
computer.enforceCrossUserPermission(callingUid, userId, false /*requireFullPermission*/,
false /*checkShell*/, "query intent activity options");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 021c3db..6ccaae1 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -40,7 +40,6 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -113,11 +112,9 @@
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
-import com.android.server.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.pkg.component.ParsedComponent;
import com.android.server.pm.pkg.component.ParsedIntentInfo;
-import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.component.ParsedPermission;
import com.android.server.pm.pkg.component.ParsedProcess;
import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
@@ -476,9 +473,9 @@
@Watched
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
@Watched
- private final WatchedArrayList<SettingBase> mAppIds;
+ private final AppIdSettingMap mAppIds;
@Watched
- private final WatchedSparseArray<SettingBase> mOtherAppIds;
+ private final AppIdSettingMap mOtherAppIds;
// For reading/writing settings file.
@Watched
@@ -594,8 +591,8 @@
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
+ mOtherAppIds = new AppIdSettingMap();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -631,8 +628,8 @@
mKeySetManagerService = new KeySetManagerService(mPackages);
mLock = lock;
- mAppIds = new WatchedArrayList<>();
- mOtherAppIds = new WatchedSparseArray<>();
+ mAppIds = new AppIdSettingMap();
+ mOtherAppIds = new AppIdSettingMap();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence, new Consumer<Integer>() {
@@ -1278,7 +1275,8 @@
// Utility method that adds a PackageSetting to mPackages and
// completes updating the shared user attributes and any restored
// app link verification state
- private void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
mPackages.put(p.getPackageName(), p);
if (sharedUser != null) {
SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);
@@ -1301,7 +1299,7 @@
p.setAppId(sharedUser.mAppId);
}
- // If the we know about this user id, we have to update it as it
+ // If we know about this user id, we have to update it as it
// has to point to the same PackageSetting instance as the package.
Object userIdPs = getSettingLPr(p.getAppId());
if (sharedUser == null) {
@@ -1366,20 +1364,13 @@
}
if (appId >= Process.FIRST_APPLICATION_UID) {
- int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- // fill the array until our index becomes valid
- while (index >= size) {
- mAppIds.add(null);
- size++;
- }
- if (mAppIds.get(index) != null) {
+ if (mAppIds.get(appId) != null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Adding duplicate app id: " + appId
+ " name=" + name);
return false;
}
- mAppIds.set(index, obj);
+ mAppIds.put(appId, obj);
} else {
if (mOtherAppIds.get(appId) != null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -1395,9 +1386,7 @@
/** Gets the setting associated with the provided App ID */
public SettingBase getSettingLPr(int appId) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- return index < size ? mAppIds.get(index) : null;
+ return mAppIds.get(appId);
} else {
return mOtherAppIds.get(appId);
}
@@ -1406,9 +1395,7 @@
/** Unregisters the provided app ID. */
void removeAppIdLPw(int appId) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, null);
+ mAppIds.remove(appId);
} else {
mOtherAppIds.remove(appId);
}
@@ -1417,9 +1404,14 @@
private void replaceAppIdLPw(int appId, SettingBase obj) {
if (appId >= Process.FIRST_APPLICATION_UID) {
- final int size = mAppIds.size();
- final int index = appId - Process.FIRST_APPLICATION_UID;
- if (index < size) mAppIds.set(index, obj);
+ if (appId <= mAppIds.getCurrentMaxAppId()) {
+ mAppIds.put(appId, obj);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: calling replaceAppIdLpw to"
+ + " replace SettingBase at appId=" + appId
+ + " but nothing is replaced.");
+ }
} else {
mOtherAppIds.put(appId, obj);
}
@@ -4304,22 +4296,21 @@
/** Returns a new AppID or -1 if we could not find an available AppID to assign */
private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
- // Let's be stupidly inefficient for now...
- final int size = mAppIds.size();
- for (int i = mFirstAvailableUid - Process.FIRST_APPLICATION_UID; i < size; i++) {
- if (mAppIds.get(i) == null) {
- mAppIds.set(i, obj);
- return Process.FIRST_APPLICATION_UID + i;
+ final int nextAvailableAppId = mAppIds.getNextAvailableAppId();
+ for (int uid = mFirstAvailableUid; uid < nextAvailableAppId; uid++) {
+ if (mAppIds.get(uid) == null) {
+ mAppIds.put(uid, obj);
+ return uid;
}
}
// None left?
- if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
+ if (nextAvailableAppId > Process.LAST_APPLICATION_UID) {
return -1;
}
- mAppIds.add(obj);
- return Process.FIRST_APPLICATION_UID + size;
+ mAppIds.put(nextAvailableAppId, obj);
+ return nextAvailableAppId;
}
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
@@ -4354,33 +4345,6 @@
return getDisabledSystemPkgLPr(enabledPackageSetting.getPackageName());
}
- boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, long flags, int userId) {
- final PackageSetting ps = mPackages.get(componentInfo.packageName);
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, componentInfo, flags);
- }
-
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public boolean isEnabledAndMatchLPr(AndroidPackage pkg, ParsedMainComponent component,
- long flags, int userId) {
- final PackageSetting ps = mPackages.get(component.getPackageName());
- if (ps == null) return false;
-
- final PackageUserStateInternal userState = ps.readUserState(userId);
- return PackageUserStateUtils.isMatch(userState, pkg.isSystem(), pkg.isEnabled(), component,
- flags);
- }
-
- boolean isOrphaned(String packageName) {
- final PackageSetting pkg = mPackages.get(packageName);
- if (pkg == null) {
- throw new IllegalArgumentException("Unknown package: " + packageName);
- }
- return pkg.getInstallSource().isOrphaned;
- }
-
int getApplicationEnabledSettingLPr(String packageName, int userId)
throws PackageManager.NameNotFoundException {
final PackageSetting pkg = mPackages.get(packageName);
diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
index 3fe0790..479a404 100644
--- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
+++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java
@@ -741,9 +741,11 @@
}
SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
+ final Computer snapshot = mPm.snapshotComputer();
+
// Remove the shared library overlays from its dependent packages.
for (int currentUserId : mPm.mUserManager.getUserIds()) {
- final List<VersionedPackage> dependents = mPm.getPackagesUsingSharedLibrary(
+ final List<VersionedPackage> dependents = snapshot.getPackagesUsingSharedLibrary(
libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
if (dependents == null) {
continue;
diff --git a/services/core/java/com/android/server/pm/SharedUidMigration.java b/services/core/java/com/android/server/pm/SharedUidMigration.java
index a7d5e955..e44ef66 100644
--- a/services/core/java/com/android/server/pm/SharedUidMigration.java
+++ b/services/core/java/com/android/server/pm/SharedUidMigration.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import android.annotation.IntDef;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.SystemProperties;
@@ -59,22 +60,15 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Strategy {}
+ @Strategy
private static final int DEFAULT = BEST_EFFORT;
/**
- * All shared UID migration is disabled.
- * This is not a strategy that can be set with system properties.
- * To disable shared UID migration, change {@link #DEFAULT} to this value.
- */
- private static final int DISABLED = 0;
-
- /**
* Whether shared UID migration is fully disabled. Disabled means the sharedUserMaxSdkVersion
* attribute will be directly ignored in the parsing phase.
*/
- @SuppressWarnings("ConstantConditions")
public static boolean isDisabled() {
- return DEFAULT == DISABLED;
+ return !PackageManager.ENABLE_SHARED_UID_MIGRATION;
}
/**
@@ -88,7 +82,7 @@
final int s = SystemProperties.getInt(PROPERTY_KEY, DEFAULT);
// No transition strategies can be used (http://b/221088088)
- if (s > BEST_EFFORT || s <= DISABLED) {
+ if (s > BEST_EFFORT || s < NEW_INSTALL_ONLY) {
return DEFAULT;
}
return s;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 52a7bed..43dde5c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -28,8 +28,6 @@
import android.content.pm.ApexStagedEvent;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.StagedApexInfo;
@@ -124,7 +122,7 @@
boolean containsApkSession();
boolean containsApexSession();
void setSessionReady();
- void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage);
+ void setSessionFailed(int errorCode, String errorMessage);
void setSessionApplied();
CompletableFuture<Void> installSession();
boolean hasParentSessionId();
@@ -279,7 +277,7 @@
String packageName = apexSession.getPackageName();
String errorMsg = mApexManager.getApkInApexInstallError(packageName);
if (errorMsg != null) {
- throw new PackageManagerException(SessionInfo.SESSION_ACTIVATION_FAILED,
+ throw new PackageManagerException(PackageManager.INSTALL_ACTIVATION_FAILED,
"Failed to install apk-in-apex of " + packageName + " : " + errorMsg);
}
}
@@ -392,7 +390,7 @@
revertMsg += " Reason for revert: " + reasonForRevert;
}
Slog.d(TAG, revertMsg);
- session.setSessionFailed(SessionInfo.SESSION_UNKNOWN_ERROR, revertMsg);
+ session.setSessionFailed(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, revertMsg);
return;
}
@@ -477,7 +475,7 @@
for (String apkInApex : mApexManager.getApksInApex(packageName)) {
if (!apkNames.add(apkInApex)) {
throw new PackageManagerException(
- SessionInfo.SESSION_ACTIVATION_FAILED,
+ PackageManager.INSTALL_ACTIVATION_FAILED,
"Package: " + packageName + " in session: "
+ apexSession.sessionId() + " has duplicate apk-in-apex: "
+ apkInApex, null);
@@ -495,9 +493,7 @@
// Should be impossible
throw new RuntimeException(e);
} catch (ExecutionException ee) {
- PackageManagerException e = (PackageManagerException) ee.getCause();
- final String errorMsg = PackageManager.installStatusToString(e.error, e.getMessage());
- throw new PackageManagerException(SessionInfo.SESSION_ACTIVATION_FAILED, errorMsg);
+ throw (PackageManagerException) ee.getCause();
}
}
@@ -651,7 +647,7 @@
// is upgrading. Fail all the sessions and exit early.
for (int i = 0; i < sessions.size(); i++) {
StagedSession session = sessions.get(i);
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Build fingerprint has changed");
}
return;
@@ -691,7 +687,7 @@
final ApexSessionInfo apexSession = apexSessions.get(session.sessionId());
if (apexSession == null || apexSession.isUnknown) {
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, "apexd did "
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED, "apexd did "
+ "not know anything about a staged session supposed to be activated");
continue;
} else if (isApexSessionFailed(apexSession)) {
@@ -707,7 +703,7 @@
errorMsg += " Error: " + apexSession.errorMessage;
}
Slog.d(TAG, errorMsg);
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED, errorMsg);
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED, errorMsg);
continue;
} else if (apexSession.isActivated || apexSession.isSuccess) {
hasAppliedApexSession = true;
@@ -716,13 +712,13 @@
// Apexd did not apply the session for some unknown reason. There is no guarantee
// that apexd will install it next time. Safer to proactively mark it as failed.
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Staged session " + session.sessionId() + " at boot didn't activate nor "
+ "fail. Marking it as failed anyway.");
} else {
Slog.w(TAG, "Apex session " + session.sessionId() + " is in impossible state");
hasFailedApexSession = true;
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Impossible state");
}
}
@@ -742,7 +738,7 @@
// Session has been already failed in the loop above.
continue;
}
- session.setSessionFailed(SessionInfo.SESSION_ACTIVATION_FAILED,
+ session.setSessionFailed(PackageManager.INSTALL_ACTIVATION_FAILED,
"Another apex session failed");
}
return;
@@ -758,7 +754,7 @@
} catch (Exception e) {
Slog.e(TAG, "Staged install failed due to unhandled exception", e);
onInstallationFailure(session, new PackageManagerException(
- SessionInfo.SESSION_ACTIVATION_FAILED,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
"Staged install failed due to unhandled exception: " + e),
supportsCheckpoint, needsCheckpoint);
}
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index bb7e55a..df19d3e 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -26,13 +26,13 @@
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import android.annotation.NonNull;
import android.app.ResourcesManager;
import android.content.IIntentReceiver;
import android.content.pm.PackageManager;
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.FileUtils;
import android.os.UserHandle;
@@ -48,6 +48,7 @@
import com.android.internal.policy.AttributeCache;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.util.ArrayList;
@@ -78,7 +79,7 @@
// Clean up any users or apps that were removed or recreated
// while this volume was missing
mPm.mUserManager.reconcileUsers(volumeUuid);
- reconcileApps(volumeUuid);
+ reconcileApps(mPm.snapshotComputer(), volumeUuid);
// Clean up any install sessions that expired or were
// cancelled while this volume was missing
@@ -299,8 +300,8 @@
* aren't expected, either due to uninstallation or reinstallation on
* another volume.
*/
- public void reconcileApps(String volumeUuid) {
- List<String> absoluteCodePaths = collectAbsoluteCodePaths();
+ public void reconcileApps(@NonNull Computer snapshot, String volumeUuid) {
+ List<String> absoluteCodePaths = collectAbsoluteCodePaths(snapshot);
List<File> filesToDelete = null;
final File[] files = FileUtils.listFilesOrEmpty(
@@ -345,10 +346,10 @@
}
}
- private List<String> collectAbsoluteCodePaths() {
+ private List<String> collectAbsoluteCodePaths(@NonNull Computer snapshot) {
List<String> codePaths = new ArrayList<>();
final ArrayMap<String, ? extends PackageStateInternal> packageStates =
- mPm.getPackageStates();
+ snapshot.getPackageStates();
final int packageCount = packageStates.size();
for (int i = 0; i < packageCount; i++) {
final PackageStateInternal ps = packageStates.valueAt(i);
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 3ef5599..588dfaf 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -100,14 +100,14 @@
* @return The names of failed packages.
*/
@Nullable
- String[] setPackagesSuspended(@NonNull Computer computer, @Nullable String[] packageNames,
+ 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) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !isSuspendAllowedForUser(userId, callingUid)) {
+ if (suspended && !isSuspendAllowedForUser(snapshot, userId, callingUid)) {
Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
@@ -123,7 +123,7 @@
ArraySet<String> modifiedPackages = new ArraySet<>();
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(computer, packageNames, userId, callingUid) : null;
+ ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid) : null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
if (callingPackage.equals(packageName)) {
@@ -133,9 +133,9 @@
continue;
}
final PackageStateInternal packageState =
- computer.getPackageStateInternal(packageName);
+ snapshot.getPackageStateInternal(packageName);
if (packageState == null
- || computer.shouldFilterApplication(packageState, callingUid, userId)) {
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -191,9 +191,11 @@
}
});
+ final Computer newSnapshot = mPm.snapshotComputer();
+
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(new String[0]);
- sendPackagesSuspendedForUser(
+ sendPackagesSuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
changedPackages, changedUids.toArray(), userId);
@@ -202,7 +204,7 @@
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!modifiedPackages.isEmpty()) {
- sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
+ sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
modifiedPackages.toArray(new String[0]), modifiedUids.toArray(), userId);
}
return unmodifiablePackages.toArray(new String[0]);
@@ -217,14 +219,14 @@
* @return The names of packages which are Unsuspendable.
*/
@NonNull
- String[] getUnsuspendablePackagesForUser(@NonNull Computer computer,
+ String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
@NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
- if (!isSuspendAllowedForUser(userId, callingUid)) {
+ if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(computer, packageNames, userId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -232,7 +234,7 @@
continue;
}
final PackageStateInternal packageState =
- computer.getPackageStateFiltered(packageNames[i], callingUid, userId);
+ snapshot.getPackageStateFiltered(packageNames[i], callingUid, userId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -250,8 +252,9 @@
* @return The app extras of the suspended package.
*/
@Nullable
- Bundle getSuspendedPackageAppExtras(@NonNull String packageName, int userId, int callingUid) {
- final PackageStateInternal ps = mPm.getPackageStateInternal(packageName, callingUid);
+ Bundle getSuspendedPackageAppExtras(@NonNull Computer snapshot, @NonNull String packageName,
+ int userId, int callingUid) {
+ final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName, callingUid);
if (ps == null) {
return null;
}
@@ -329,12 +332,14 @@
}
});
+ final Computer newSnapshot = mPm.snapshotComputer();
+
mPm.scheduleWritePackageRestrictions(userId);
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
- sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_UNSUSPENDED,
+ sendPackagesSuspendedForUser(newSnapshot, Intent.ACTION_PACKAGES_UNSUSPENDED,
packageArray, unsuspendedUids.toArray(), userId);
}
}
@@ -348,10 +353,10 @@
* @return The launcher extras.
*/
@Nullable
- Bundle getSuspendedPackageLauncherExtras(@NonNull String packageName, int userId,
- int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
- packageName, callingUid);
+ Bundle getSuspendedPackageLauncherExtras(@NonNull Computer snapshot,
+ @NonNull String packageName, int userId, int callingUid) {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName, callingUid);
if (packageState == null) {
return null;
}
@@ -376,9 +381,10 @@
* @param callingUid The caller's uid.
* @return {@code true}, if the given package is suspended.
*/
- boolean isPackageSuspended(@NonNull String packageName, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
- packageName, callingUid);
+ boolean isPackageSuspended(@NonNull Computer snapshot, @NonNull String packageName, int userId,
+ int callingUid) {
+ final PackageStateInternal packageState =
+ snapshot.getPackageStateInternal(packageName, callingUid);
return packageState != null && packageState.getUserStateOrDefault(userId)
.isSuspended();
}
@@ -392,8 +398,9 @@
* @return The name of suspending package.
*/
@Nullable
- String getSuspendingPackage(@NonNull String suspendedPackage, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
+ String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ int userId, int callingUid) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
if (packageState == null) {
return null;
@@ -424,9 +431,10 @@
* @return The dialog info.
*/
@Nullable
- SuspendDialogInfo getSuspendedDialogInfo(@NonNull String suspendedPackage,
- @NonNull String suspendingPackage, int userId, int callingUid) {
- final PackageStateInternal packageState = mPm.getPackageStateInternal(
+ SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
+ @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
+ int callingUid) {
+ final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
if (packageState == null) {
return null;
@@ -454,9 +462,9 @@
* @param callingUid The caller's uid.
* @return {@code true} if the user is allowed to suspend packages by the caller.
*/
- boolean isSuspendAllowedForUser(int userId, int callingUid) {
+ boolean isSuspendAllowedForUser(@NonNull Computer snapshot, int userId, int callingUid) {
final UserManagerService userManager = mInjector.getUserManagerService();
- return isCallerDeviceOrProfileOwner(userId, callingUid)
+ return isCallerDeviceOrProfileOwner(snapshot, userId, callingUid)
|| (!userManager.hasUserRestriction(UserManager.DISALLOW_APPS_CONTROL, userId)
&& !userManager.hasUserRestriction(UserManager.DISALLOW_UNINSTALL_APPS, userId));
}
@@ -471,21 +479,23 @@
* @return An array containing results of the checks
*/
@NonNull
- boolean[] canSuspendPackageForUser(@NonNull Computer computer, @NonNull String[] packageNames,
+ boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
int userId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner = isCallerDeviceOrProfileOwner(userId, callingUid);
+ final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, 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 requiredInstallerPackage = getKnownPackageName(PACKAGE_INSTALLER, userId);
+ final String requiredInstallerPackage =
+ getKnownPackageName(snapshot, PACKAGE_INSTALLER, userId);
final String requiredUninstallerPackage =
- getKnownPackageName(PACKAGE_UNINSTALLER, userId);
- final String requiredVerifierPackage = getKnownPackageName(PACKAGE_VERIFIER, userId);
+ getKnownPackageName(snapshot, PACKAGE_UNINSTALLER, userId);
+ final String requiredVerifierPackage =
+ getKnownPackageName(snapshot, PACKAGE_VERIFIER, userId);
final String requiredPermissionControllerPackage =
- getKnownPackageName(PACKAGE_PERMISSION_CONTROLLER, userId);
+ getKnownPackageName(snapshot, PACKAGE_PERMISSION_CONTROLLER, userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
@@ -530,7 +540,7 @@
+ "\": protected package");
continue;
}
- if (!isCallerOwner && computer.getBlockUninstall(userId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -539,7 +549,7 @@
// Cannot suspend static shared libs as they are considered
// a part of the using app (emulating static linking). Also
// static libs are installed always on internal storage.
- PackageStateInternal packageState = computer.getPackageStateInternal(packageName);
+ PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
// Cannot suspend SDK libs as they are controlled by SDK manager.
@@ -580,8 +590,8 @@
* @param userId The user where packages reside.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- void sendPackagesSuspendedForUser(@NonNull String intent, @NonNull String[] pkgList,
- @NonNull int[] uidList, int userId) {
+ void sendPackagesSuspendedForUser(@NonNull Computer snapshot, @NonNull String intent,
+ @NonNull String[] pkgList, @NonNull int[] uidList, int userId) {
final List<List<String>> pkgsToSend = new ArrayList(pkgList.length);
final List<IntArray> uidsToSend = new ArrayList(pkgList.length);
final List<SparseArray<int[]>> allowListsToSend = new ArrayList(pkgList.length);
@@ -592,8 +602,8 @@
final String pkgName = pkgList[i];
final int uid = uidList[i];
SparseArray<int[]> allowList = mInjector.getAppsFilter().getVisibilityAllowList(
- mPm.getPackageStateInternal(pkgName, SYSTEM_UID),
- userIds, mPm.getPackageStates());
+ snapshot.getPackageStateInternal(pkgName, SYSTEM_UID),
+ userIds, snapshot.getPackageStates());
if (allowList == null) {
allowList = new SparseArray<>(0);
}
@@ -628,19 +638,22 @@
}
}
- private String getKnownPackageName(@KnownPackage int knownPackage, int userId) {
- final String[] knownPackages = mPm.getKnownPackageNamesInternal(knownPackage, userId);
+ private String getKnownPackageName(@NonNull Computer snapshot, @KnownPackage int knownPackage,
+ int userId) {
+ final String[] knownPackages =
+ mPm.getKnownPackageNamesInternal(snapshot, knownPackage, userId);
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(int userId, int callingUid) {
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
+ int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- return callingUid == mPm.getPackageUidInternal(
- ownerPackage, 0, userId, callingUid);
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
+ callingUid);
}
return false;
}
@@ -659,9 +672,10 @@
return;
}
final int[] targetUserIds = new int[] {userId};
+ final Computer snapshot = mPm.snapshotComputer();
for (String packageName : affectedPackages) {
final Bundle appExtras = suspended
- ? getSuspendedPackageAppExtras(packageName, userId, SYSTEM_UID)
+ ? getSuspendedPackageAppExtras(snapshot, packageName, userId, SYSTEM_UID)
: null;
final Bundle intentExtras;
if (appExtras != null) {
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 5047690..95482d7 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -118,8 +118,11 @@
flags | StorageManager.FLAG_STORAGE_DE, false);
} else {
try {
- Log.e(TAG, "prepareUserData failed", e);
- RecoverySystem.rebootPromptAndWipeUserData(mContext, "prepareUserData failed");
+ Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
+ if (userId == UserHandle.USER_SYSTEM) {
+ RecoverySystem.rebootPromptAndWipeUserData(mContext,
+ "prepareUserData failed for system user");
+ }
} catch (IOException e2) {
throw new RuntimeException("error rebooting into recovery", e2);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index eb2de60..0e6d5e5 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -312,4 +312,12 @@
*/
public abstract void setDefaultCrossProfileIntentFilters(
@UserIdInt int parentUserId, @UserIdInt int profileUserId);
+
+ /**
+ * Returns {@code true} if the system should ignore errors when preparing
+ * the storage directories for the user with ID {@code userId}. This will
+ * return {@code false} for all new users; it will only return {@code true}
+ * for users that already existed on-disk from an older version of Android.
+ */
+ public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 006e82b..eae7658 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -211,6 +211,8 @@
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
"lastRequestQuietModeEnabledCall";
+ private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
+ "ignorePrepareStorageErrors";
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -320,6 +322,14 @@
private long mLastRequestQuietModeEnabledMillis;
+ /**
+ * {@code true} if the system should ignore errors when preparing the
+ * storage directories for this user. This is {@code false} for all new
+ * users; it will only be {@code true} for users that already existed
+ * on-disk from an older version of Android.
+ */
+ private boolean mIgnorePrepareStorageErrors;
+
void setLastRequestQuietModeEnabledMillis(long millis) {
mLastRequestQuietModeEnabledMillis = millis;
}
@@ -328,6 +338,25 @@
return mLastRequestQuietModeEnabledMillis;
}
+ boolean getIgnorePrepareStorageErrors() {
+ return mIgnorePrepareStorageErrors;
+ }
+
+ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API.
+ void setIgnorePrepareStorageErrors() {
+ // This method won't be called for new users. But to fully rule out
+ // the possibility of mIgnorePrepareStorageErrors ever being true
+ // for any user on any device that launched with T or later, we also
+ // explicitly check that DEVICE_INITIAL_SDK_INT is below T before
+ // honoring the request to set mIgnorePrepareStorageErrors to true.
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+ mIgnorePrepareStorageErrors = true;
+ return;
+ }
+ Slog.w(LOG_TAG, "Not setting mIgnorePrepareStorageErrors to true"
+ + " since this is a new device");
+ }
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -1564,13 +1593,13 @@
}
@Override
- public boolean isCredentialSharedWithParent(@UserIdInt int userId) {
+ public boolean isCredentialSharableWithParent(@UserIdInt int userId) {
checkManageOrInteractPermissionIfCallerInOtherProfileGroup(userId,
- "isCredentialSharedWithParent");
+ "isCredentialSharableWithParent");
synchronized (mUsersLock) {
UserTypeDetails userTypeDetails = getUserTypeDetailsNoChecks(userId);
return userTypeDetails != null && userTypeDetails.isProfile()
- && userTypeDetails.isCredentialSharedWithParent();
+ && userTypeDetails.isCredentialSharableWithParent();
}
}
@@ -3408,6 +3437,10 @@
serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
}
+ serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+ serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
+ serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -3517,6 +3550,7 @@
Bundle legacyLocalRestrictions = null;
RestrictionsSet localRestrictions = null;
Bundle globalRestrictions = null;
+ boolean ignorePrepareStorageErrors = true; // default is true for old users
final TypedXmlPullParser parser = Xml.resolvePullParser(is);
int type;
@@ -3595,6 +3629,11 @@
if (type == XmlPullParser.TEXT) {
lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
}
+ } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
+ }
}
}
}
@@ -3622,6 +3661,9 @@
userData.persistSeedData = persistSeedData;
userData.seedAccountOptions = seedAccountOptions;
userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+ if (ignorePrepareStorageErrors) {
+ userData.setIgnorePrepareStorageErrors();
+ }
synchronized (mRestrictionsLock) {
if (baseRestrictions != null) {
@@ -4106,11 +4148,11 @@
continue;
}
if (filter.direction == DefaultCrossProfileIntentFilter.Direction.TO_PARENT) {
- mPm.addCrossProfileIntentFilter(
+ mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
filter.filter, mContext.getOpPackageName(), profileUserId, parentUserId,
filter.flags);
} else {
- mPm.addCrossProfileIntentFilter(
+ mPm.addCrossProfileIntentFilter(mPm.snapshotComputer(),
filter.filter, mContext.getOpPackageName(), parentUserId, profileUserId,
filter.flags);
}
@@ -5732,6 +5774,9 @@
pw.println();
}
}
+
+ pw.println(" Ignore errors preparing storage: "
+ + userData.getIgnorePrepareStorageErrors());
}
private static void dumpTimeAgo(PrintWriter pw, StringBuilder sb, long nowTime, long time) {
@@ -6135,6 +6180,14 @@
UserManagerService.this.setDefaultCrossProfileIntentFilters(
profileUserId, userTypeDetails, restrictions, parentUserId);
}
+
+ @Override
+ public boolean shouldIgnorePrepareStorageErrors(int userId) {
+ synchronized (mUsersLock) {
+ UserData userData = mUsers.get(userId);
+ return userData != null && userData.getIgnorePrepareStorageErrors();
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 2f5e238..4aad1a7 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -161,7 +161,7 @@
*
* <p> Default value is false
*/
- private final boolean mIsCredentialSharedWithParent;
+ private final boolean mIsCredentialSharableWithParent;
private UserTypeDetails(@NonNull String name, boolean enabled, int maxAllowed,
@UserInfoFlag int baseType, @UserInfoFlag int defaultUserInfoPropertyFlags, int label,
@@ -174,7 +174,7 @@
@Nullable Bundle defaultSecureSettings,
@Nullable List<DefaultCrossProfileIntentFilter> defaultCrossProfileIntentFilters,
boolean isMediaSharedWithParent,
- boolean isCredentialSharedWithParent) {
+ boolean isCredentialSharableWithParent) {
this.mName = name;
this.mEnabled = enabled;
this.mMaxAllowed = maxAllowed;
@@ -194,7 +194,7 @@
this.mBadgeColors = badgeColors;
this.mDarkThemeBadgeColors = darkThemeBadgeColors;
this.mIsMediaSharedWithParent = isMediaSharedWithParent;
- this.mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+ this.mIsCredentialSharableWithParent = isCredentialSharableWithParent;
}
/**
@@ -323,8 +323,8 @@
* Returns true if the user has shared encryption credential with parent user or
* false otherwise.
*/
- public boolean isCredentialSharedWithParent() {
- return mIsCredentialSharedWithParent;
+ public boolean isCredentialSharableWithParent() {
+ return mIsCredentialSharableWithParent;
}
/** Returns a {@link Bundle} representing the default user restrictions. */
@@ -419,7 +419,7 @@
private @DrawableRes int mBadgePlain = Resources.ID_NULL;
private @DrawableRes int mBadgeNoBackground = Resources.ID_NULL;
private boolean mIsMediaSharedWithParent = false;
- private boolean mIsCredentialSharedWithParent = false;
+ private boolean mIsCredentialSharableWithParent = false;
public Builder setName(String name) {
mName = name;
@@ -521,10 +521,10 @@
/**
* Sets shared media property for the user.
- * @param isCredentialSharedWithParent the value to be set, true or false
+ * @param isCredentialSharableWithParent the value to be set, true or false
*/
- public Builder setIsCredentialSharedWithParent(boolean isCredentialSharedWithParent) {
- mIsCredentialSharedWithParent = isCredentialSharedWithParent;
+ public Builder setIsCredentialSharableWithParent(boolean isCredentialSharableWithParent) {
+ mIsCredentialSharableWithParent = isCredentialSharableWithParent;
return this;
}
@@ -571,7 +571,7 @@
mDefaultSecureSettings,
mDefaultCrossProfileIntentFilters,
mIsMediaSharedWithParent,
- mIsCredentialSharedWithParent);
+ mIsCredentialSharableWithParent);
}
private boolean hasBadge() {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 1e3b67c..cb18c6d 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -122,7 +122,7 @@
.setLabel(0)
.setDefaultRestrictions(null)
.setIsMediaSharedWithParent(true)
- .setIsCredentialSharedWithParent(true);
+ .setIsCredentialSharableWithParent(true);
}
/**
@@ -154,7 +154,7 @@
.setDefaultRestrictions(getDefaultManagedProfileRestrictions())
.setDefaultSecureSettings(getDefaultManagedProfileSecureSettings())
.setDefaultCrossProfileIntentFilters(getDefaultManagedCrossProfileIntentFilter())
- .setIsCredentialSharedWithParent(true);
+ .setIsCredentialSharableWithParent(true);
}
/**
diff --git a/services/core/java/com/android/server/pm/VerificationParams.java b/services/core/java/com/android/server/pm/VerificationParams.java
index bc93611..7423bf6 100644
--- a/services/core/java/com/android/server/pm/VerificationParams.java
+++ b/services/core/java/com/android/server/pm/VerificationParams.java
@@ -72,6 +72,7 @@
import android.util.Slog;
import com.android.server.DeviceIdleInternal;
+import com.android.server.sdksandbox.SdkSandboxManagerLocal;
import java.io.File;
import java.util.ArrayList;
@@ -441,9 +442,22 @@
final long verificationTimeout = VerificationUtils.getVerificationTimeout(mPm.mContext,
streaming);
- final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
+ List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
receivers.getList(), verificationState);
+ // Add broadcastReceiver Component to verify Sdk before run in Sdk sandbox.
+ if (pkgLite.isSdkLibrary) {
+ if (sufficientVerifiers == null) {
+ sufficientVerifiers = new ArrayList<>();
+ }
+ ComponentName sdkSandboxComponentName = new ComponentName("android",
+ SdkSandboxManagerLocal.VERIFIER_RECEIVER);
+ sufficientVerifiers.add(sdkSandboxComponentName);
+
+ // Add uid of system_server the same uid for SdkSandboxManagerService
+ verificationState.addSufficientVerifier(Process.myUid());
+ }
+
DeviceIdleInternal idleController =
mPm.mInjector.getLocalService(DeviceIdleInternal.class);
final BroadcastOptions options = BroadcastOptions.makeBasic();
diff --git a/services/core/java/com/android/server/pm/WatchedIntentFilter.java b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
index 30f276e..5d7a2a3 100644
--- a/services/core/java/com/android/server/pm/WatchedIntentFilter.java
+++ b/services/core/java/com/android/server/pm/WatchedIntentFilter.java
@@ -84,7 +84,7 @@
}
// Convert an {@link IntentFilter} to a {@link WatchedIntentFilter}
- protected WatchedIntentFilter(IntentFilter f) {
+ public WatchedIntentFilter(IntentFilter f) {
mFilter = new IntentFilter(f);
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index e28a6ea..7e4da94 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -31,13 +31,13 @@
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.dex.PackageOptimizationInfo;
-import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.system.Os;
@@ -55,6 +55,7 @@
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.PackageManagerServiceCompilerMapping;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -92,7 +93,7 @@
private static final String BOOT_IMAGE_PROFILE_NAME = "android.prof";
private final Context mContext;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final Object mInstallLock;
@GuardedBy("mInstallLock")
private final Installer mInstaller;
@@ -103,10 +104,9 @@
verifyTronLoggingConstants();
}
- public ArtManagerService(Context context, IPackageManager pm, Installer installer,
+ public ArtManagerService(Context context, Installer installer,
Object installLock) {
mContext = context;
- mPackageManager = pm;
mInstaller = installer;
mInstallLock = installLock;
mHandler = new Handler(BackgroundThread.getHandler().getLooper());
@@ -114,6 +114,15 @@
LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
// Callers always need this permission
mContext.enforceCallingOrSelfPermission(
@@ -157,7 +166,7 @@
}
PackageInfo info = null;
try {
- info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ info = getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
} catch (RemoteException ignored) {
// Should not happen.
}
@@ -221,7 +230,7 @@
// TODO(calin): consider adding an API to PMS which can retrieve the
// PackageParser.Package.
- info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+ info = getPackageManager().getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
} catch (RemoteException ignored) {
// Should not happen.
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 5371454..17109e9 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -23,6 +23,8 @@
import static java.util.function.Function.identity;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -33,6 +35,7 @@
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -109,7 +112,7 @@
// record class loaders or ISAs.)
private final DynamicCodeLogger mDynamicCodeLogger;
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final PackageDexOptimizer mPackageDexOptimizer;
private final Object mInstallLock;
@GuardedBy("mInstallLock")
@@ -128,16 +131,22 @@
private static int DEX_SEARCH_FOUND_SPLIT = 2; // dex file is a split apk
private static int DEX_SEARCH_FOUND_SECONDARY = 3; // dex file is a secondary dex
- public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
- Installer installer, Object installLock) {
+ public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+ Object installLock) {
+ this(context, pdo, installer, installLock, null);
+ }
+
+ @VisibleForTesting
+ public DexManager(Context context, PackageDexOptimizer pdo, Installer installer,
+ Object installLock, @Nullable IPackageManager packageManager) {
mContext = context;
mPackageCodeLocationsCache = new HashMap<>();
mPackageDexUsage = new PackageDexUsage();
- mPackageManager = pms;
mPackageDexOptimizer = pdo;
mInstaller = installer;
mInstallLock = installLock;
- mDynamicCodeLogger = new DynamicCodeLogger(pms, installer);
+ mDynamicCodeLogger = new DynamicCodeLogger(installer);
+ mPackageManager = packageManager;
// This is currently checked to handle tests that pass in a null context.
// TODO(b/174783329): Modify the tests to pass in a mocked Context, PowerManager,
@@ -157,6 +166,15 @@
}
}
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
+ }
+
public DynamicCodeLogger getDynamicCodeLogger() {
return mDynamicCodeLogger;
}
@@ -529,7 +547,7 @@
PackageInfo pkg;
try {
- pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
dexUseInfo.getOwnerUserId());
} catch (RemoteException e) {
throw new AssertionError(e);
@@ -673,7 +691,7 @@
// to get back the real app uid and its storage kind. These are only used
// to perform extra validation in installd.
// TODO(calin): maybe a bit overkill.
- pkg = mPackageManager.getPackageInfo(packageName, /*flags*/0,
+ pkg = getPackageManager().getPackageInfo(packageName, /*flags*/0,
dexUseInfo.getOwnerUserId());
} catch (RemoteException ignore) {
// Can't happen, DexManager is local.
diff --git a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
index 75b4e38..9b94e99 100644
--- a/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DynamicCodeLogger.java
@@ -19,11 +19,13 @@
import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_DEX;
import static com.android.server.pm.dex.PackageDynamicCodeLoading.FILE_TYPE_NATIVE;
+import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.os.FileUtils;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.EventLog;
@@ -58,20 +60,30 @@
private static final String DCL_DEX_SUBTAG = "dcl";
private static final String DCL_NATIVE_SUBTAG = "dcln";
- private final IPackageManager mPackageManager;
+ private IPackageManager mPackageManager;
private final PackageDynamicCodeLoading mPackageDynamicCodeLoading;
private final Installer mInstaller;
- DynamicCodeLogger(IPackageManager pms, Installer installer) {
- this(pms, installer, new PackageDynamicCodeLoading());
+ DynamicCodeLogger(Installer installer) {
+ mInstaller = installer;
+ mPackageDynamicCodeLoading = new PackageDynamicCodeLoading();
}
@VisibleForTesting
- DynamicCodeLogger(IPackageManager pms, Installer installer,
- PackageDynamicCodeLoading packageDynamicCodeLoading) {
- mPackageManager = pms;
- mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+ DynamicCodeLogger(@NonNull IPackageManager packageManager, @NonNull Installer installer,
+ @NonNull PackageDynamicCodeLoading packageDynamicCodeLoading) {
+ mPackageManager = packageManager;
mInstaller = installer;
+ mPackageDynamicCodeLoading = packageDynamicCodeLoading;
+ }
+
+ @NonNull
+ private IPackageManager getPackageManager() {
+ if (mPackageManager == null) {
+ mPackageManager = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ }
+ return mPackageManager;
}
public Set<String> getAllPackagesWithDynamicCodeLoading() {
@@ -104,7 +116,7 @@
try {
PackageInfo ownerInfo =
- mPackageManager.getPackageInfo(packageName, /*flags*/ 0, userId);
+ getPackageManager().getPackageInfo(packageName, /*flags*/ 0, userId);
appInfo = ownerInfo == null ? null : ownerInfo.applicationInfo;
} catch (RemoteException ignored) {
// Can't happen, we're local.
@@ -167,7 +179,7 @@
loadingUid = appInfo.uid;
} else {
try {
- loadingUid = mPackageManager.getPackageUid(loadingPackageName, /*flags*/ 0,
+ loadingUid = getPackageManager().getPackageUid(loadingPackageName, /*flags*/ 0,
userId);
} catch (RemoteException ignored) {
// Can't happen, we're local.
@@ -223,7 +235,7 @@
public void recordNative(int loadingUid, String path) {
String[] packages;
try {
- packages = mPackageManager.getPackagesForUid(loadingUid);
+ packages = getPackageManager().getPackagesForUid(loadingUid);
if (packages == null || packages.length == 0) {
return;
}
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 63469cb..8d1bcfc 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -122,6 +122,12 @@
info.isStub = pkg.isStub();
info.coreApp = pkg.isCoreApp();
+ if (pkgSetting != null && !pkgSetting.hasSharedUser()) {
+ // It is possible that this shared UID app has left
+ info.sharedUserId = null;
+ info.sharedUserLabel = 0;
+ }
+
if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
final int N = pkg.getActivities().size();
if (N > 0) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index f6f9faf..cbba346 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -287,9 +287,6 @@
ParsingPackage setInstallLocation(int installLocation);
- /** @see R#styleable.AndroidManifest_inheritKeyStoreKeys */
- ParsingPackage setInheritKeyStoreKeys(boolean inheritKeyStoreKeys);
-
/** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
ParsingPackage setLeavingSharedUid(boolean leavingSharedUid);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 6767027..1484df8 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -494,7 +494,6 @@
ATTRIBUTIONS_ARE_USER_VISIBLE,
RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED,
SDK_LIBRARY,
- INHERIT_KEYSTORE_KEYS,
})
public @interface Values {}
private static final long EXTERNAL_STORAGE = 1L;
@@ -547,9 +546,8 @@
private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47;
private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
private static final long SDK_LIBRARY = 1L << 49;
- private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
- private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
- private static final long LEAVING_SHARED_UID = 1L << 52;
+ private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 50;
+ private static final long LEAVING_SHARED_UID = 1L << 51;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2394,11 +2392,6 @@
}
@Override
- public boolean shouldInheritKeyStoreKeys() {
- return getBoolean(Booleans.INHERIT_KEYSTORE_KEYS);
- }
-
- @Override
public boolean isOnBackInvokedCallbackEnabled() {
return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK);
}
@@ -2552,11 +2545,6 @@
}
@Override
- public ParsingPackageImpl setInheritKeyStoreKeys(boolean value) {
- return setBoolean(Booleans.INHERIT_KEYSTORE_KEYS, value);
- }
-
- @Override
public ParsingPackageImpl setLeavingSharedUid(boolean value) {
return setBoolean(Booleans.LEAVING_SHARED_UID, value);
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 50033f6..20b1ed8 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -352,11 +352,6 @@
int getLocaleConfigRes();
/**
- * @see R.styleable#AndroidManifest_inheritKeyStoreKeys
- */
- boolean shouldInheritKeyStoreKeys();
-
- /**
* @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
*/
boolean isOnBackInvokedCallbackEnabled();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 3eaca9d..112b9e0 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -894,9 +894,7 @@
.setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
- .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0)
- .setInheritKeyStoreKeys(bool(false,
- R.styleable.AndroidManifest_inheritKeyStoreKeys, sa));
+ .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
boolean foundApp = false;
final int depth = parser.getDepth();
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index ee0e5ba..e3dcfd0 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -247,6 +247,8 @@
if (autoGrantPermissions != null && callingPkg != null) {
// Need to own the Uri to call in with permissions to grant.
enforceOwner(callingPkg, uri, userId);
+ // b/208232850: Needs to verify caller before granting slice access
+ verifyCaller(callingPkg);
for (String perm : autoGrantPermissions) {
if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
diff --git a/services/core/java/com/android/server/trust/TEST_MAPPING b/services/core/java/com/android/server/trust/TEST_MAPPING
new file mode 100644
index 0000000..be8ed67
--- /dev/null
+++ b/services/core/java/com/android/server/trust/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+ }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 58407cf..e12426b 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -60,8 +60,6 @@
static final float RAMP_OFF_AMPLITUDE_MIN = 1e-3f;
static final List<Step> EMPTY_STEP_LIST = new ArrayList<>();
- private final Object mLock = new Object();
-
// Used within steps.
public final VibrationSettings vibrationSettings;
public final DeviceVibrationEffectAdapter deviceEffectAdapter;
@@ -74,6 +72,11 @@
private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>();
// Signalling fields.
+ // Note that vibrator callback signals may happen inside vibrator HAL calls made by the
+ // VibrationThread, or on an external executor, so this lock should not be held for anything
+ // other than updating signalling state - particularly not during HAL calls or when invoking
+ // other callbacks that may trigger calls into the thread.
+ private final Object mLock = new Object();
@GuardedBy("mLock")
private final IntArray mSignalVibratorsComplete;
@GuardedBy("mLock")
@@ -334,9 +337,9 @@
* The state update is recorded for processing on the main execution thread (VibrationThread).
*/
public void notifyVibratorComplete(int vibratorId) {
- if (Build.IS_DEBUGGABLE) {
- expectIsVibrationThread(false);
- }
+ // HAL callbacks may be triggered directly within HAL calls, so these notifications
+ // could be on the VibrationThread as it calls the HAL, or some other executor later.
+ // Therefore no thread assertion is made here.
if (DEBUG) {
Slog.d(TAG, "Vibration complete reported by vibrator " + vibratorId);
@@ -356,9 +359,9 @@
* (VibrationThread).
*/
public void notifySyncedVibrationComplete() {
- if (Build.IS_DEBUGGABLE) {
- expectIsVibrationThread(false);
- }
+ // HAL callbacks may be triggered directly within HAL calls, so these notifications
+ // could be on the VibrationThread as it calls the HAL, or some other executor later.
+ // Therefore no thread assertion is made here.
if (DEBUG) {
Slog.d(TAG, "Synced vibration complete reported by vibrator manager");
@@ -394,7 +397,7 @@
int[] vibratorsToProcess = null;
boolean doCancel = false;
boolean doCancelImmediate = false;
- // Swap out the queue of completions to process.
+ // Collect signals to process, but don't keep the lock while processing them.
synchronized (mLock) {
if (mSignalCancelImmediate) {
if (mCancelledImmediately) {
@@ -407,6 +410,7 @@
doCancel = true;
}
if (!doCancelImmediate && mSignalVibratorsComplete.size() > 0) {
+ // Swap out the queue of completions to process.
vibratorsToProcess = mSignalVibratorsComplete.toArray(); // makes a copy
mSignalVibratorsComplete.clear();
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 205ea62..cecc5c0 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -22,6 +22,7 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.Trace;
import android.os.WorkSource;
import android.util.Slog;
@@ -176,7 +177,7 @@
* @return true if the vibration completed, or false if waiting timed out.
*/
public boolean waitForThreadIdle(long maxWaitMillis) {
- long now = System.currentTimeMillis();
+ long now = SystemClock.elapsedRealtime();
long deadline = now + maxWaitMillis;
synchronized (mLock) {
while (true) {
@@ -191,7 +192,7 @@
} catch (InterruptedException e) {
Slog.w(TAG, "VibrationThread interrupted waiting to stop, continuing");
}
- now = System.currentTimeMillis();
+ now = SystemClock.elapsedRealtime();
}
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index a4a200d..543e44c 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -757,12 +757,12 @@
}
@Override
- public void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ public void setShouldDockBigOverlays(IBinder token, boolean shouldDockBigOverlays) {
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- r.setPreferDockBigOverlays(preferDockBigOverlays);
+ r.setShouldDockBigOverlays(shouldDockBigOverlays);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 1c93abd..677babe 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -534,7 +534,7 @@
// activity can enter picture in picture while pausing (only when switching to another task)
PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build();
// The PiP params used when deferring the entering of picture-in-picture.
- boolean preferDockBigOverlays;
+ boolean shouldDockBigOverlays;
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last launch of this activity
ComponentName requestedVrComponent; // the requested component for handling VR mode.
@@ -2042,7 +2042,7 @@
mLetterboxUiController = new LetterboxUiController(mWmService, this);
mCameraCompatControlEnabled = mWmService.mContext.getResources()
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
- preferDockBigOverlays = mWmService.mContext.getResources()
+ shouldDockBigOverlays = mWmService.mContext.getResources()
.getBoolean(R.bool.config_dockBigOverlayWindows);
if (_createTime > 0) {
@@ -6767,7 +6767,8 @@
}
// Choose the default behavior for Launcher and SystemUI when the SplashScreen style is
// not specified in the ActivityOptions.
- if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME) {
+ if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
+ || launchedFromUid == Process.SHELL_UID) {
return false;
} else if (mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEMUI) {
return true;
@@ -6787,7 +6788,8 @@
// solid color splash screen.
// Need to check sourceRecord before in case this activity is launched from service.
return !startActivity || !(mLaunchSourceType == LAUNCH_SOURCE_TYPE_SYSTEM
- || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME);
+ || mLaunchSourceType == LAUNCH_SOURCE_TYPE_HOME
+ || launchedFromUid == Process.SHELL_UID);
}
private int getSplashscreenTheme(ActivityOptions options) {
@@ -9573,9 +9575,9 @@
getTask().getRootTask().onPictureInPictureParamsChanged();
}
- void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
- this.preferDockBigOverlays = preferDockBigOverlays;
- getTask().getRootTask().onPreferDockBigOverlaysChanged();
+ void setShouldDockBigOverlays(boolean shouldDockBigOverlays) {
+ this.shouldDockBigOverlays = shouldDockBigOverlays;
+ getTask().getRootTask().onShouldDockBigOverlaysChanged();
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ac121a1..7d2dfa0 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -2023,22 +2023,12 @@
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
@NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
final Task hostTask = taskFragment.getTask();
- if (hostTask == null) {
+ // Not allowed embedding a separate task or without host task.
+ if (hostTask == null || newTask || targetTask != hostTask) {
return false;
}
- // Allowing the embedding if the task is owned by system.
- final int hostUid = hostTask.effectiveUid;
- if (UserHandle.getAppId(hostUid) == Process.SYSTEM_UID) {
- return true;
- }
-
- if (!taskFragment.isAllowedToEmbedActivity(starting)) {
- return false;
- }
-
- // Not allowed embedding task.
- return !newTask && (targetTask == null || targetTask == hostTask);
+ return taskFragment.isAllowedToEmbedActivity(starting);
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 6d8b3b1d..b5312c4 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -205,8 +205,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
@@ -4300,11 +4298,6 @@
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
-
- final Message m = PooledLambda.obtainMessage(
- ActivityTaskManagerService::sendLocaleToMountDaemonMsg, this,
- locales.get(bestLocaleIndex));
- mH.sendMessage(m);
}
mTempConfig.seq = increaseConfigurationSeqLocked();
@@ -4458,17 +4451,6 @@
Settings.System.putConfigurationForUser(resolver, config, userId);
}
- private void sendLocaleToMountDaemonMsg(Locale l) {
- try {
- IBinder service = ServiceManager.getService("mount");
- IStorageManager storageManager = IStorageManager.Stub.asInterface(service);
- Log.d(TAG, "Storing locale " + l.toLanguageTag() + " for decryption UI");
- storageManager.setField(StorageManager.SYSTEM_LOCALE_KEY, l.toLanguageTag());
- } catch (RemoteException e) {
- Log.e(TAG, "Error storing locale for decryption UI", e);
- }
- }
-
private void expireStartAsCallerTokenMsg(IBinder permissionToken) {
mStartActivitySources.remove(permissionToken);
mExpiredStartAsCallerTokens.add(permissionToken);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index c55af9b..7bf150b 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -443,6 +443,13 @@
|| !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
+ /**
+ * @return Whether the dream activity is on top of default display.
+ */
+ boolean isShowingDream() {
+ return getDisplayState(DEFAULT_DISPLAY).mShowingDream;
+ }
+
private void dismissMultiWindowModeForTaskIfNeeded(int displayId,
@Nullable Task currentTaskControllingOcclusion) {
// TODO(b/113840485): Handle docked stack for individual display.
@@ -501,6 +508,7 @@
private boolean mKeyguardGoingAway;
private boolean mDismissalRequested;
private boolean mOccluded;
+ private boolean mShowingDream;
private ActivityRecord mTopOccludesActivity;
private ActivityRecord mDismissingKeyguardActivity;
@@ -536,6 +544,7 @@
mRequestDismissKeyguard = false;
mOccluded = false;
+ mShowingDream = false;
mTopOccludesActivity = null;
mDismissingKeyguardActivity = null;
@@ -570,9 +579,9 @@
}
}
- final boolean dreaming = display.getDisplayPolicy().isShowingDreamLw() && (top != null
+ mShowingDream = display.getDisplayPolicy().isShowingDreamLw() && (top != null
&& top.getActivityType() == ACTIVITY_TYPE_DREAM);
- mOccluded = dreaming || occludedByActivity;
+ mOccluded = mShowingDream || occludedByActivity;
mRequestDismissKeyguard = lastDismissKeyguardActivity != mDismissingKeyguardActivity
&& !mOccluded
&& mDismissingKeyguardActivity != null
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 7bddb62..f3713eb 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -19,20 +19,46 @@
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
-import android.util.ArraySet;
+import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.view.Display;
import android.view.Display.Mode;
import android.view.DisplayInfo;
+import java.util.HashMap;
+
/**
* Policy to select a lower refresh rate for the display if applicable.
*/
class RefreshRatePolicy {
+ class PackageRefreshRate {
+ private final HashMap<String, RefreshRateRange> mPackages = new HashMap<>();
+
+ public void add(String s, float minRefreshRate, float maxRefreshRate) {
+ float minSupportedRefreshRate =
+ Math.max(RefreshRatePolicy.this.mMinSupportedRefreshRate, minRefreshRate);
+ float maxSupportedRefreshRate =
+ Math.min(RefreshRatePolicy.this.mMaxSupportedRefreshRate, maxRefreshRate);
+
+ mPackages.put(s,
+ new RefreshRateRange(minSupportedRefreshRate, maxSupportedRefreshRate));
+ }
+
+ public RefreshRateRange get(String s) {
+ return mPackages.get(s);
+ }
+
+ public void remove(String s) {
+ mPackages.remove(s);
+ }
+ }
+
private final Mode mLowRefreshRateMode;
- private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
+ private final PackageRefreshRate mNonHighRefreshRatePackages = new PackageRefreshRate();
private final HighRefreshRateDenylist mHighRefreshRateDenylist;
private final WindowManagerService mWmService;
+ private float mMinSupportedRefreshRate;
+ private float mMaxSupportedRefreshRate;
/**
* The following constants represent priority of the window. SF uses this information when
@@ -70,7 +96,12 @@
Mode mode = displayInfo.getDefaultMode();
float[] refreshRates = displayInfo.getDefaultRefreshRates();
float bestRefreshRate = mode.getRefreshRate();
+ mMinSupportedRefreshRate = bestRefreshRate;
+ mMaxSupportedRefreshRate = bestRefreshRate;
for (int i = refreshRates.length - 1; i >= 0; i--) {
+ mMinSupportedRefreshRate = Math.min(mMinSupportedRefreshRate, refreshRates[i]);
+ mMaxSupportedRefreshRate = Math.max(mMaxSupportedRefreshRate, refreshRates[i]);
+
if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) {
bestRefreshRate = refreshRates[i];
}
@@ -78,12 +109,13 @@
return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate);
}
- void addNonHighRefreshRatePackage(String packageName) {
- mNonHighRefreshRatePackages.add(packageName);
+ void addRefreshRateRangeForPackage(String packageName,
+ float minRefreshRate, float maxRefreshRate) {
+ mNonHighRefreshRatePackages.add(packageName, minRefreshRate, maxRefreshRate);
mWmService.requestTraversal();
}
- void removeNonHighRefreshRatePackage(String packageName) {
+ void removeRefreshRateRangeForPackage(String packageName) {
mNonHighRefreshRatePackages.remove(packageName);
mWmService.requestTraversal();
}
@@ -172,8 +204,9 @@
// If app is using Camera, we set both the min and max refresh rate to the camera's
// preferred refresh rate to make sure we don't end up with a refresh rate lower
// than the camera capture rate, which will lead to dropping camera frames.
- if (mNonHighRefreshRatePackages.contains(packageName)) {
- return mLowRefreshRateMode.getRefreshRate();
+ RefreshRateRange range = mNonHighRefreshRatePackages.get(packageName);
+ if (range != null) {
+ return range.min;
}
return 0;
@@ -192,8 +225,9 @@
final String packageName = w.getOwningPackage();
// If app is using Camera, force it to default (lower) refresh rate.
- if (mNonHighRefreshRatePackages.contains(packageName)) {
- return mLowRefreshRateMode.getRefreshRate();
+ RefreshRateRange range = mNonHighRefreshRatePackages.get(packageName);
+ if (range != null) {
+ return range.max;
}
return 0;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b3ae602..cd7ebe3 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1523,7 +1523,7 @@
mTaskSupervisor.removeTask(this, false /* killProcess */,
!REMOVE_FROM_RECENTS, reason);
}
- } else if (!mReuseTask && !mCreatedByOrganizer) {
+ } else if (!mReuseTask && shouldRemoveSelfOnLastChildRemoval()) {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
// or created by task organizer.
if (!isRootTask()) {
@@ -2036,8 +2036,10 @@
Rect outOverrideBounds = getResolvedOverrideConfiguration().windowConfiguration.getBounds();
if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
- // Use empty bounds to indicate "fill parent".
- outOverrideBounds.setEmpty();
+ if (!mCreatedByOrganizer) {
+ // Use empty bounds to indicate "fill parent".
+ outOverrideBounds.setEmpty();
+ }
// The bounds for fullscreen mode shouldn't be adjusted by minimal size. Otherwise if
// the parent or display is smaller than the size, the content may be cropped.
return;
@@ -3401,7 +3403,7 @@
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
- info.preferDockBigOverlays = getPreferDockBigOverlays();
+ info.shouldDockBigOverlays = shouldDockBigOverlays();
if (info.pictureInPictureParams != null
&& info.pictureInPictureParams.isLaunchIntoPip()
&& top.getTopMostActivity().getLastParentBeforePip() != null) {
@@ -3454,9 +3456,9 @@
? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
}
- private boolean getPreferDockBigOverlays() {
+ private boolean shouldDockBigOverlays() {
final ActivityRecord topMostActivity = getTopMostActivity();
- return topMostActivity != null && topMostActivity.preferDockBigOverlays;
+ return topMostActivity != null && topMostActivity.shouldDockBigOverlays;
}
Rect getDisplayCutoutInsets() {
@@ -4352,7 +4354,7 @@
}
}
- void onPreferDockBigOverlaysChanged() {
+ void onShouldDockBigOverlaysChanged() {
dispatchTaskInfoChangedIfNeeded(true /* force */);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3411104..597d29f 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -242,7 +242,7 @@
/** Client assigned unique token for this TaskFragment if this is created by an organizer. */
@Nullable
- private IBinder mFragmentToken;
+ private final IBinder mFragmentToken;
/**
* Whether to delay the last activity of TaskFragment being immediately removed while finishing.
@@ -2304,6 +2304,10 @@
mMinHeight = minHeight;
}
+ boolean shouldRemoveSelfOnLastChildRemoval() {
+ return !mCreatedByOrganizer || mIsRemovalRequested;
+ }
+
@Override
void removeChild(WindowContainer child) {
removeChild(child, true /* removeSelfIfPossible */);
@@ -2319,7 +2323,7 @@
mBackScreenshots.remove(r.mActivityComponent.flattenToString());
}
}
- if (removeSelfIfPossible && (!mCreatedByOrganizer || mIsRemovalRequested) && !hasChild()) {
+ if (removeSelfIfPossible && shouldRemoveSelfOnLastChildRemoval() && !hasChild()) {
removeImmediately("removeLastChild " + child);
}
}
@@ -2337,13 +2341,18 @@
return;
}
mIsRemovalRequested = true;
- forAllActivities(r -> {
- if (withTransition) {
+ // The task order may be changed by finishIfPossible() for adjusting focus if there are
+ // nested tasks, so add all activities into a list to avoid missed removals.
+ final ArrayList<ActivityRecord> removingActivities = new ArrayList<>();
+ forAllActivities((Consumer<ActivityRecord>) removingActivities::add);
+ for (int i = removingActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = removingActivities.get(i);
+ if (withTransition && r.isVisible()) {
r.finishIfPossible(reason, false /* oomAdj */);
} else {
r.destroyIfPossible(reason);
}
- });
+ }
}
void setDelayLastActivityRemoval(boolean delay) {
@@ -2383,10 +2392,18 @@
void removeImmediately() {
mIsRemovalRequested = false;
resetAdjacentTaskFragment();
+ cleanUp();
super.removeImmediately();
sendTaskFragmentVanished();
}
+ /** Called on remove to cleanup. */
+ private void cleanUp() {
+ if (mIsEmbedded) {
+ mAtmService.mWindowOrganizerController.cleanUpEmbeddedTaskFragment(this);
+ }
+ }
+
@Override
Dimmer getDimmer() {
// If the window is in an embedded TaskFragment, we want to dim at the TaskFragment.
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 19f921d..bdec49e 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -140,7 +140,7 @@
mLastSentTaskFragmentInfos.put(tf, info);
tf.mTaskFragmentAppearedSent = true;
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentAppeared callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentAppeared callback", e);
}
onTaskFragmentParentInfoChanged(organizer, tf);
}
@@ -150,7 +150,7 @@
try {
organizer.onTaskFragmentVanished(tf.getTaskFragmentInfo());
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentVanished callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentVanished callback", e);
}
tf.mTaskFragmentAppearedSent = false;
mLastSentTaskFragmentInfos.remove(tf);
@@ -175,7 +175,7 @@
organizer.onTaskFragmentInfoChanged(tf.getTaskFragmentInfo());
mLastSentTaskFragmentInfos.put(tf, info);
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentInfoChanged callback", e);
}
}
@@ -198,7 +198,7 @@
organizer.onTaskFragmentParentInfoChanged(tf.getFragmentToken(), parentConfig);
mLastSentTaskFragmentParentConfigs.put(tf, new Configuration(parentConfig));
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentParentInfoChanged callback", e);
}
}
@@ -210,7 +210,7 @@
try {
organizer.onTaskFragmentError(errorCallbackToken, exceptionBundle);
} catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskFragmentError callback", e);
+ Slog.d(TAG, "Exception sending onTaskFragmentError callback", e);
}
}
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 331f124..ff5bfbe 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -800,17 +800,24 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
- DisplayContent dc = mService.mWindowManager.mRoot
+ final DisplayContent dc = mService.mWindowManager.mRoot
.getDisplayContent(displayId);
- if (dc == null || dc.getImeTarget(IME_TARGET_LAYERING) == null) {
+ if (dc == null) {
return null;
}
+
+ final InsetsControlTarget imeLayeringTarget = dc.getImeTarget(IME_TARGET_LAYERING);
+ if (imeLayeringTarget == null || imeLayeringTarget.getWindow() == null) {
+ return null;
+ }
+
// Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
- final Task task = dc.getImeTarget(IME_TARGET_LAYERING).getWindow().getTask();
+ final Task task = imeLayeringTarget.getWindow().asTask();
if (task == null) {
return null;
}
- return task.getRootTask().mRemoteToken.toWindowContainerToken();
+
+ return task.mRemoteToken.toWindowContainerToken();
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4c23f39..7f32447 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -491,7 +491,8 @@
// Avoid commit visibility to false here, or else we will get a sudden
// "flash" / surface going invisible for a split second.
commitVisibility = false;
- } else {
+ } else if (ar.getDeferHidingClient()) {
+ // Legacy PIP-enter requires pause event with user-leaving.
mController.mAtm.mTaskSupervisor.mUserLeaving = true;
ar.getTaskFragment().startPausing(false /* uiSleeping */,
null /* resuming */, "finishTransition");
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0436233..8840cd5 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -61,7 +61,7 @@
/** Whether to use shell-transitions rotation instead of fixed-rotation. */
private static final boolean SHELL_TRANSITIONS_ROTATION =
- SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+ SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
/** The same as legacy APP_TRANSITION_TIMEOUT_MS. */
private static final int DEFAULT_TIMEOUT_MS = 5000;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 9585a4b..0a3c3f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -725,17 +725,18 @@
public abstract void hideIme(IBinder imeTargetWindowToken, int displayId);
/**
- * Tell window manager about a package that should not be running with high refresh rate
- * setting until removeNonHighRefreshRatePackage is called for the same package.
+ * Tell window manager about a package that should be running with a restricted range of
+ * refresh rate setting until removeRefreshRateRangeForPackage is called for the same package.
*
* This must not be called again for the same package.
*/
- public abstract void addNonHighRefreshRatePackage(@NonNull String packageName);
+ public abstract void addRefreshRateRangeForPackage(@NonNull String packageName,
+ float minRefreshRate, float maxRefreshRate);
/**
* Tell window manager to stop constraining refresh rate for the given package.
*/
- public abstract void removeNonHighRefreshRatePackage(@NonNull String packageName);
+ public abstract void removeRefreshRateRangeForPackage(@NonNull String packageName);
/**
* Checks if the device supports touch or faketouch.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 49d9b65..6718235 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -406,7 +406,7 @@
/**
* Use WMShell for app transition.
*/
- public static final String ENABLE_SHELL_TRANSITIONS = "persist.debug.shell_transit";
+ public static final String ENABLE_SHELL_TRANSITIONS = "persist.wm.debug.shell_transit";
/**
* @see #ENABLE_SHELL_TRANSITIONS
@@ -3233,8 +3233,8 @@
if (!checkCallingPermission(permission.CONTROL_KEYGUARD, "dismissKeyguard")) {
throw new SecurityException("Requires CONTROL_KEYGUARD permission");
}
- if (mAtmService.isDreaming()) {
- mAtmService.mTaskSupervisor.wakeUp("dismissKeyguard");
+ if (mAtmService.mKeyguardController.isShowingDream()) {
+ mAtmService.mTaskSupervisor.wakeUp("leaveDream");
}
synchronized (mGlobalLock) {
mPolicy.dismissKeyguardLw(callback, message);
@@ -7969,18 +7969,20 @@
}
@Override
- public void addNonHighRefreshRatePackage(@NonNull String packageName) {
+ public void addRefreshRateRangeForPackage(@NonNull String packageName,
+ float minRefreshRate, float maxRefreshRate) {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
- .addNonHighRefreshRatePackage(packageName));
+ .addRefreshRateRangeForPackage(
+ packageName, minRefreshRate, maxRefreshRate));
}
}
@Override
- public void removeNonHighRefreshRatePackage(@NonNull String packageName) {
+ public void removeRefreshRateRangeForPackage(@NonNull String packageName) {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(dc -> dc.getDisplayPolicy().getRefreshRatePolicy()
- .removeNonHighRefreshRatePackage(packageName));
+ .removeRefreshRateRangeForPackage(packageName));
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 81344ac..d862012 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1470,6 +1470,10 @@
return mLaunchTaskFragments.get(tfToken);
}
+ void cleanUpEmbeddedTaskFragment(TaskFragment taskFragment) {
+ mLaunchTaskFragments.remove(taskFragment.getFragmentToken());
+ }
+
static class CallerInfo {
final int mPid;
final int mUid;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 2090ab3..2f5ab0b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -307,8 +307,8 @@
public boolean mAdminCanGrantSensorsPermissions;
public boolean mPreferentialNetworkServiceEnabled =
DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT;
- public PreferentialNetworkServiceConfig mPreferentialNetworkServiceConfig =
- PreferentialNetworkServiceConfig.DEFAULT;
+ public List<PreferentialNetworkServiceConfig> mPreferentialNetworkServiceConfigs =
+ List.of(PreferentialNetworkServiceConfig.DEFAULT);
private static final boolean USB_DATA_SIGNALING_ENABLED_DEFAULT = true;
boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5388f17..3d40f48 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -133,7 +133,6 @@
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
-import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
@@ -141,6 +140,7 @@
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
import static android.provider.Telephony.Carriers.ENFORCE_MANAGED_URI;
+import static android.provider.Telephony.Carriers.INVALID_APN_ID;
import static android.security.keystore.AttestationUtils.USE_INDIVIDUAL_ATTESTATION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
@@ -3357,14 +3357,14 @@
updatePermissionPolicyCache(userId);
updateAdminCanGrantSensorsPermissionCache(userId);
- final PreferentialNetworkServiceConfig preferentialNetworkServiceConfig;
+ final List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs;
synchronized (getLockObject()) {
ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
- preferentialNetworkServiceConfig = owner != null
- ? owner.mPreferentialNetworkServiceConfig
- : PreferentialNetworkServiceConfig.DEFAULT;
+ preferentialNetworkServiceConfigs = owner != null
+ ? owner.mPreferentialNetworkServiceConfigs
+ : List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
- updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfig);
+ updateNetworkPreferenceForUser(userId, preferentialNetworkServiceConfigs);
startOwnerService(userId, "start-user");
}
@@ -3381,7 +3381,7 @@
@Override
void handleStopUser(int userId) {
- updateNetworkPreferenceForUser(userId, PreferentialNetworkServiceConfig.DEFAULT);
+ updateNetworkPreferenceForUser(userId, List.of(PreferentialNetworkServiceConfig.DEFAULT));
stopOwnerService(userId, "stop-user");
}
@@ -12258,87 +12258,50 @@
}
@Override
- public void setPreferentialNetworkServiceEnabled(boolean enabled) {
+ public void setPreferentialNetworkServiceConfigs(
+ List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
if (!mHasFeature) {
return;
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner;"
- + " only profile owner may control the preferential network service");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller),
+ "Caller is not profile owner or device owner;"
+ + " only profile owner or device owner may control the preferential"
+ + " network service");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
caller.getUserId());
- if (requiredAdmin != null
- && requiredAdmin.mPreferentialNetworkServiceEnabled != enabled) {
- requiredAdmin.mPreferentialNetworkServiceEnabled = enabled;
+ if (!requiredAdmin.mPreferentialNetworkServiceConfigs.equals(
+ preferentialNetworkServiceConfigs)) {
+ requiredAdmin.mPreferentialNetworkServiceConfigs =
+ new ArrayList<>(preferentialNetworkServiceConfigs);
saveSettingsLocked(caller.getUserId());
}
}
- updateNetworkPreferenceForUser(caller.getUserId(), enabled);
+ updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfigs);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
- .setBoolean(enabled)
+ .setBoolean(preferentialNetworkServiceConfigs
+ .stream().anyMatch(c -> c.isEnabled()))
.write();
}
@Override
- public boolean isPreferentialNetworkServiceEnabled(int userHandle) {
+ public List<PreferentialNetworkServiceConfig> getPreferentialNetworkServiceConfigs() {
if (!mHasFeature) {
- return false;
+ return List.of(PreferentialNetworkServiceConfig.DEFAULT);
}
final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner");
- synchronized (getLockObject()) {
- final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(userHandle);
- if (requiredAdmin != null) {
- return requiredAdmin.mPreferentialNetworkServiceEnabled;
- } else {
- return false;
- }
- }
- }
-
- @Override
- public void setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- if (!mHasFeature) {
- return;
- }
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner;"
- + " only profile owner may control the preferential network service");
- synchronized (getLockObject()) {
- final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(
- caller.getUserId());
- if (!requiredAdmin.mPreferentialNetworkServiceConfig.equals(
- preferentialNetworkServiceConfig)) {
- requiredAdmin.mPreferentialNetworkServiceConfig = preferentialNetworkServiceConfig;
- saveSettingsLocked(caller.getUserId());
- }
- }
- updateNetworkPreferenceForUser(caller.getUserId(), preferentialNetworkServiceConfig);
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.SET_PREFERENTIAL_NETWORK_SERVICE_ENABLED)
- .setBoolean(preferentialNetworkServiceConfig.isEnabled())
- .write();
- }
-
- @Override
- public PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig() {
- if (!mHasFeature) {
- return PreferentialNetworkServiceConfig.DEFAULT;
- }
-
- final CallerIdentity caller = getCallerIdentity();
- Preconditions.checkCallAuthorization(isProfileOwner(caller),
- "Caller is not profile owner");
+ Preconditions.checkCallAuthorization(isProfileOwner(caller)
+ || isDefaultDeviceOwner(caller),
+ "Caller is not profile owner or device owner;"
+ + " only profile owner or device owner may retrieve the preferential"
+ + " network service configurations");
synchronized (getLockObject()) {
final ActiveAdmin requiredAdmin = getProfileOwnerAdminLocked(caller.getUserId());
- return requiredAdmin.mPreferentialNetworkServiceConfig;
+ return requiredAdmin.mPreferentialNetworkServiceConfigs;
}
}
@@ -16459,7 +16422,12 @@
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in addOverrideApn");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ if (apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
if (tm != null) {
@@ -16467,7 +16435,7 @@
() -> tm.addDevicePolicyOverrideApn(mContext, apnSetting));
} else {
Slogf.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
- return Telephony.Carriers.INVALID_APN_ID;
+ return INVALID_APN_ID;
}
}
@@ -16480,7 +16448,14 @@
Objects.requireNonNull(who, "ComponentName is null");
Objects.requireNonNull(apnSetting, "ApnSetting is null in updateOverrideApn");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ ApnSetting apn = getApnSetting(apnId);
+ if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
+ && apnSetting.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
if (apnId < 0) {
return false;
@@ -16502,7 +16477,13 @@
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
- Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ ApnSetting apn = getApnSetting(apnId);
+ if (apn != null && apn.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
+ || isProfileOwner(caller));
+ } else {
+ Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller));
+ }
return removeOverrideApnUnchecked(apnId);
}
@@ -16516,6 +16497,27 @@
return numDeleted > 0;
}
+ private ApnSetting getApnSetting(int apnId) {
+ if (apnId < 0) {
+ return null;
+ }
+ ApnSetting apnSetting = null;
+ Cursor cursor = mInjector.binderWithCleanCallingIdentity(
+ () -> mContext.getContentResolver().query(
+ Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)), null, null, null,
+ Telephony.Carriers.DEFAULT_SORT_ORDER));
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ apnSetting = ApnSetting.makeApnSetting(cursor);
+ if (apnSetting != null) {
+ break;
+ }
+ }
+ cursor.close();
+ }
+ return apnSetting;
+ }
+
@Override
public List<ApnSetting> getOverrideApns(@NonNull ComponentName who) {
if (!mHasFeature || !mHasTelephonyFeature) {
@@ -18363,54 +18365,38 @@
}
private void updateNetworkPreferenceForUser(int userId,
- boolean preferentialNetworkServiceEnabled) {
+ List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs) {
if (!isManagedProfile(userId)) {
return;
}
- ProfileNetworkPreference.Builder preferenceBuilder =
- new ProfileNetworkPreference.Builder();
- if (preferentialNetworkServiceEnabled) {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
- preferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
- } else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
- }
List<ProfileNetworkPreference> preferences = new ArrayList<>();
- preferences.add(preferenceBuilder.build());
- mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getConnectivityManager().setProfileNetworkPreferences(
- UserHandle.of(userId), preferences,
- null /* executor */, null /* listener */));
- }
-
- private void updateNetworkPreferenceForUser(int userId,
- PreferentialNetworkServiceConfig preferentialNetworkServiceConfig) {
- if (!isManagedProfile(userId)) {
- return;
- }
- ProfileNetworkPreference.Builder preferenceBuilder =
- new ProfileNetworkPreference.Builder();
- if (preferentialNetworkServiceConfig.isEnabled()) {
- if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ for (PreferentialNetworkServiceConfig preferentialNetworkServiceConfig :
+ preferentialNetworkServiceConfigs) {
+ ProfileNetworkPreference.Builder preferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ if (preferentialNetworkServiceConfig.isEnabled()) {
+ if (preferentialNetworkServiceConfig.isFallbackToDefaultConnectionAllowed()) {
+ preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
+ } else {
+ preferenceBuilder.setPreference(
+ PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ }
} else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
+ preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
}
- } else {
- preferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT);
+ List<Integer> allowedUids = Arrays.stream(
+ preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
+ Collectors.toList());
+ List<Integer> excludedUids = Arrays.stream(
+ preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
+ Collectors.toList());
+ preferenceBuilder.setIncludedUids(allowedUids);
+ preferenceBuilder.setExcludedUids(excludedUids);
+ preferenceBuilder.setPreferenceEnterpriseId(
+ preferentialNetworkServiceConfig.getNetworkId());
+
+ preferences.add(preferenceBuilder.build());
}
- List<Integer> allowedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getIncludedUids()).boxed().collect(
- Collectors.toList());
- List<Integer> excludedUids = Arrays.stream(
- preferentialNetworkServiceConfig.getExcludedUids()).boxed().collect(
- Collectors.toList());
- preferenceBuilder.setIncludedUids(allowedUids);
- preferenceBuilder.setExcludedUids(excludedUids);
- preferenceBuilder.setPreferenceEnterpriseId(
- preferentialNetworkServiceConfig.getNetworkId());
- List<ProfileNetworkPreference> preferences = new ArrayList<>();
- preferences.add(preferenceBuilder.build());
mInjector.binderWithCleanCallingIdentity(() ->
mInjector.getConnectivityManager().setProfileNetworkPreferences(
UserHandle.of(userId), preferences,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index fa2850a..c8eaa23 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -423,6 +423,8 @@
private static final String SDK_SANDBOX_MANAGER_SERVICE_CLASS =
"com.android.server.sdksandbox.SdkSandboxManagerService$Lifecycle";
+ private static final String AD_SERVICES_MANAGER_SERVICE_CLASS =
+ "com.android.server.adservices.AdServicesManagerService$Lifecycle";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -2608,6 +2610,11 @@
mSystemServiceManager.startService(SDK_SANDBOX_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ // AdServicesManagerService (PP API service)
+ t.traceBegin("StartAdServicesManagerService");
+ mSystemServiceManager.startService(AD_SERVICES_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
+
if (safeMode) {
mActivityManagerService.enterSafeMode();
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index c5f990d..66e840b 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -112,7 +112,7 @@
try {
mIProfcollect.registerProviderStatusCallback(mProviderStatusCallback);
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to register provider status callback: " + e.getMessage());
}
}
@@ -123,7 +123,7 @@
try {
return !mIProfcollect.get_supported_provider().isEmpty();
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to get supported provider: " + e.getMessage());
return false;
}
}
@@ -219,7 +219,8 @@
try {
sSelfService.mIProfcollect.process();
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to process profiles in background: "
+ + e.getMessage());
}
});
return true;
@@ -234,8 +235,11 @@
// Event observers
private void registerObservers() {
- registerAppLaunchObserver();
- registerOTAObserver();
+ BackgroundThread.get().getThreadHandler().post(
+ () -> {
+ registerAppLaunchObserver();
+ registerOTAObserver();
+ });
}
private final AppLaunchObserver mAppLaunchObserver = new AppLaunchObserver();
@@ -264,7 +268,7 @@
try {
mIProfcollect.trace_once("applaunch");
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
});
}
@@ -348,7 +352,7 @@
.putExtra("filename", reportName);
context.sendBroadcast(intent);
} catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ Log.e(LOG_TAG, "Failed to upload report: " + e.getMessage());
}
});
}
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 83ccabf..8f81e93 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
@@ -505,11 +505,6 @@
)
}
),
- getSetByValue(
- AndroidPackage::shouldInheritKeyStoreKeys,
- ParsingPackage::setInheritKeyStoreKeys,
- true
- ),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
getSetByValue(
AndroidPackage::isOnBackInvokedCallbackEnabled,
diff --git a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
index e89c812..4fe9cd3 100644
--- a/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
+++ b/services/tests/mockingservicestests/src/android/service/games/GameSessionTest.java
@@ -28,7 +28,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import android.graphics.Bitmap;
import android.platform.test.annotations.Presubmit;
import android.service.games.GameSession.ScreenshotCallback;
import android.testing.AndroidTestingRunner;
@@ -61,7 +60,6 @@
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public final class GameSessionTest {
private static final long WAIT_FOR_CALLBACK_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1);
- private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
@Mock
private IGameSessionController mMockGameSessionController;
@@ -101,7 +99,7 @@
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -131,7 +129,7 @@
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -160,7 +158,7 @@
}
@Override
- public void onSuccess(Bitmap bitmap) {
+ public void onSuccess() {
fail();
}
});
@@ -170,10 +168,10 @@
}
@Test
- public void takeScreenshot_gameManagerSuccess_returnsBitmap() throws Exception {
+ public void takeScreenshot_gameManagerSuccess() throws Exception {
doAnswer(invocation -> {
AndroidFuture result = invocation.getArgument(1);
- result.complete(GameScreenshotResult.createSuccessResult(TEST_BITMAP));
+ result.complete(GameScreenshotResult.createSuccessResult());
return null;
}).when(mMockGameSessionController).takeScreenshot(anyInt(), any());
@@ -187,8 +185,7 @@
}
@Override
- public void onSuccess(Bitmap bitmap) {
- assertEquals(TEST_BITMAP, bitmap);
+ public void onSuccess() {
countDownLatch.countDown();
}
});
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 32a31d0..319a769 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.app.GameServiceProviderInstanceImplTest.FakeGameService.GameServiceState;
@@ -26,19 +27,21 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verifyZeroInteractions;
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.IProcessObserver;
import android.app.ITaskStackListener;
import android.content.ComponentName;
import android.content.Context;
@@ -46,7 +49,12 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Picture;
import android.graphics.Rect;
+import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -71,6 +79,7 @@
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.ScreenshotHelper;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.TaskSystemBarsListener;
import com.android.server.wm.WindowManagerService;
@@ -87,6 +96,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
+import java.util.function.Consumer;
/**
@@ -114,11 +124,22 @@
new ComponentName(GAME_B_PACKAGE, "com.package.game.b.MainActivity");
- private static final Bitmap TEST_BITMAP = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888);
+ private static final Bitmap TEST_BITMAP;
+ static {
+ Picture picture = new Picture();
+ Canvas canvas = picture.beginRecording(200, 100);
+ Paint p = new Paint();
+ p.setColor(Color.BLACK);
+ canvas.drawCircle(10, 10, 10, p);
+ picture.endRecording();
+ TEST_BITMAP = Bitmap.createBitmap(picture);
+ }
private MockitoSession mMockingSession;
private GameServiceProviderInstance mGameServiceProviderInstance;
@Mock
+ private ActivityManagerInternal mMockActivityManagerInternal;
+ @Mock
private IActivityTaskManager mMockActivityTaskManager;
@Mock
private WindowManagerService mMockWindowManagerService;
@@ -126,6 +147,8 @@
private WindowManagerInternal mMockWindowManagerInternal;
@Mock
private IActivityManager mMockActivityManager;
+ @Mock
+ private ScreenshotHelper mMockScreenshotHelper;
private MockContext mMockContext;
private FakeGameClassifier mFakeGameClassifier;
private FakeGameService mFakeGameService;
@@ -133,6 +156,7 @@
private FakeGameSessionService mFakeGameSessionService;
private FakeServiceConnector<IGameSessionService> mFakeGameSessionServiceConnector;
private ArrayList<ITaskStackListener> mTaskStackListeners;
+ private ArrayList<IProcessObserver> mProcessObservers;
private ArrayList<TaskSystemBarsListener> mTaskSystemBarsListeners;
private ArrayList<RunningTaskInfo> mRunningTaskInfos;
@@ -167,6 +191,16 @@
return null;
}).when(mMockActivityTaskManager).unregisterTaskStackListener(any());
+ mProcessObservers = new ArrayList<>();
+ doAnswer(invocation -> {
+ mProcessObservers.add(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityManager).registerProcessObserver(any());
+ doAnswer(invocation -> {
+ mProcessObservers.remove(invocation.getArgument(0));
+ return null;
+ }).when(mMockActivityManager).unregisterProcessObserver(any());
+
mTaskSystemBarsListeners = new ArrayList<>();
doAnswer(invocation -> {
mTaskSystemBarsListeners.add(invocation.getArgument(0));
@@ -188,11 +222,13 @@
mMockContext,
mFakeGameClassifier,
mMockActivityManager,
+ mMockActivityManagerInternal,
mMockActivityTaskManager,
mMockWindowManagerService,
mMockWindowManagerInternal,
mFakeGameServiceConnector,
- mFakeGameSessionServiceConnector);
+ mFakeGameSessionServiceConnector,
+ mMockScreenshotHelper);
}
@After
@@ -410,6 +446,214 @@
}
@Test
+ public void gameProcessStopped_soleProcess_destroysGameSession() throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the sole game process destroys the game session.
+ dispatchProcessDied(gameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessStopped_soleProcess_destroysMultipleGameSessionsForSamePackage()
+ throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // Multiple tasks exist for the same package.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(11, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(11);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ FakeGameSession gameSession11 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(11)
+ .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+
+ // Death of the sole game process destroys both game sessions.
+ dispatchProcessDied(gameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessStopped_multipleProcesses_gameSessionDestroyedWhenAllDead()
+ throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1001;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the first process (with the second one still alive) does not destroy the game
+ // session.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // Death of the second process does destroy the game session.
+ dispatchProcessDied(secondGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ }
+
+ @Test
+ public void gameProcessCreatedAfterInitialProcessDead_newGameSessionCreated() throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+
+ // After the first game process dies, the game session should be destroyed.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+
+ // However, when a new process for the game starts, a new game session should be created.
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+ // Verify that a new pending game session is created for the game's taskId.
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+ }
+
+ @Test
+ public void gameProcessCreatedAfterInitialProcessDead_multipleGameSessionsCreatedSamePackage()
+ throws Exception {
+ int firstGameProcessId = 1000;
+ int secondGameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // Multiple tasks exist for the same package.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(11, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+ mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(11);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+ FakeGameSession gameSession11 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage11 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(11)
+ .complete(new CreateGameSessionResult(gameSession11, mockSurfacePackage11));
+
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ assertThat(gameSession11.mIsDestroyed).isFalse();
+
+ // After the first game process dies, both game sessions for the package should be
+ // destroyed.
+ dispatchProcessDied(firstGameProcessId);
+ assertThat(gameSession10.mIsDestroyed).isTrue();
+ assertThat(gameSession11.mIsDestroyed).isTrue();
+
+ // However, when a new process for the game starts, new game sessions for the same
+ // package should be created.
+ startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
+ // Verify that new pending game sessions were created for each of the game's taskIds.
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(10));
+ assertNotNull(mFakeGameSessionService.removePendingFutureForTaskId(11));
+ }
+
+ @Test
+ public void gameProcessStarted_gameSessionNotRequested_doesNothing() throws Exception {
+ int gameProcessId = 1000;
+
+ mGameServiceProviderInstance.start();
+
+ // A game task and process are started, but requestCreateGameSession is never called.
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+ startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+
+ // No game session should be created.
+ assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
+ }
+
+ @Test
+ public void processActivityAndDeath_notForGame_gameSessionUnaffected() throws Exception {
+ mGameServiceProviderInstance.start();
+
+ startTask(10, GAME_A_MAIN_ACTIVITY);
+
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
+ mFakeGameService.requestCreateGameSession(10);
+
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockSurfacePackage10 = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockSurfacePackage10));
+
+ // Process activity for a process without a known package is ignored.
+ startProcessForPackage(1000, /*packageName=*/ null);
+ dispatchProcessActivity(1000);
+ dispatchProcessDied(1000);
+
+ // Process activity for a process with a different package is ignored
+ startProcessForPackage(1001, GAME_B_PACKAGE);
+ dispatchProcessActivity(1001);
+ dispatchProcessDied(1001);
+
+ // Death of a process for which there was no activity is ignored
+ dispatchProcessDied(1002);
+
+ // Despite all the process activity and death, the game session is not destroyed.
+ assertThat(gameSession10.mIsDestroyed).isFalse();
+ }
+
+ @Test
public void taskSystemBarsListenerChanged_noAssociatedGameSession_doesNothing() {
mGameServiceProviderInstance.start();
@@ -425,6 +669,7 @@
public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() {
mGameServiceProviderInstance.start();
startTask(10, GAME_A_MAIN_ACTIVITY);
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
FakeGameSession gameSession10 = new FakeGameSession();
@@ -446,6 +691,7 @@
public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() {
mGameServiceProviderInstance.start();
startTask(10, GAME_A_MAIN_ACTIVITY);
+ mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
FakeGameSession gameSession10 = new FakeGameSession();
@@ -799,27 +1045,32 @@
SurfaceControl mockOverlaySurfaceControl = Mockito.mock(SurfaceControl.class);
SurfaceControl[] excludeLayers = new SurfaceControl[1];
excludeLayers[0] = mockOverlaySurfaceControl;
+ int taskId = 10;
when(mMockWindowManagerService.captureTaskBitmap(eq(10), any())).thenReturn(TEST_BITMAP);
-
+ doAnswer(invocation -> {
+ Consumer<Uri> consumer = invocation.getArgument(invocation.getArguments().length - 1);
+ consumer.accept(Uri.parse("a/b.png"));
+ return null;
+ }).when(mMockScreenshotHelper).provideScreenshot(
+ any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any());
mGameServiceProviderInstance.start();
- startTask(10, GAME_A_MAIN_ACTIVITY);
+ startTask(taskId, GAME_A_MAIN_ACTIVITY);
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
- mFakeGameService.requestCreateGameSession(10);
+ mFakeGameService.requestCreateGameSession(taskId);
FakeGameSession gameSession10 = new FakeGameSession();
SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
when(mockOverlaySurfacePackage.getSurfaceControl()).thenReturn(mockOverlaySurfaceControl);
- mFakeGameSessionService.removePendingFutureForTaskId(10)
+ mFakeGameSessionService.removePendingFutureForTaskId(taskId)
.complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
IGameSessionController gameSessionController = getOnlyElement(
mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
- gameSessionController.takeScreenshot(10, resultFuture);
+ gameSessionController.takeScreenshot(taskId, resultFuture);
GameScreenshotResult result = resultFuture.get();
assertEquals(GameScreenshotResult.GAME_SCREENSHOT_SUCCESS, result.getStatus());
- assertEquals(TEST_BITMAP, result.getBitmap());
}
@Test
@@ -874,7 +1125,8 @@
mFakeGameSessionService.getCapturedCreateInvocations())
.mGameSessionController.restartGame(11);
- verifyZeroInteractions(mMockActivityManager);
+ verify(mMockActivityManager).registerProcessObserver(any());
+ verifyNoMoreInteractions(mMockActivityManager);
assertThat(mMockContext.getLastStartedIntent()).isNull();
}
@@ -906,7 +1158,6 @@
dispatchTaskRemoved(taskId);
}
-
private void dispatchTaskRemoved(int taskId) {
dispatchTaskChangeEvent(taskStackListener -> {
taskStackListener.onTaskRemoved(taskId);
@@ -932,6 +1183,37 @@
}
}
+ private void startProcessForPackage(int processId, @Nullable String packageName) {
+ if (packageName != null) {
+ when(mMockActivityManagerInternal.getPackageNameByPid(processId)).thenReturn(
+ packageName);
+ }
+
+ dispatchProcessActivity(processId);
+ }
+
+ private void dispatchProcessActivity(int processId) {
+ dispatchProcessChangedEvent(processObserver -> {
+ // Neither uid nor foregroundActivities are used by the implementation being tested.
+ processObserver.onForegroundActivitiesChanged(processId, /*uid=*/
+ 0, /*foregroundActivities=*/ false);
+ });
+ }
+
+ private void dispatchProcessDied(int processId) {
+ dispatchProcessChangedEvent(processObserver -> {
+ // The uid param is not used by the implementation being tested.
+ processObserver.onProcessDied(processId, /*uid=*/ 0);
+ });
+ }
+
+ private void dispatchProcessChangedEvent(
+ ThrowingConsumer<IProcessObserver> processObserverConsumer) {
+ for (IProcessObserver processObserver : mProcessObservers) {
+ processObserverConsumer.accept(processObserver);
+ }
+ }
+
private void mockPermissionGranted(String permission) {
mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 8223b8c..6f503c7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -116,7 +116,7 @@
when(mInjector.getDataDirStorageLowBytes()).thenReturn(STORAGE_LOW_BYTES);
when(mInjector.getDexOptThermalCutoff()).thenReturn(PowerManager.THERMAL_STATUS_CRITICAL);
when(mInjector.getCurrentThermalStatus()).thenReturn(PowerManager.THERMAL_STATUS_NONE);
- when(mDexOptHelper.getOptimizablePackages()).thenReturn(DEFAULT_PACKAGE_LIST);
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(DEFAULT_PACKAGE_LIST);
when(mDexOptHelper.performDexOptWithStatus(any())).thenReturn(
PackageDexOptimizer.DEX_OPT_PERFORMED);
@@ -158,7 +158,7 @@
@Test
public void testNoExecutionForNoOptimizablePackages() {
initUntilBootCompleted();
- when(mDexOptHelper.getOptimizablePackages()).thenReturn(EMPTY_PACKAGE_LIST);
+ when(mDexOptHelper.getOptimizablePackages(any())).thenReturn(EMPTY_PACKAGE_LIST);
assertThat(mService.onStartJob(mJobServiceForPostBoot,
mJobParametersForPostBoot)).isFalse();
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
index 1319903..537a028 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageManagerServiceHibernationTests.kt
@@ -157,7 +157,7 @@
rule.system().validateFinalState()
whenever(appHibernationManager.isHibernatingGlobally(TEST_PACKAGE_2_NAME)).thenReturn(true)
- val optimizablePkgs = DexOptHelper(pm).optimizablePackages
+ val optimizablePkgs = DexOptHelper(pm).getOptimizablePackages(pm.snapshotComputer())
assertTrue(optimizablePkgs.contains(TEST_PACKAGE_NAME))
assertFalse(optimizablePkgs.contains(TEST_PACKAGE_2_NAME))
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 b063d22..1515282 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SharedLibrariesImplTest.kt
@@ -85,6 +85,7 @@
private lateinit var mSharedLibrariesImpl: SharedLibrariesImpl
private lateinit var mPms: PackageManagerService
private lateinit var mSettings: Settings
+ private lateinit var mComputer: Computer
@Mock
private lateinit var mDeletePackageHelper: DeletePackageHelper
@@ -114,22 +115,16 @@
mSharedLibrariesImpl.setDeletePackageHelper(mDeletePackageHelper)
addExistingSharedLibraries()
+ mComputer = mock {
+ whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
+ whenever(resolveInternalPackageName(anyString(), anyLong())) { arguments[0] }
+ }
+
whenever(mSettings.getPackageLPr(any())) { mExistingSettings[arguments[0]] }
whenever(mRule.mocks().injector.getSystemService(StorageManager::class.java))
.thenReturn(mStorageManager)
whenever(mStorageManager.findPathForUuid(nullable())).thenReturn(mFile)
- doAnswer { it.arguments[0] }.`when`(mPms).resolveInternalPackageName(any(), any())
- doAnswer {
- mockThrowOnUnmocked<Computer> {
- whenever(sharedLibraries) { mSharedLibrariesImpl.sharedLibraries }
- whenever(resolveInternalPackageName(anyString(), anyLong())) {
- mPms.resolveInternalPackageName(getArgument(0), getArgument(1))
- }
- whenever(getPackageStateInternal(anyString())) {
- mPms.getPackageStateInternal(getArgument(0))
- }
- }
- }.`when`(mPms).snapshotComputer()
+ doAnswer { mComputer }.`when`(mPms).snapshotComputer()
whenever(mDeletePackageHelper.deletePackageX(any(), any(), any(), any(), any()))
.thenReturn(PackageManager.DELETE_SUCCEEDED)
whenever(mRule.mocks().injector.compatibility).thenReturn(mPlatformCompat)
@@ -189,7 +184,8 @@
@Test
fun removeSharedLibrary() {
- doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }.`when`(mPms)
+ doAnswer { mutableListOf(VersionedPackage(CONSUMER_PACKAGE_NAME, 1L)) }
+ .`when`(mComputer)
.getPackagesUsingSharedLibrary(any(), any(), any(), any())
val staticInfo = mSharedLibrariesImpl
.getSharedLibraryInfo(STATIC_LIB_NAME, STATIC_LIB_VERSION)!!
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index f7b1dd5..1464405 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -39,8 +39,7 @@
import android.content.pm.ApexStagedEvent;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionInfo;
-import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode;
+import android.content.pm.PackageManager;
import android.content.pm.StagedApexInfo;
import android.os.SystemProperties;
import android.os.storage.IStorageManager;
@@ -158,10 +157,10 @@
mStagingManager.restoreSessions(Arrays.asList(session1, session2), true);
- assertThat(session1.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ assertThat(session1.getErrorCode()).isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(session1.getErrorMessage()).isEqualTo("Build fingerprint has changed");
- assertThat(session2.getErrorCode()).isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ assertThat(session2.getErrorCode()).isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(session2.getErrorMessage()).isEqualTo("Build fingerprint has changed");
}
@@ -247,12 +246,12 @@
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ "staged session supposed to be activated");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -303,22 +302,22 @@
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession1.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. "
+ "Error: Failed for test");
assertThat(apexSession2.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession2.getErrorMessage()).isEqualTo("Staged session 101 at boot didn't "
+ "activate nor fail. Marking it as failed anyway.");
assertThat(apexSession3.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession3.getErrorMessage()).isEqualTo("apexd did not know anything about a "
+ "staged session supposed to be activated");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -351,12 +350,12 @@
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("Staged session 1543 at boot didn't "
+ "activate nor fail. Marking it as failed anyway.");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -445,11 +444,11 @@
verify(mStorageManager, never()).abortChanges(eq("abort-staged-install"), eq(false));
assertThat(apexSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apexSession.getErrorMessage()).isEqualTo("Impossible state");
assertThat(apkSession.getErrorCode())
- .isEqualTo(SessionInfo.SESSION_ACTIVATION_FAILED);
+ .isEqualTo(PackageManager.INSTALL_ACTIVATION_FAILED);
assertThat(apkSession.getErrorMessage()).isEqualTo("Another apex session failed");
}
@@ -755,7 +754,7 @@
/* isReady */ false,
/* isFailed */ false,
/* isApplied */false,
- /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.SESSION_NO_ERROR,
+ /* stagedSessionErrorCode */ PackageManager.INSTALL_UNKNOWN,
/* stagedSessionErrorMessage */ "no error");
StagingManager.StagedSession stagedSession = spy(session.mStagedSession);
@@ -775,7 +774,7 @@
private boolean mIsReady = false;
private boolean mIsApplied = false;
private boolean mIsFailed = false;
- private @SessionErrorCode int mErrorCode = -1;
+ private int mErrorCode = -1;
private String mErrorMessage;
private boolean mIsDestroyed = false;
private int mParentSessionId = -1;
@@ -828,7 +827,7 @@
return this;
}
- private @SessionErrorCode int getErrorCode() {
+ private int getErrorCode() {
return mErrorCode;
}
@@ -940,7 +939,7 @@
}
@Override
- public void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage) {
+ public void setSessionFailed(int errorCode, String errorMessage) {
Preconditions.checkState(!mIsApplied, "Already marked as applied");
mIsFailed = true;
mErrorCode = errorCode;
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 5230ea7..4818573 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -104,9 +104,9 @@
pms, rule.mocks().injector, broadcastHelper, protectedPackages)
defaultAppProvider = rule.mocks().defaultAppProvider
testHandler = rule.mocks().handler
- packageSetting1 = pms.getPackageStateInternal(TEST_PACKAGE_1)!!
- packageSetting2 = pms.getPackageStateInternal(TEST_PACKAGE_2)!!
- ownerSetting = pms.getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
+ packageSetting1 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_1)!!
+ packageSetting2 = pms.snapshotComputer().getPackageStateInternal(TEST_PACKAGE_2)!!
+ ownerSetting = pms.snapshotComputer().getPackageStateInternal(DEVICE_OWNER_PACKAGE)!!
deviceOwnerUid = UserHandle.getUid(TEST_USER_ID, ownerSetting.appId)
packagesToSuspend = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
uidsToSuspend = intArrayOf(packageSetting1.appId, packageSetting2.appId)
@@ -270,7 +270,7 @@
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedPackageAppExtras(
+ val result = suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.getString(TEST_PACKAGE_1)).isEqualTo(TEST_PACKAGE_1)
@@ -286,13 +286,13 @@
null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
@@ -311,13 +311,13 @@
nullable(), nullable(), any(), eq(TEST_PACKAGE_2), nullable(), any(), any(),
nullable(), nullable())
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNull()
- assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(
+ assertThat(suspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNull()
}
@@ -331,7 +331,7 @@
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(
+ val result = suspendPackageHelper.getSuspendedPackageLauncherExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.getString(TEST_PACKAGE_2)).isEqualTo(TEST_PACKAGE_2)
@@ -346,7 +346,7 @@
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.isPackageSuspended(
+ assertThat(suspendPackageHelper.isPackageSuspended(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isTrue()
}
@@ -360,7 +360,7 @@
testHandler.flush()
assertThat(failedNames).isEmpty()
- assertThat(suspendPackageHelper.getSuspendingPackage(
+ assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
}
@@ -375,7 +375,7 @@
testHandler.flush()
assertThat(failedNames).isEmpty()
- val result = suspendPackageHelper.getSuspendedDialogInfo(
+ val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
@@ -387,8 +387,8 @@
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10003))
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(any(), nullable(), bundleCaptor.capture(),
anyInt(), nullable(), nullable(), any(), nullable(), any(), nullable())
@@ -406,8 +406,8 @@
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, allowList(10001, 10002, 10007))
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -429,8 +429,8 @@
mockAllowList(packageSetting1, allowList(10001, 10002, 10003))
mockAllowList(packageSetting2, null)
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENDED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENDED, packagesToSuspend, uidsToSuspend, TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper, times(2)).sendPackageBroadcast(
any(), nullable(), bundleCaptor.capture(), anyInt(), nullable(), nullable(), any(),
@@ -449,8 +449,9 @@
@Test
@Throws(Exception::class)
fun sendPackagesSuspendModifiedForUser() {
- suspendPackageHelper.sendPackagesSuspendedForUser(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
- packagesToSuspend, uidsToSuspend, TEST_USER_ID)
+ suspendPackageHelper.sendPackagesSuspendedForUser(pms.snapshotComputer(),
+ Intent.ACTION_PACKAGES_SUSPENSION_CHANGED, packagesToSuspend, uidsToSuspend,
+ TEST_USER_ID)
testHandler.flush()
verify(broadcastHelper).sendPackageBroadcast(
eq(Intent.ACTION_PACKAGES_SUSPENSION_CHANGED), nullable(), bundleCaptor.capture(),
@@ -483,13 +484,13 @@
Mockito.doReturn(DIALER_PACKAGE).`when`(defaultAppProvider)
.getDefaultDialer(eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(INSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_INSTALLER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(UNINSTALLER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_UNINSTALLER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(VERIFIER_PACKAGE)).`when`(pms).getKnownPackageNamesInternal(
- eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
+ any(), eq(PackageManagerInternal.PACKAGE_VERIFIER), eq(TEST_USER_ID))
Mockito.doReturn(arrayOf(PERMISSION_CONTROLLER_PACKAGE)).`when`(pms)
- .getKnownPackageNamesInternal(
+ .getKnownPackageNamesInternal(any(),
eq(PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER), eq(TEST_USER_ID))
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 8abe46f..9d26971 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -159,8 +159,8 @@
.when(mockContext)
.getSystemService(PowerManager.class);
- mDexManager = new DexManager(mockContext, mPM, /*PackageDexOptimizer*/ null,
- mInstaller, mInstallLock);
+ mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null,
+ mInstaller, mInstallLock, mPM);
// Foo and Bar are available to user0.
// Only Bar is available to user1;
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 b601d14..1ebcbe1 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -4157,8 +4157,8 @@
@Test
public void testSetPreferentialNetworkServiceConfig_noProfileOwner() throws Exception {
assertExpectException(SecurityException.class, null,
- () -> dpm.setPreferentialNetworkServiceConfig(
- PreferentialNetworkServiceConfig.DEFAULT));
+ () -> dpm.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT)));
}
@Test
@@ -4198,10 +4198,10 @@
addManagedProfile(admin1, managedProfileAdminUid, admin1);
mContext.binder.callingUid = managedProfileAdminUid;
- dpm.setPreferentialNetworkServiceConfig(PreferentialNetworkServiceConfig.DEFAULT);
+ dpm.setPreferentialNetworkServiceConfigs(
+ List.of(PreferentialNetworkServiceConfig.DEFAULT));
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
- assertThat(dpm.getPreferentialNetworkServiceConfig()
- .isEnabled()).isFalse();
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0).isEnabled()).isFalse();
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
@@ -4227,8 +4227,8 @@
addManagedProfile(admin1, managedProfileAdminUid, admin1);
mContext.binder.callingUid = managedProfileAdminUid;
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
ProfileNetworkPreference preferenceDetails =
new ProfileNetworkPreference.Builder()
@@ -4257,8 +4257,8 @@
.setFallbackToDefaultConnectionAllowed(false)
.setIncludedUids(new int[]{1, 2})
.build();
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
List<Integer> includedList = new ArrayList<>();
includedList.add(1);
@@ -4292,8 +4292,8 @@
.setExcludedUids(new int[]{1, 2})
.build();
- dpm.setPreferentialNetworkServiceConfig(preferentialNetworkServiceConfigEnabled);
- assertThat(dpm.getPreferentialNetworkServiceConfig()
+ dpm.setPreferentialNetworkServiceConfigs(List.of(preferentialNetworkServiceConfigEnabled));
+ assertThat(dpm.getPreferentialNetworkServiceConfigs().get(0)
.isEnabled()).isTrue();
List<Integer> excludedUids = new ArrayList<>();
excludedUids.add(1);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 21c09a0..1d10b8a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -217,7 +217,7 @@
}
@Override
- protected boolean isCredentialSharedWithParent(int userId) {
+ protected boolean isCredentialSharableWithParent(int userId) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
return userInfo.isCloneProfile() || userInfo.isManagedProfile();
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index b37e94a..27c3ca4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -28,6 +28,7 @@
import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
import android.platform.test.annotations.Presubmit;
import android.util.AtomicFile;
import android.util.Slog;
@@ -197,7 +198,7 @@
/* isFailed */ false,
/* isApplied */false,
/* stagedSessionErrorCode */
- PackageInstaller.SessionInfo.SESSION_VERIFICATION_FAILED,
+ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
/* stagedSessionErrorMessage */ "some error");
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 050b224..946108d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -23,11 +23,10 @@
import static org.junit.Assert.fail;
import static java.lang.reflect.Modifier.isFinal;
-import static java.lang.reflect.Modifier.isPrivate;
-import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.IIntentReceiver;
@@ -63,7 +62,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
@@ -101,7 +99,7 @@
@Nullable Bundle bOptions) {
}
- public void sendPackageAddedForNewUsers(String packageName,
+ public void sendPackageAddedForNewUsers(@NonNull Computer snapshot, String packageName,
boolean sendBootComplete, boolean includeStopped, int appId,
int[] userIds, int[] instantUserIds, int dataLoaderType) {
}
@@ -456,147 +454,6 @@
return null;
}
- // Return the boolean locked value. A null return means the annotation was not
- // found. This method will fail if the annotation is found but is not one of the
- // known constants.
- private Boolean getOverride(Method m) {
- final String name = "Computer." + displayName(m);
- final Computer.LiveImplementation annotation =
- m.getAnnotation(Computer.LiveImplementation.class);
- if (annotation == null) {
- return null;
- }
- final int override = annotation.override();
- if (override == Computer.LiveImplementation.MANDATORY) {
- return true;
- } else if (override == Computer.LiveImplementation.NOT_ALLOWED) {
- return false;
- } else {
- flag(name, "invalid Live value: " + override);
- return null;
- }
- }
-
- @Test
- public void testComputerStructure() {
- // Verify that Copmuter methods are properly annotated and that ComputerLocked is
- // properly populated per annotations.
- // Call PackageManagerService.validateComputer();
- Class base = Computer.class;
-
- HashMap<Method, Boolean> methodType = new HashMap<>();
-
- // Verify that all Computer methods are annotated and that the annotation
- // parameter locked() is valid.
- for (Method m : base.getDeclaredMethods()) {
- final String name = "Computer." + displayName(m);
- Boolean override = getOverride(m);
- if (override == null) {
- flag(name, "missing required Live annotation");
- }
- methodType.put(m, override);
- }
-
- Class coreClass = ComputerEngine.class;
- final Method[] coreMethods = coreClass.getDeclaredMethods();
-
- // Examine every method in the core. If it inherits from a base method it must be
- // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY.
- // If the core method does not inherit from the base then it must be either
- // private or protected.
- for (Method m : base.getDeclaredMethods()) {
- String name = "Computer." + displayName(m);
- final boolean locked = methodType.get(m);
- final Method core = matchMethod(m, coreMethods);
- if (core == null) {
- flag(name, "not overridden in ComputerEngine");
- continue;
- }
- name = "ComputerEngine." + displayName(m);
- final int modifiers = core.getModifiers();
- if (!locked) {
- if (!isPublic(modifiers)) {
- flag(name, "is not public");
- }
- if (!isFinal(modifiers)) {
- flag(name, "is not final");
- }
- }
- }
- // Any methods left in the coreMethods array must be private or protected.
- // Protected methods must be overridden (and final) in the live list.
- Method[] coreHelpers = new Method[coreMethods.length];
- int coreIndex = 0;
- for (Method m : coreMethods) {
- if (m != null) {
- final String name = "ComputerEngine." + displayName(m);
- if (name.contains(".lambda$static")) {
- // skip static lambda function
- continue;
- }
-
- final int modifiers = m.getModifiers();
- if (isPrivate(modifiers)) {
- // Okay
- } else if (isProtected(modifiers)) {
- coreHelpers[coreIndex++] = m;
- } else {
- flag(name, "is neither private nor protected");
- }
- }
- }
-
- Class liveClass = ComputerLocked.class;
- final Method[] liveMethods = liveClass.getDeclaredMethods();
-
- // Examine every method in the live list. Every method must be final and must
- // inherit either from base or core. If the method inherits from a base method
- // then the base must be MANDATORY.
- for (Method m : base.getDeclaredMethods()) {
- String name = "Computer." + displayName(m);
- final boolean locked = methodType.get(m);
- final Method live = matchMethod(m, liveMethods);
- if (live == null) {
- if (locked) {
- flag(name, "not overridden in ComputerLocked");
- }
- continue;
- }
- if (!locked) {
- flag(name, "improperly overridden in ComputerLocked");
- continue;
- }
-
- name = "ComputerLocked." + displayName(m);
- final int modifiers = live.getModifiers();
- if (!locked) {
- if (!isPublic(modifiers)) {
- flag(name, "is not public");
- }
- if (!isFinal(modifiers)) {
- flag(name, "is not final");
- }
- }
- }
- for (Method m : coreHelpers) {
- if (m == null) {
- continue;
- }
- String name = "ComputerLocked." + displayName(m);
- final Method live = matchMethod(m, liveMethods);
- if (live == null) {
- flag(name, "is not overridden in ComputerLocked");
- continue;
- }
- }
- for (Method m : liveMethods) {
- if (m != null) {
- String name = "ComputerLocked." + displayName(m);
- flag(name, "illegal local method");
- }
- }
- }
-
private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
final String defaultTimeouts = "3600000001:3600000002:3600000003";
List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 2b34bc2..f4ab3db 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -31,11 +31,11 @@
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
@@ -1103,6 +1103,59 @@
assertThat(countDownLatch.getCount(), is(0L));
}
+ @Test
+ public void testRegisterAndRemoveAppId() throws PackageManagerException {
+ // Test that the first new app UID should start from FIRST_APPLICATION_UID
+ final Settings settings = makeSettings();
+ final PackageSetting ps = createPackageSetting("com.foo");
+ assertTrue(settings.registerAppIdLPw(ps, false));
+ assertEquals(10000, ps.getAppId());
+ // Set up existing app IDs: 10000, 10001, 10003
+ final PackageSetting ps1 = createPackageSetting("com.foo1");
+ ps1.setAppId(10001);
+ final PackageSetting ps2 = createPackageSetting("com.foo2");
+ ps2.setAppId(10003);
+ final PackageSetting ps3 = createPackageSetting("com.foo3");
+ assertEquals(0, ps3.getAppId());
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ assertTrue(settings.registerAppIdLPw(ps2, false));
+ assertTrue(settings.registerAppIdLPw(ps3, false));
+ assertEquals(10001, ps1.getAppId());
+ assertEquals(10003, ps2.getAppId());
+ // Expecting the new one to start with the next available uid
+ assertEquals(10002, ps3.getAppId());
+ // Remove and insert a new one and the new one should not reuse the same uid
+ settings.removeAppIdLPw(10002);
+ final PackageSetting ps4 = createPackageSetting("com.foo4");
+ assertTrue(settings.registerAppIdLPw(ps4, false));
+ assertEquals(10004, ps4.getAppId());
+ // Keep adding more
+ final PackageSetting ps5 = createPackageSetting("com.foo5");
+ assertTrue(settings.registerAppIdLPw(ps5, false));
+ assertEquals(10005, ps5.getAppId());
+ // Remove the last one and the new one should use incremented uid
+ settings.removeAppIdLPw(10005);
+ final PackageSetting ps6 = createPackageSetting("com.foo6");
+ assertTrue(settings.registerAppIdLPw(ps6, false));
+ assertEquals(10006, ps6.getAppId());
+ }
+
+ /**
+ * Test replacing a PackageSetting with a SharedUserSetting in mAppIds
+ */
+ @Test
+ public void testAddPackageSetting() throws PackageManagerException {
+ final Settings settings = makeSettings();
+ final SharedUserSetting sus1 = new SharedUserSetting(
+ "TestUser", 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
+ sus1.mAppId = 10001;
+ final PackageSetting ps1 = createPackageSetting("com.foo");
+ ps1.setAppId(10001);
+ assertTrue(settings.registerAppIdLPw(ps1, false));
+ settings.addPackageSettingLPw(ps1, sus1);
+ assertSame(sus1, settings.getSharedUserSettingLPr(ps1));
+ }
+
private void verifyUserState(PackageUserState userState,
boolean notLaunched, boolean stopped, boolean installed) {
assertThat(userState.getEnabledState(), is(0));
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 18d3f3d..1ce957d 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -489,6 +489,7 @@
@Before
public void setUp() throws Exception {
+ LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
LocalServices.addService(
UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
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 d752322..67382bf 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2705,13 +2705,10 @@
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
-
- // should not trigger a broadcast
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_IGNORED);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_DEFAULT);
// should trigger a broadcast
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
@@ -2720,7 +2717,7 @@
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
@@ -2737,7 +2734,6 @@
// should not trigger a broadcast
when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
// should trigger a broadcast
mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index a838872..2ba587d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -606,9 +606,9 @@
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_IGNORED);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
@@ -618,14 +618,14 @@
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
}
@Test
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
- mService.mAppOpsCallback.opChanged(0, mUid, PKG);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
Thread.sleep(500);
waitForIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 1924760..9d2eb26 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -101,14 +101,63 @@
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
- mPolicy.removeNonHighRefreshRatePackage("com.android.test");
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testCameraRange() {
+ final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
+ cameraUsingWindow.mAttrs.packageName = "com.android.test";
+ parcelLayoutParams(cameraUsingWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, MID_REFRESH_RATE);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(LOW_REFRESH_RATE,
+ mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(MID_REFRESH_RATE,
+ mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testCameraRange_OutOfRange() {
+ final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
+ cameraUsingWindow.mAttrs.packageName = "com.android.test";
+ parcelLayoutParams(cameraUsingWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE - 10, HI_REFRESH_RATE + 10);
+ assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
+ assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(LOW_REFRESH_RATE,
+ mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ assertEquals(HI_REFRESH_RATE,
+ mPolicy.getPreferredMaxRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
+ mPolicy.removeRefreshRateRangeForPackage("com.android.test");
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(0, mPolicy.getPreferredMinRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
@@ -162,7 +211,8 @@
overrideWindow.mAttrs.packageName = "com.android.test";
overrideWindow.mAttrs.preferredDisplayModeId = HI_MODE_ID;
parcelLayoutParams(overrideWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(HI_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(HI_REFRESH_RATE,
mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
@@ -178,7 +228,8 @@
overrideWindow.mAttrs.packageName = "com.android.test";
overrideWindow.mAttrs.preferredRefreshRate = HI_REFRESH_RATE;
parcelLayoutParams(overrideWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
assertEquals(HI_REFRESH_RATE,
mPolicy.getPreferredRefreshRate(overrideWindow), FLOAT_TOLERANCE);
@@ -257,7 +308,8 @@
cameraUsingWindow.mAttrs.packageName = "com.android.test";
parcelLayoutParams(cameraUsingWindow);
- mPolicy.addNonHighRefreshRatePackage("com.android.test");
+ mPolicy.addRefreshRateRangeForPackage("com.android.test",
+ LOW_REFRESH_RATE, LOW_REFRESH_RATE);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
assertEquals(0, mPolicy.getPreferredRefreshRate(cameraUsingWindow), FLOAT_TOLERANCE);
assertEquals(LOW_REFRESH_RATE,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 0debdfa..c615866 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -359,17 +359,11 @@
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
throws RemoteException {
mController.registerOrganizer(mIOrganizer);
- final ActivityRecord activity = createActivityRecord(mDisplayContent);
- final int uid = Binder.getCallingUid();
- activity.info.applicationInfo.uid = uid;
- activity.getTask().effectiveUid = uid;
+ final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
final IBinder fragmentToken = new Binder();
- final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
- mOrganizerToken, fragmentToken, activity.token).build();
- mOrganizer.applyTransaction(mTransaction);
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
- mTransaction.createTaskFragment(params);
+ createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
mTransaction.startActivityInTaskFragment(
mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
@@ -381,7 +375,7 @@
final TaskFragment taskFragment = mAtm.mWindowOrganizerController
.getTaskFragment(fragmentToken);
assertNotNull(taskFragment);
- assertEquals(activity.getTask(), taskFragment.getTask());
+ assertEquals(ownerActivity.getTask(), taskFragment.getTask());
}
@Test
@@ -523,4 +517,43 @@
mController.dispatchPendingEvents();
verify(mOrganizer).onTaskFragmentInfoChanged(any());
}
+
+ /**
+ * When an embedded {@link TaskFragment} is removed, we should clean up the reference in the
+ * {@link WindowOrganizerController}.
+ */
+ @Test
+ public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
+ throws RemoteException {
+ mController.registerOrganizer(mIOrganizer);
+ final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
+ final IBinder fragmentToken = new Binder();
+ createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
+ mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+ final TaskFragment taskFragment = mAtm.mWindowOrganizerController
+ .getTaskFragment(fragmentToken);
+
+ assertNotNull(taskFragment);
+
+ taskFragment.removeImmediately();
+
+ assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+ }
+
+ /**
+ * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
+ * {@link WindowOrganizerController#applyTransaction} to apply the transaction,
+ */
+ private void createTaskFragmentFromOrganizer(WindowContainerTransaction wct,
+ ActivityRecord ownerActivity, IBinder fragmentToken) {
+ final int uid = Binder.getCallingUid();
+ ownerActivity.info.applicationInfo.uid = uid;
+ ownerActivity.getTask().effectiveUid = uid;
+ final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
+ mOrganizerToken, fragmentToken, ownerActivity.token).build();
+ mOrganizer.applyTransaction(wct);
+
+ // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
+ wct.createTaskFragment(params);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index fe41734..636c6bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -146,6 +146,27 @@
}
@Test
+ public void testRemoveContainer_multipleNestedTasks() {
+ final Task rootTask = createTask(mDisplayContent);
+ rootTask.mCreatedByOrganizer = true;
+ final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
+ final Task task2 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
+ final ActivityRecord activity1 = createActivityRecord(task1);
+ final ActivityRecord activity2 = createActivityRecord(task2);
+ activity1.setVisible(false);
+
+ // All activities under the root task should be finishing.
+ rootTask.remove(true /* withTransition */, "test");
+ assertTrue(activity1.finishing);
+ assertTrue(activity2.finishing);
+
+ // After all activities activities are destroyed, the root task should also be removed.
+ activity1.removeImmediately();
+ activity2.removeImmediately();
+ assertFalse(rootTask.isAttached());
+ }
+
+ @Test
public void testRemoveContainer_deferRemoval() {
final Task rootTask = createTask(mDisplayContent);
final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 68e90e1..08320f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -161,7 +161,7 @@
@Test
public void testDismissKeyguardCanWakeUp() {
doReturn(true).when(mWm).checkCallingPermission(anyString(), anyString());
- doReturn(true).when(mWm.mAtmService).isDreaming();
+ doReturn(true).when(mWm.mAtmService.mKeyguardController).isShowingDream();
doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
mWm.dismissKeyguard(null, "test-dismiss-keyguard");
verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 27d423b..bce6809 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -3171,9 +3171,14 @@
*
* {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, android.os.Bundle)}.
*
+ * @param connectionManagerPhoneAccount The connection manager account to use for managing
+ * this call
+ * @param request Details about the outgoing call
+ * @return The {@code Connection} object to satisfy this call, or the result of an invocation
+ * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call
* @hide
*/
- @SystemApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public @Nullable Connection onCreateUnknownConnection(
@NonNull PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 493ad5e..1ccb464 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -48,6 +48,9 @@
@Override
public void sendMessage(SipMessage sipMessage, long configVersion) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.sendMessage(sipMessage, configVersion));
@@ -59,6 +62,9 @@
@Override
public void notifyMessageReceived(String viaTransactionId) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.notifyMessageReceived(viaTransactionId));
@@ -71,6 +77,9 @@
@Override
public void notifyMessageReceiveError(String viaTransactionId, int reason) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.notifyMessageReceiveError(viaTransactionId, reason));
@@ -83,6 +92,9 @@
@Override
public void cleanupSession(String callId) {
SipDelegate d = mDelegate;
+ if (d == null) {
+ return;
+ }
final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> d.cleanupSession(callId));
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
index 18f9623..bf8bd14 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -18,11 +18,13 @@
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.util.Log;
+import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
+import android.widget.TextView;
import android.widget.Toast;
import java.util.Random;
@@ -79,6 +81,14 @@
view.setPadding(0, 0, 0, 0);
view.addView(inner, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, height));
+ TextView text = new TextView(this);
+ text.setText("Handwriting IME");
+ text.setTextSize(13f);
+ text.setTextColor(getColor(android.R.color.white));
+ text.setGravity(Gravity.CENTER);
+ text.setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT, height));
+ view.addView(text);
inner.setBackgroundColor(0xff0110fe); // blue
return view;
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
index 4ffdc92..87a5b90 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -33,6 +33,7 @@
private static final long FINISH_TIMEOUT = 2500;
private final HandwritingIme.HandwritingFinisher mHwCanceller;
private final HandwritingIme.StylusConsumer mConsumer;
+ private final int mTopInset;
private Paint mPaint;
private Path mPath;
private float mX, mY;
@@ -63,6 +64,7 @@
setLayoutParams(new ViewGroup.LayoutParams(
metrics.getBounds().width() - insets.left - insets.right,
metrics.getBounds().height() - insets.top - insets.bottom));
+ mTopInset = insets.top;
}
@Override
@@ -74,12 +76,14 @@
}
private void stylusStart(float x, float y) {
+ y = y - mTopInset;
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void stylusMove(float x, float y) {
+ y = y - mTopInset;
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (mPath.isEmpty()) {
diff --git a/tests/TrustTests/AndroidManifest.xml b/tests/TrustTests/AndroidManifest.xml
index c94152d..68bc1f69 100644
--- a/tests/TrustTests/AndroidManifest.xml
+++ b/tests/TrustTests/AndroidManifest.xml
@@ -23,7 +23,9 @@
<uses-permission android:name="android.permission.BIND_DEVICE_ADMIN" />
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.PROVIDE_TRUST_AGENT" />
<uses-permission android:name="android.permission.TRUST_LISTENER" />
diff --git a/tests/TrustTests/TEST_MAPPING b/tests/TrustTests/TEST_MAPPING
new file mode 100644
index 0000000..b9c46bf
--- /dev/null
+++ b/tests/TrustTests/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "TrustTests",
+ "options": [
+ {
+ "include-filter": "android.trust.test"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/TrustTests/src/android/trust/test/LockUserTest.kt b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
index 83fc28f..8f200a6 100644
--- a/tests/TrustTests/src/android/trust/test/LockUserTest.kt
+++ b/tests/TrustTests/src/android/trust/test/LockUserTest.kt
@@ -25,7 +25,6 @@
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
@@ -49,7 +48,6 @@
.around(lockStateTrackingRule)
.around(trustAgentRule)
- @Ignore("Causes issues with subsequent tests") // TODO: Enable test
@Test
fun lockUser_locksTheDevice() {
Log.i(TAG, "Locking user")
diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
index bc100ba..006525d 100644
--- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt
@@ -20,6 +20,8 @@
import android.util.Log
import android.view.WindowManagerGlobal
import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
import com.android.internal.widget.LockPatternUtils
import com.android.internal.widget.LockscreenCredential
import com.google.common.truth.Truth.assertWithMessage
@@ -32,6 +34,7 @@
*/
class ScreenLockRule : TestRule {
private val context: Context = getApplicationContext()
+ private val uiDevice = UiDevice.getInstance(getInstrumentation())
private val windowManager = WindowManagerGlobal.getWindowManagerService()
private val lockPatternUtils = LockPatternUtils(context)
private var instantLockSavedValue = false
@@ -48,19 +51,21 @@
} finally {
removeScreenLock()
revertLockOnPowerButton()
+ verifyKeyguardDismissed()
}
}
}
private fun verifyNoScreenLockAlreadySet() {
assertWithMessage("Screen Lock must not already be set on device")
- .that(lockPatternUtils.isSecure(context.userId))
- .isFalse()
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isFalse()
}
private fun verifyKeyguardDismissed() {
val maxWaits = 30
var waitCount = 0
+
while (windowManager.isKeyguardLocked && waitCount < maxWaits) {
Log.i(TAG, "Keyguard still showing; attempting to dismiss and wait 50ms ($waitCount)")
windowManager.dismissKeyguard(null, null)
@@ -68,19 +73,19 @@
waitCount++
}
assertWithMessage("Keyguard should be unlocked")
- .that(windowManager.isKeyguardLocked)
- .isFalse()
+ .that(windowManager.isKeyguardLocked)
+ .isFalse()
}
private fun setScreenLock() {
lockPatternUtils.setLockCredential(
- LockscreenCredential.createPin(PIN),
- LockscreenCredential.createNone(),
- context.userId
+ LockscreenCredential.createPin(PIN),
+ LockscreenCredential.createNone(),
+ context.userId
)
assertWithMessage("Screen Lock should now be set")
- .that(lockPatternUtils.isSecure(context.userId))
- .isTrue()
+ .that(lockPatternUtils.isSecure(context.userId))
+ .isTrue()
Log.i(TAG, "Device PIN set to $PIN")
}
@@ -90,14 +95,25 @@
}
private fun removeScreenLock() {
- lockPatternUtils.setLockCredential(
- LockscreenCredential.createNone(),
- LockscreenCredential.createPin(PIN),
- context.userId
- )
- Log.i(TAG, "Device PIN cleared; waiting 50 ms then dismissing Keyguard")
- Thread.sleep(50)
- windowManager.dismissKeyguard(null, null)
+ var lockCredentialUnset = lockPatternUtils.setLockCredential(
+ LockscreenCredential.createNone(),
+ LockscreenCredential.createPin(PIN),
+ context.userId)
+ Thread.sleep(100)
+ assertWithMessage("Lock screen credential should be unset")
+ .that(lockCredentialUnset)
+ .isTrue()
+
+ lockPatternUtils.setLockScreenDisabled(true, context.userId)
+ Thread.sleep(100)
+ assertWithMessage("Lockscreen needs to be disabled")
+ .that(lockPatternUtils.isLockScreenDisabled(context.userId))
+ .isTrue()
+
+ // this is here because somehow it helps the keyguard not get stuck
+ uiDevice.sleep()
+ Thread.sleep(500) // delay added to avoid initiating camera by double clicking power
+ uiDevice.wakeUp()
}
private fun revertLockOnPowerButton() {
diff --git a/tools/aapt2/tools/finalize_res.py b/tools/aapt2/tools/finalize_res.py
new file mode 100755
index 0000000..0e4d865
--- /dev/null
+++ b/tools/aapt2/tools/finalize_res.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2022 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.
+#
+# 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.
+
+"""
+Finalize resource values in <staging-public-group> tags
+and convert those to <staging-public-group-final>
+
+Usage: $ANDROID_BUILD_TOP/frameworks/base/tools/aapt2/tools/finalize_res.py \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-staging.xml \
+ $ANDROID_BUILD_TOP/frameworks/base/core/res/res/values/public-final.xml
+"""
+
+import re
+import sys
+
+resTypes = ["attr", "id", "style", "string", "dimen", "color", "array", "drawable", "layout",
+ "anim", "animator", "interpolator", "mipmap", "integer", "transition", "raw", "bool",
+ "fraction"]
+
+_type_ids = {}
+_type = ""
+
+_lowest_staging_first_id = 0x01FFFFFF
+
+"""
+ Created finalized <public> declarations for staging resources, ignoring them if they've been
+ prefixed with removed_. The IDs are assigned without holes starting from the last ID for that
+ type currently finalized in public-final.xml.
+"""
+def finalize_item(raw):
+ name = raw.group(1)
+ if re.match(r'_*removed.+', name):
+ return ""
+ id = _type_ids[_type]
+ _type_ids[_type] += 1
+ return ' <public type="%s" name="%s" id="%s" />\n' % (_type, name, '0x{0:0{1}x}'.format(id, 8))
+
+
+"""
+ Finalizes staging-public-groups if they have any entries in them. Also keeps track of the
+ lowest first-id of the non-empty groups so that the next release's staging-public-groups can
+ be assigned the next down shifted first-id.
+"""
+def finalize_group(raw):
+ global _type, _lowest_staging_first_id
+ _type = raw.group(1)
+ id = int(raw.group(2), 16)
+ _type_ids[_type] = _type_ids.get(_type, id)
+ (res, count) = re.subn(' {0,4}<public name="(.+?)" */>\n', finalize_item, raw.group(3))
+ if count > 0:
+ res = raw.group(0).replace("staging-public-group",
+ "staging-public-group-final") + '\n' + res
+ _lowest_staging_first_id = min(id, _lowest_staging_first_id)
+ return res
+
+"""
+ Collects the max ID for each resType so that the new IDs can be assigned afterwards
+"""
+def collect_ids(raw):
+ for m in re.finditer(r'<public type="(.+?)" name=".+?" id="(.+?)" />', raw):
+ type = m.group(1)
+ id = int(m.group(2), 16)
+ _type_ids[type] = max(id + 1, _type_ids.get(type, 0))
+
+
+with open(sys.argv[1], "r+") as stagingFile:
+ with open(sys.argv[2], "r+") as finalFile:
+ existing = finalFile.read()
+ # Cut out the closing resources tag so that it can be concatenated easily later
+ existing = "\n".join(existing.rsplit("</resources>", 1))
+
+ # Collect the IDs from the existing already finalized resources
+ collect_ids(existing)
+
+ staging = stagingFile.read()
+ stagingSplit = staging.rsplit("<resources>")
+ staging = stagingSplit[1]
+ staging = re.sub(
+ r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>',
+ finalize_group, staging, flags=re.DOTALL)
+ staging = re.sub(r' *\n', '\n', staging)
+ staging = re.sub(r'\n{3,}', '\n\n', staging)
+
+ # First write the existing finalized declarations and then append the new stuff
+ finalFile.seek(0)
+ finalFile.write(existing.strip("\n"))
+ finalFile.write("\n\n")
+ finalFile.write(staging.strip("\n"))
+ finalFile.write("\n")
+ finalFile.truncate()
+
+ stagingFile.seek(0)
+ # Include the documentation from public-staging.xml that was previously split out
+ stagingFile.write(stagingSplit[0])
+ # Write the next platform header
+ stagingFile.write("<resources>\n\n")
+ stagingFile.write(" <!-- ===============================================================\n")
+ stagingFile.write(" Resources added in version NEXT of the platform\n\n")
+ stagingFile.write(" NOTE: After this version of the platform is forked, changes cannot be made to the root\n")
+ stagingFile.write(" branch's groups for that release. Only merge changes to the forked platform branch.\n")
+ stagingFile.write(" =============================================================== -->\n")
+ stagingFile.write(" <eat-comment/>\n\n")
+
+ # Seed the next release's staging-public-groups as empty declarations,
+ # so its easy for another developer to expose a new public resource
+ nextId = _lowest_staging_first_id - 0x00010000
+ for resType in resTypes:
+ stagingFile.write(' <staging-public-group type="%s" first-id="%s">\n'
+ ' </staging-public-group>\n\n' %
+ (resType, '0x{0:0{1}x}'.format(nextId, 8)))
+ nextId -= 0x00010000
+
+ # Close the resources tag and truncate, since the file will be shorter than the previous
+ stagingFile.write("</resources>\n")
+ stagingFile.truncate()
diff --git a/tools/finalize_res/finalize_res.py b/tools/finalize_res/finalize_res.py
deleted file mode 100755
index aaf0187..0000000
--- a/tools/finalize_res/finalize_res.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python3
-#-*- coding: utf-8 -*-
-
-# Copyright (C) 2021 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.
-
-"""
-Finalize resource values in <staging-public-group> tags
-
-Usage: finalize_res.py core/res/res/values/public.xml public_finalized.xml
-"""
-
-import re, sys, codecs
-
-def finalize_item(raw):
- global _type, _id
- _id += 1
- return '<public type="%s" name="%s" id="%s" />' % (_type, raw.group(1), '0x{0:0{1}x}'.format(_id-1,8))
-
-def finalize_group(raw):
- global _type, _id
- _type = raw.group(1)
- _id = int(raw.group(2), 16)
- return re.sub(r'<public name="(.+?)" */>', finalize_item, raw.group(3))
-
-with open(sys.argv[1]) as f:
- raw = f.read()
- raw = re.sub(r'<staging-public-group type="(.+?)" first-id="(.+?)">(.+?)</staging-public-group>', finalize_group, raw, flags=re.DOTALL)
- with open(sys.argv[2], "w") as f:
- f.write(raw)
diff --git a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
index 1aec9b8..2e60f64 100644
--- a/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
+++ b/tools/processors/staledataclass/src/android/processor/staledataclass/StaleDataclassProcessor.kt
@@ -21,8 +21,6 @@
import com.android.codegen.CANONICAL_BUILDER_CLASS
import com.android.codegen.CODEGEN_NAME
import com.android.codegen.CODEGEN_VERSION
-import com.sun.tools.javac.code.Symbol
-import com.sun.tools.javac.code.Type
import java.io.File
import java.io.FileNotFoundException
import javax.annotation.processing.AbstractProcessor
@@ -33,6 +31,7 @@
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
+import javax.lang.model.type.ExecutableType
import javax.tools.Diagnostic
private const val STALE_FILE_THRESHOLD_MS = 1000
@@ -102,14 +101,13 @@
append(" ")
append(elem.annotationMirrors.joinToString(" ", transform = { annotationToString(it) }))
append(" ")
- if (elem is Symbol) {
- if (elem.type is Type.MethodType) {
- append((elem.type as Type.MethodType).returnType)
- } else {
- append(elem.type)
- }
- append(" ")
+ val type = elem.asType()
+ if (type is ExecutableType) {
+ append(type.returnType)
+ } else {
+ append(type)
}
+ append(" ")
append(elem)
}
}
@@ -234,4 +232,4 @@
override fun getSupportedSourceVersion(): SourceVersion {
return SourceVersion.latest()
}
-}
\ No newline at end of file
+}
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index 9604475..8630ec4 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -963,6 +963,25 @@
}
/**
+ * Get the max number of SSIDs that the driver supports per scan.
+ *
+ * @param ifaceName Name of the interface.
+ */
+ public int getMaxNumScanSsids(@NonNull String ifaceName) {
+ IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
+ if (scannerImpl == null) {
+ Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
+ return 0;
+ }
+ try {
+ return scannerImpl.getMaxNumScanSsids();
+ } catch (RemoteException e1) {
+ Log.e(TAG, "Failed to getMaxNumScanSsids");
+ }
+ return 0;
+ }
+
+ /**
* Return scan type for the parcelable {@link SingleScanSettings}
*/
private static int getScanType(@WifiAnnotations.ScanType int scanType) {