Merge "Bouncer: Use Y coord delta instead of velocity." into tm-dev
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
index 4ad015d..c92c634 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/RelayoutPerfTest.java
@@ -20,6 +20,7 @@
import android.app.Activity;
import android.content.Context;
+import android.os.Bundle;
import android.os.RemoteException;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
@@ -153,7 +154,8 @@
while (state.keepRunning()) {
session.relayout(mWindow, mParams, mWidth, mHeight,
mViewVisibility.getAsInt(), mFlags, mOutFrames,
- mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls);
+ mOutMergedConfiguration, mOutSurfaceControl, mOutInsetsState, mOutControls,
+ new Bundle());
}
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 90ec700..528be3c 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -4891,13 +4891,15 @@
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
- getContext().registerReceiver(this, filter);
+ getContext().registerReceiverForAllUsers(this, filter,
+ /* broadcastPermission */ null, /* scheduler */ null);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
sdFilter.addAction(Intent.ACTION_UID_REMOVED);
- getContext().registerReceiver(this, sdFilter);
+ getContext().registerReceiverForAllUsers(this, sdFilter,
+ /* broadcastPermission */ null, /* scheduler */ null);
}
@Override
@@ -4915,9 +4917,6 @@
}
}
return;
- case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
- break;
case Intent.ACTION_USER_STOPPED:
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (userHandle >= 0) {
@@ -4932,6 +4931,18 @@
mRemovalHistory.delete(uid);
mLastOpScheduleExactAlarm.delete(uid);
return;
+ case Intent.ACTION_PACKAGE_ADDED:
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ final String packageUpdated = intent.getData().getSchemeSpecificPart();
+ mHandler.obtainMessage(
+ AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
+ packageUpdated).sendToTarget();
+ }
+ mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
+ return;
+ case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ break;
case Intent.ACTION_PACKAGE_REMOVED:
if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// This package is being updated; don't kill its alarms.
@@ -4950,15 +4961,6 @@
}
}
break;
- case Intent.ACTION_PACKAGE_ADDED:
- if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
- final String packageUpdated = intent.getData().getSchemeSpecificPart();
- mHandler.obtainMessage(
- AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE, uid, -1,
- packageUpdated).sendToTarget();
- }
- mHandler.sendEmptyMessage(AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES);
- return;
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkg : pkgList) {
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index dd102bd..e986b1a 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -667,8 +667,8 @@
long getBucketExpiryTimeMs(String packageName, int userId, int bucket, long elapsedRealtimeMs) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
- elapsedRealtimeMs, true);
- if (appUsageHistory.bucketExpiryTimesMs == null) {
+ elapsedRealtimeMs, false /* create */);
+ if (appUsageHistory == null || appUsageHistory.bucketExpiryTimesMs == null) {
return 0;
}
return appUsageHistory.bucketExpiryTimesMs.get(bucket, 0);
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 6a685a79..a157517 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -64,8 +64,6 @@
"libwilhelm",
],
- header_libs: ["bionic_libc_platform_headers"],
-
compile_multilib: "both",
cflags: [
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 815f945..12083b6 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -15,7 +15,6 @@
#include <android-base/macros.h>
#include <binder/IPCThreadState.h>
-#include <bionic/pac.h>
#include <hwbinder/IPCThreadState.h>
#include <utils/Log.h>
#include <cutils/memory.h>
@@ -183,10 +182,6 @@
ALOGV("app_process main with argv: %s", argv_String.string());
}
- // Because of applications that are using PAC instructions incorrectly, PAC
- // is disabled in application processes for now.
- ScopedDisablePAC x;
-
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index c202f6f..6ef6845 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -52,6 +52,7 @@
"-readability-braces-around-statements",
"-readability-const-return-type",
"-readability-convert-member-functions-to-static",
+ "-readability-duplicate-include",
"-readability-else-after-return",
"-readability-identifier-length",
"-readability-named-parameter",
diff --git a/core/api/current.txt b/core/api/current.txt
index 19ffd36e..74e3043 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3901,7 +3901,7 @@
method public Object getAnimatedValue(String);
method public long getCurrentPlayTime();
method public long getDuration();
- method @FloatRange(from=0, to=1) public static float getDurationScale();
+ method @FloatRange(from=0) public static float getDurationScale();
method public static long getFrameDelay();
method public int getRepeatCount();
method public int getRepeatMode();
@@ -3941,7 +3941,7 @@
}
public static interface ValueAnimator.DurationScaleChangeListener {
- method public void onChanged(float);
+ method public void onChanged(@FloatRange(from=0) float);
}
}
@@ -5630,6 +5630,7 @@
method public boolean onException(Object, Throwable);
method public void onStart();
method public void removeMonitor(android.app.Instrumentation.ActivityMonitor);
+ method public void resetInTouchMode();
method public void runOnMainSync(Runnable);
method public void sendCharacterSync(int);
method public void sendKeyDownUpSync(int);
@@ -6644,6 +6645,15 @@
public final class PictureInPictureParams implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.List<android.app.RemoteAction> getActions();
+ method @Nullable public android.util.Rational getAspectRatio();
+ method @Nullable public android.app.RemoteAction getCloseAction();
+ method @Nullable public android.util.Rational getExpandedAspectRatio();
+ method @Nullable public android.graphics.Rect getSourceRectHint();
+ method @Nullable public CharSequence getSubtitle();
+ method @Nullable public CharSequence getTitle();
+ method public boolean isAutoEnterEnabled();
+ method public boolean isSeamlessResizeEnabled();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.PictureInPictureParams> CREATOR;
}
@@ -11300,6 +11310,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+ method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
}
@@ -16407,12 +16418,8 @@
package android.graphics.text {
public final class LineBreakConfig {
- ctor public LineBreakConfig();
method public int getLineBreakStyle();
method public int getLineBreakWordStyle();
- method public void set(@NonNull android.graphics.text.LineBreakConfig);
- method public void setLineBreakStyle(int);
- method public void setLineBreakWordStyle(int);
field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
@@ -16421,6 +16428,13 @@
field public static final int LINE_BREAK_WORD_STYLE_PHRASE = 1; // 0x1
}
+ public static final class LineBreakConfig.Builder {
+ ctor public LineBreakConfig.Builder();
+ method @NonNull public android.graphics.text.LineBreakConfig build();
+ method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakStyle(int);
+ method @NonNull public android.graphics.text.LineBreakConfig.Builder setLineBreakWordStyle(int);
+ }
+
public class LineBreaker {
method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -17408,7 +17422,7 @@
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES;
- field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES;
+ field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SCALER_DEFAULT_SECURE_IMAGE_SIZE;
field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS;
@@ -18193,7 +18207,7 @@
method public int get10BitFormat();
method @NonNull public java.util.List<android.util.Size> getAvailableSizes();
method public int getFormat();
- method public int getStreamUseCase();
+ method public long getStreamUseCase();
method public boolean is10BitCapable();
method public boolean isInput();
method public boolean isMaximumSize();
@@ -18251,7 +18265,7 @@
method public long getDynamicRangeProfile();
method public int getMaxSharedSurfaceCount();
method public int getMirrorMode();
- method public int getStreamUseCase();
+ method public long getStreamUseCase();
method @Nullable public android.view.Surface getSurface();
method public int getSurfaceGroupId();
method @NonNull public java.util.List<android.view.Surface> getSurfaces();
@@ -18261,7 +18275,7 @@
method public void setDynamicRangeProfile(long);
method public void setMirrorMode(int);
method public void setPhysicalCameraId(@Nullable String);
- method public void setStreamUseCase(int);
+ method public void setStreamUseCase(long);
method public void setTimestampBase(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.camera2.params.OutputConfiguration> CREATOR;
@@ -25177,17 +25191,23 @@
}
public final class CommandRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
- ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String);
+ ctor public CommandRequest(int, int, @NonNull String, @NonNull String, @NonNull String, @NonNull String);
+ method @NonNull public String getArgumentType();
method @NonNull public String getArguments();
method @NonNull public String getName();
- method @NonNull public String getNameSpace();
+ method @NonNull public String getNamespace();
+ field public static final String ARGUMENT_TYPE_JSON = "json";
+ field public static final String ARGUMENT_TYPE_XML = "xml";
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandRequest> CREATOR;
}
public final class CommandResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
- ctor public CommandResponse(int, int, int, @Nullable String);
+ ctor public CommandResponse(int, int, int, @Nullable String, @NonNull String);
method @Nullable public String getResponse();
+ method @NonNull public String getResponseType();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.CommandResponse> CREATOR;
+ field public static final String RESPONSE_TYPE_JSON = "json";
+ field public static final String RESPONSE_TYPE_XML = "xml";
}
public final class DsmccRequest extends android.media.tv.BroadcastInfoRequest implements android.os.Parcelable {
@@ -25252,7 +25272,7 @@
ctor public StreamEventResponse(int, int, int, int, long, @Nullable byte[]);
method @Nullable public byte[] getData();
method public int getEventId();
- method public long getNpt();
+ method public long getNptMillis();
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.StreamEventResponse> CREATOR;
}
@@ -25282,7 +25302,7 @@
public final class TimelineResponse extends android.media.tv.BroadcastInfoResponse implements android.os.Parcelable {
ctor public TimelineResponse(int, int, int, @Nullable String, int, int, long, long);
- method @Nullable public String getSelector();
+ method @Nullable public android.net.Uri getSelector();
method public long getTicks();
method public int getUnitsPerSecond();
method public int getUnitsPerTick();
@@ -43782,6 +43802,7 @@
method public int getNetworkTypeBitmask();
method public String getOperatorNumeric();
method public String getPassword();
+ method public int getProfileId();
method public int getProtocol();
method @Deprecated public java.net.InetAddress getProxyAddress();
method public String getProxyAddressAsString();
@@ -43789,6 +43810,7 @@
method public int getRoamingProtocol();
method public String getUser();
method public boolean isEnabled();
+ method public boolean isPersistent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUTH_TYPE_CHAP = 2; // 0x2
field public static final int AUTH_TYPE_NONE = 0; // 0x0
@@ -45062,7 +45084,7 @@
public static final class PrecomputedText.Params {
method public int getBreakStrategy();
method public int getHyphenationFrequency();
- method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig();
+ method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
method @NonNull public android.text.TextDirectionHeuristic getTextDirection();
method @NonNull public android.text.TextPaint getTextPaint();
}
@@ -57352,7 +57374,8 @@
method public final android.text.Layout getLayout();
method public float getLetterSpacing();
method public int getLineBounds(int, android.graphics.Rect);
- method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
+ method public int getLineBreakStyle();
+ method public int getLineBreakWordStyle();
method public int getLineCount();
method public int getLineHeight();
method public float getLineSpacingExtra();
@@ -57480,7 +57503,8 @@
method public void setKeyListener(android.text.method.KeyListener);
method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
method public void setLetterSpacing(float);
- method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
+ method public void setLineBreakStyle(int);
+ method public void setLineBreakWordStyle(int);
method public void setLineHeight(@IntRange(from=0) @Px int);
method public void setLineSpacing(float, float);
method public void setLines(int);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 3d5232b..d2cc0f5 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -243,7 +243,8 @@
method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningOrLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached();
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 09d1114..5df9881 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1114,6 +1114,7 @@
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setStrings(@NonNull java.util.Set<android.app.admin.DevicePolicyStringResource>);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE = "android.app.action.BIND_SECONDARY_LOCKSCREEN_SERVICE";
@@ -1128,7 +1129,7 @@
field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE = "android.app.action.ROLE_HOLDER_PROVISION_MANAGED_PROFILE";
field public static final String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field @Deprecated public static final String ACTION_STATE_USER_SETUP_COMPLETE = "android.app.action.STATE_USER_SETUP_COMPLETE";
- field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+ field @RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP) public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER = "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_LOST_MODE_LOCATION = "android.app.extra.LOST_MODE_LOCATION";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
@@ -1161,8 +1162,8 @@
field public static final String REQUIRED_APP_MANAGED_PROFILE = "android.app.REQUIRED_APP_MANAGED_PROFILE";
field public static final String REQUIRED_APP_MANAGED_USER = "android.app.REQUIRED_APP_MANAGED_USER";
field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
- field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
- field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
+ field public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
field public static final int RESULT_WORK_PROFILE_CREATED = 122; // 0x7a
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
@@ -3192,6 +3193,7 @@
}
public class CrossProfileApps {
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES}) public void startActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
}
@@ -9791,6 +9793,7 @@
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();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isPrimaryUser();
+ method public static boolean isRemoveResultSuccessful(int);
method public boolean isRestrictedProfile();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}, conditional=true) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle);
@@ -9808,7 +9811,10 @@
field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
field public static final int REMOVE_RESULT_ALREADY_BEING_REMOVED = 2; // 0x2
field public static final int REMOVE_RESULT_DEFERRED = 1; // 0x1
- field public static final int REMOVE_RESULT_ERROR = 3; // 0x3
+ field public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4; // 0xfffffffc
+ field public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1; // 0xffffffff
+ field public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3; // 0xfffffffd
+ field public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2; // 0xfffffffe
field public static final int REMOVE_RESULT_REMOVED = 0; // 0x0
field public static final int RESTRICTION_NOT_SET = 0; // 0x0
field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
@@ -10859,10 +10865,11 @@
}
public static final class AmbientContextDetectionResult.Builder {
- ctor public AmbientContextDetectionResult.Builder();
+ ctor public AmbientContextDetectionResult.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvent(@NonNull android.app.ambientcontext.AmbientContextEvent);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder addEvents(@NonNull java.util.List<android.app.ambientcontext.AmbientContextEvent>);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder setPackageName(@NonNull String);
+ method @NonNull public android.service.ambientcontext.AmbientContextDetectionResult.Builder clearEvents();
}
public abstract class AmbientContextDetectionService extends android.app.Service {
@@ -10883,9 +10890,8 @@
}
public static final class AmbientContextDetectionServiceStatus.Builder {
- ctor public AmbientContextDetectionServiceStatus.Builder();
+ ctor public AmbientContextDetectionServiceStatus.Builder(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus build();
- method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setPackageName(@NonNull String);
method @NonNull public android.service.ambientcontext.AmbientContextDetectionServiceStatus.Builder setStatusCode(int);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 66f893d..2e8bed3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -96,7 +96,7 @@
package android.animation {
public class ValueAnimator extends android.animation.Animator {
- method @MainThread public static void setDurationScale(@FloatRange(from=0, to=1) float);
+ method @MainThread public static void setDurationScale(@FloatRange(from=0) float);
}
}
@@ -356,14 +356,8 @@
}
public final class PictureInPictureParams implements android.os.Parcelable {
- method public java.util.List<android.app.RemoteAction> getActions();
- method public float getAspectRatio();
- method @Nullable public android.app.RemoteAction getCloseAction();
- method public float getExpandedAspectRatio();
- method public android.graphics.Rect getSourceRectHint();
- method @Nullable public CharSequence getSubtitle();
- method @Nullable public CharSequence getTitle();
- method public boolean isSeamlessResizeEnabled();
+ method public float getAspectRatioFloat();
+ method public float getExpandedAspectRatioFloat();
}
public final class PictureInPictureUiState implements android.os.Parcelable {
diff --git a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
index 4e6cfb35..f53cfe4 100644
--- a/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityShortcutInfo.java
@@ -169,10 +169,6 @@
mIntroResId = asAttributes.getResourceId(
com.android.internal.R.styleable.AccessibilityShortcutTarget_intro, 0);
asAttributes.recycle();
-
- if ((mDescriptionResId == 0 && mHtmlDescriptionRes == 0) || mSummaryResId == 0) {
- throw new XmlPullParserException("No description or summary in meta-data");
- }
} catch (PackageManager.NameNotFoundException e) {
throw new XmlPullParserException("Unable to create context for: "
+ mActivityInfo.packageName);
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index bca6b6a..6ab7ae6 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -316,7 +316,7 @@
@UnsupportedAppUsage
@TestApi
@MainThread
- public static void setDurationScale(@FloatRange(from = 0, to = 1) float durationScale) {
+ public static void setDurationScale(@FloatRange(from = 0) float durationScale) {
sDurationScale = durationScale;
List<WeakReference<DurationScaleChangeListener>> listenerCopy;
@@ -340,7 +340,7 @@
*
* @return the duration scale.
*/
- @FloatRange(from = 0, to = 1)
+ @FloatRange(from = 0)
public static float getDurationScale() {
return sDurationScale;
}
@@ -1798,8 +1798,8 @@
public interface DurationScaleChangeListener {
/**
* Called when the duration scale changes.
- * @param scale the duration scalel
+ * @param scale the duration scale
*/
- void onChanged(float scale);
+ void onChanged(@FloatRange(from = 0) float scale);
}
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e0c69df..ac979c4 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -393,6 +393,15 @@
}
/**
+ * Resets the {@link #setInTouchMode touch mode} to the device default.
+ */
+ public void resetInTouchMode() {
+ final boolean defaultInTouchMode = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_defaultInTouchMode);
+ setInTouchMode(defaultInTouchMode);
+ }
+
+ /**
* Schedule a callback for when the application's main thread goes idle
* (has no more events to process).
*
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 2d2788c..3f1844e 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -280,7 +280,7 @@
private Rational mAspectRatio;
/**
- * The expected aspect ratio of the vertically expanded picture-in-picture window.
+ * The expected aspect ratio of the expanded picture-in-picture window.
*/
@Nullable
private Rational mExpandedAspectRatio;
@@ -441,15 +441,21 @@
* @hide
*/
@TestApi
- public float getAspectRatio() {
+ public float getAspectRatioFloat() {
if (mAspectRatio != null) {
return mAspectRatio.floatValue();
}
return 0f;
}
- /** @hide */
- public Rational getAspectRatioRational() {
+ /**
+ * Returns the expected aspect ratio of the picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getAspectRatio() {
return mAspectRatio;
}
@@ -466,7 +472,7 @@
* @hide
*/
@TestApi
- public float getExpandedAspectRatio() {
+ public float getExpandedAspectRatioFloat() {
if (mExpandedAspectRatio != null) {
return mExpandedAspectRatio.floatValue();
}
@@ -474,6 +480,17 @@
}
/**
+ * Returns the desired aspect ratio of the expanded picture-in-picture window.
+ *
+ * @return aspect ratio as the desired width / height or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setExpandedAspectRatio(Rational)
+ */
+ @Nullable
+ public Rational getExpandedAspectRatio() {
+ return mExpandedAspectRatio;
+ }
+
+ /**
* @return whether the expanded aspect ratio is set
* @hide
*/
@@ -482,11 +499,17 @@
}
/**
- * @return the set of user actions.
- * @hide
+ * Returns the list of user actions that are associated with the activity when in
+ * picture-in-picture mode.
+ *
+ * @return the user actions in a new list.
+ * @see PictureInPictureParams.Builder#setActions(List)
*/
- @TestApi
+ @NonNull
public List<RemoteAction> getActions() {
+ if (mUserActions == null) {
+ return new ArrayList<>();
+ }
return mUserActions;
}
@@ -499,10 +522,11 @@
}
/**
- * @return the close action.
- * @hide
+ * Returns the action that is to replace the system close action.
+ *
+ * @return the close action or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setCloseAction(RemoteAction)
*/
- @TestApi
@Nullable
public RemoteAction getCloseAction() {
return mCloseAction;
@@ -528,10 +552,12 @@
}
/**
- * @return the source rect hint
- * @hide
+ * Returns the source rect hint.
+ *
+ * @return the source rect hint also known as launch bounds or {@code null} if not set.
+ * @see PictureInPictureParams.Builder#setSourceRectHint(Rect)
*/
- @TestApi
+ @Nullable
public Rect getSourceRectHint() {
return mSourceRectHint;
}
@@ -545,18 +571,23 @@
}
/**
- * @return whether auto pip is enabled.
- * @hide
+ * Returns whether auto enter picture-in-picture is enabled.
+ *
+ * @return {@code true} if the system will automatically put the activity in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setAutoEnterEnabled(boolean)
*/
public boolean isAutoEnterEnabled() {
return mAutoEnterEnabled == null ? false : mAutoEnterEnabled;
}
/**
- * @return whether seamless resize is enabled.
- * @hide
+ * Returns whether seamless resize is enabled.
+ *
+ * @return true if the system can seamlessly resize the window while activity is in
+ * picture-in-picture mode.
+ * @see PictureInPictureParams.Builder#setSeamlessResizeEnabled(boolean)
*/
- @TestApi
public boolean isSeamlessResizeEnabled() {
return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled;
}
@@ -570,10 +601,11 @@
}
/**
- * @return title of the pip.
- * @hide
+ * Returns the title of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return title of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setTitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getTitle() {
return mTitle;
@@ -588,10 +620,11 @@
}
/**
- * @return subtitle of the pip.
- * @hide
+ * Returns the subtitle of the picture-in-picture window that may be displayed to the user.
+ *
+ * @return subtitle of the picture-in-picture window.
+ * @see PictureInPictureParams.Builder#setSubtitle(CharSequence)
*/
- @TestApi
@Nullable
public CharSequence getSubtitle() {
return mSubtitle;
@@ -716,7 +749,7 @@
@Override
public String toString() {
return "PictureInPictureParams("
- + " aspectRatio=" + getAspectRatioRational()
+ + " aspectRatio=" + getAspectRatio()
+ " expandedAspectRatio=" + mExpandedAspectRatio
+ " sourceRectHint=" + getSourceRectHint()
+ " hasSetActions=" + hasSetActions()
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index bf6f634..6615374 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -154,6 +154,7 @@
import android.net.wifi.WifiFrameworkInitializer;
import android.net.wifi.nl80211.WifiNl80211Manager;
import android.nfc.NfcManager;
+import android.ondevicepersonalization.OnDevicePersonalizationFrameworkInitializer;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryStatsManager;
@@ -1560,6 +1561,7 @@
SafetyCenterFrameworkInitializer.registerServiceWrappers();
ConnectivityFrameworkInitializerTiramisu.registerServiceWrappers();
NearbyFrameworkInitializer.registerServiceWrappers();
+ OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4c7b910..7269b0d 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -719,10 +719,11 @@
/**
* A {@code boolean} extra which determines whether to force a role holder update, regardless
- * of any internal conditions {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER} might have.
+ * of any internal conditions {@link #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} might
+ * have.
*
* <p>This extra can be provided to intents with action {@link
- * #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}.
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER}.
*
* @hide
*/
@@ -3281,39 +3282,43 @@
*
* <p>The activity must handle the device policy management role holder update and set the
* intent result to either {@link Activity#RESULT_OK} if the update was successful, {@link
- * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a problem
- * that may be solved by relaunching it again, or {@link
- * #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a problem
- * that will not be solved by relaunching it again.
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR} if it encounters a
+ * problem that may be solved by relaunching it again, or {@link
+ * #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a
+ * problem that will not be solved by relaunching it again.
*
* <p>If this activity has additional internal conditions which are not met, it should return
- * {@link #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
+ * {@link #RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
*
* @hide
*/
@RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP)
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
@SystemApi
- public static final String ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER =
- "android.app.action.UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER";
+ public static final String ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER =
+ "android.app.action.UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER";
/**
- * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
- * handler if it encounters a problem that may be solved by relaunching it again.
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem
+ * that may be solved by relaunching it again.
*
* @hide
*/
@SystemApi
- public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1;
+ public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR =
+ 1;
/**
- * Result code that can be returned by the {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}
- * handler if it encounters a problem that will not be solved by relaunching it again.
+ * Result code that can be returned by the {@link
+ * #ACTION_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER} handler if it encounters a problem that
+ * will not be solved by relaunching it again.
*
* @hide
*/
@SystemApi
- public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2;
+ public static final int RESULT_UPDATE_DEVICE_POLICY_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR =
+ 2;
/**
* An {@link Intent} extra which resolves to a custom user consent screen.
@@ -15760,4 +15765,23 @@
}
return deviceManagerConfig;
}
+
+ /**
+ * @return {@code true} if bypassing the device policy management role qualification is allowed
+ * with the current state of the device.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ if (mService != null) {
+ try {
+ return mService.shouldAllowBypassingDevicePolicyManagementRoleQualification();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 77db146..fb1ca41 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -558,4 +558,6 @@
void setStrings(in List<DevicePolicyStringResource> strings);
void resetStrings(in String[] stringIds);
ParcelableResource getString(String stringId);
+
+ boolean shouldAllowBypassingDevicePolicyManagementRoleQualification();
}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 94f0561..b6917e26 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -104,7 +104,44 @@
mContext.getAttributionTag(),
component,
targetUser.getIdentifier(),
- true);
+ true,
+ null,
+ null);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts the specified main activity of the caller package in the specified profile, launching
+ * in the specified activity.
+ *
+ * @param component The ComponentName of the activity to launch, it must be exported and has
+ * action {@link android.content.Intent#ACTION_MAIN}, category
+ * {@link android.content.Intent#CATEGORY_LAUNCHER}. Otherwise, SecurityException will
+ * be thrown.
+ * @param targetUser The UserHandle of the profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ */
+ public void startMainActivity(@NonNull ComponentName component,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
+ try {
+ mService.startActivityAsUser(
+ mContext.getIApplicationThread(),
+ mContext.getPackageName(),
+ mContext.getAttributionTag(),
+ component,
+ targetUser.getIdentifier(),
+ true,
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -191,6 +228,48 @@
* @param targetUser The UserHandle of the profile, must be one of the users returned by
* {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
* be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.START_CROSS_PROFILE_ACTIVITIES})
+ public void startActivity(
+ @NonNull ComponentName component,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
+ try {
+ mService.startActivityAsUser(
+ mContext.getIApplicationThread(),
+ mContext.getPackageName(),
+ mContext.getAttributionTag(),
+ component,
+ targetUser.getIdentifier(),
+ false,
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts the specified activity of the caller package in the specified profile. Unlike
+ * {@link #startMainActivity}, this can start any activity of the caller package, not just
+ * the main activity.
+ * The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
+ * or {@link android.Manifest.permission#START_CROSS_PROFILE_ACTIVITIES}
+ * permission and both the caller and target user profiles must be in the same profile group.
+ *
+ * @param component The ComponentName of the activity to launch. It must be exported.
+ * @param targetUser The UserHandle of the profile, must be one of the users returned by
+ * {@link #getTargetUserProfiles()}, otherwise a {@link SecurityException} will
+ * be thrown.
* @hide
*/
@SystemApi
@@ -201,7 +280,7 @@
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
mContext.getPackageName(), mContext.getAttributionTag(), component,
- targetUser.getIdentifier(), false);
+ targetUser.getIdentifier(), false, null, null);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index e2850f1..4f2c106 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -29,7 +29,7 @@
interface ICrossProfileApps {
void startActivityAsUser(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in ComponentName component, int userId,
- boolean launchMainActivity);
+ boolean launchMainActivity, in IBinder task, in Bundle options);
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity,
in Bundle options);
diff --git a/core/java/android/hardware/CameraStreamStats.java b/core/java/android/hardware/CameraStreamStats.java
index 7b24cc4..3952467 100644
--- a/core/java/android/hardware/CameraStreamStats.java
+++ b/core/java/android/hardware/CameraStreamStats.java
@@ -49,7 +49,7 @@
private float[] mHistogramBins;
private long[] mHistogramCounts;
private long mDynamicRangeProfile;
- private int mStreamUseCase;
+ private long mStreamUseCase;
private static final String TAG = "CameraStreamStats";
@@ -73,7 +73,7 @@
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) {
+ long streamUseCase) {
mWidth = width;
mHeight = height;
mFormat = format;
@@ -135,7 +135,7 @@
dest.writeFloatArray(mHistogramBins);
dest.writeLongArray(mHistogramCounts);
dest.writeLong(mDynamicRangeProfile);
- dest.writeInt(mStreamUseCase);
+ dest.writeLong(mStreamUseCase);
}
public void readFromParcel(Parcel in) {
@@ -154,7 +154,7 @@
mHistogramBins = in.createFloatArray();
mHistogramCounts = in.createLongArray();
mDynamicRangeProfile = in.readLong();
- mStreamUseCase = in.readInt();
+ mStreamUseCase = in.readLong();
}
public int getWidth() {
@@ -217,7 +217,7 @@
return mDynamicRangeProfile;
}
- public int getStreamUseCase() {
+ public long getStreamUseCase() {
return mStreamUseCase;
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7bebe1f..b05e6d1 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3563,8 +3563,8 @@
*/
@PublicKey
@NonNull
- public static final Key<int[]> SCALER_AVAILABLE_STREAM_USE_CASES =
- new Key<int[]>("android.scaler.availableStreamUseCases", int[].class);
+ public static final Key<long[]> SCALER_AVAILABLE_STREAM_USE_CASES =
+ new Key<long[]>("android.scaler.availableStreamUseCases", long[].class);
/**
* <p>An array of mandatory stream combinations with stream use cases.
diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
index 465abfb..a3bc665 100644
--- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
+++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java
@@ -66,7 +66,7 @@
private final boolean mIsUltraHighResolution;
private final boolean mIsMaximumSize;
private final boolean mIs10BitCapable;
- private final int mStreamUseCase;
+ private final long mStreamUseCase;
/**
* Create a new {@link MandatoryStreamInformation}.
@@ -168,7 +168,7 @@
*/
public MandatoryStreamInformation(@NonNull List<Size> availableSizes, @Format int format,
boolean isMaximumSize, boolean isInput, boolean isUltraHighResolution,
- boolean is10BitCapable, @StreamUseCase int streamUseCase) {
+ boolean is10BitCapable, @StreamUseCase long streamUseCase) {
if (availableSizes.isEmpty()) {
throw new IllegalArgumentException("No available sizes");
}
@@ -308,9 +308,9 @@
* For {@link MandatoryStreamInformation} belonging to other mandatory stream
* combinations, the return value will be DEFAULT. </p>
*
- * @return the integer stream use case.
+ * @return the long integer stream use case.
*/
- public @StreamUseCase int getStreamUseCase() {
+ public @StreamUseCase long getStreamUseCase() {
return mStreamUseCase;
}
@@ -365,15 +365,15 @@
/**
* Short hand for stream use cases
*/
- private static final int STREAM_USE_CASE_PREVIEW =
+ private static final long STREAM_USE_CASE_PREVIEW =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
- private static final int STREAM_USE_CASE_STILL_CAPTURE =
+ private static final long STREAM_USE_CASE_STILL_CAPTURE =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
- private static final int STREAM_USE_CASE_RECORD =
+ private static final long STREAM_USE_CASE_RECORD =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
- private static final int STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
+ private static final long STREAM_USE_CASE_PREVIEW_VIDEO_STILL =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
- private static final int STREAM_USE_CASE_VIDEO_CALL =
+ private static final long STREAM_USE_CASE_VIDEO_CALL =
CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
/**
@@ -471,12 +471,12 @@
private static final class StreamTemplate {
public int mFormat;
public SizeThreshold mSizeThreshold;
- public int mStreamUseCase;
+ public long mStreamUseCase;
public StreamTemplate(int format, SizeThreshold sizeThreshold) {
this(format, sizeThreshold, CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
}
public StreamTemplate(@Format int format, @NonNull SizeThreshold sizeThreshold,
- @StreamUseCase int streamUseCase) {
+ @StreamUseCase long streamUseCase) {
mFormat = format;
mSizeThreshold = sizeThreshold;
mStreamUseCase = streamUseCase;
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 2350b7c..39cb7f3 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -918,9 +918,9 @@
* @throws IllegalArgumentException If the streamUseCase isn't within the range of valid
* values.
*/
- public void setStreamUseCase(@StreamUseCase int streamUseCase) {
+ public void setStreamUseCase(@StreamUseCase long streamUseCase) {
// Verify that the value is in range
- int maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ long maxUseCaseValue = CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
if (streamUseCase > maxUseCaseValue &&
streamUseCase < CameraMetadata.SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START) {
throw new IllegalArgumentException("Not a valid stream use case value " +
@@ -938,7 +938,7 @@
*
* @return the currently set stream use case
*/
- public int getStreamUseCase() {
+ public long getStreamUseCase() {
return mStreamUseCase;
}
@@ -1067,7 +1067,7 @@
String physicalCameraId = source.readString();
boolean isMultiResolutionOutput = source.readInt() == 1;
int[] sensorPixelModesUsed = source.createIntArray();
- int streamUseCase = source.readInt();
+ long streamUseCase = source.readLong();
checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
long dynamicRangeProfile = source.readLong();
@@ -1218,7 +1218,7 @@
// writeList doesn't seem to work well with Integer list.
dest.writeIntArray(convertIntegerToIntList(mSensorPixelModesUsed));
dest.writeLong(mDynamicRangeProfile);
- dest.writeInt(mStreamUseCase);
+ dest.writeLong(mStreamUseCase);
dest.writeInt(mTimestampBase);
dest.writeInt(mMirrorMode);
}
@@ -1337,7 +1337,7 @@
// Dynamic range profile
private long mDynamicRangeProfile;
// Stream use case
- private int mStreamUseCase;
+ private long mStreamUseCase;
// Timestamp base
private int mTimestampBase;
// Mirroring mode
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 18ec8f5..2c2a703 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -580,6 +580,24 @@
}
/**
+ * Notifies that the specified {@link NetworkStatsProvider} has reached its warning threshold
+ * which was set through {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void notifyStatsProviderWarningReached() {
+ try {
+ mService.notifyStatsProviderWarningOrLimitReached();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies that the specified {@link NetworkStatsProvider} has reached its quota
* which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
* {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
@@ -590,7 +608,7 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void notifyStatsProviderWarningOrLimitReached() {
+ public void notifyStatsProviderLimitReached() {
try {
mService.notifyStatsProviderWarningOrLimitReached();
} catch (RemoteException e) {
diff --git a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
index 2dd3aaa1..5c9989e 100644
--- a/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
+++ b/core/java/android/net/netstats/NetworkStatsDataMigrationUtils.java
@@ -27,6 +27,7 @@
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import android.annotation.NonNull;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.net.NetworkIdentity;
import android.net.NetworkStatsCollection;
@@ -47,6 +48,8 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.ProtocolException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -76,6 +79,15 @@
*/
public static final String PREFIX_UID_TAG = "uid_tag";
+ /** @hide */
+ @StringDef(prefix = {"PREFIX_"}, value = {
+ PREFIX_XT,
+ PREFIX_UID,
+ PREFIX_UID_TAG,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Prefix {}
+
private static final HashMap<String, String> sPrefixLegacyFileNameMap =
new HashMap<String, String>() {{
put(PREFIX_XT, "netstats_xt.bin");
@@ -141,13 +153,13 @@
// Get /data/system/netstats_*.bin legacy files. Does not check for existence.
@NonNull
- private static File getLegacyBinFileForPrefix(@NonNull String prefix) {
+ private static File getLegacyBinFileForPrefix(@NonNull @Prefix String prefix) {
return new File(getPlatformSystemDir(), sPrefixLegacyFileNameMap.get(prefix));
}
// List /data/system/netstats/[xt|uid|uid_tag].<start>-<end> legacy files.
@NonNull
- private static ArrayList<File> getPlatformFileListForPrefix(@NonNull String prefix) {
+ private static ArrayList<File> getPlatformFileListForPrefix(@NonNull @Prefix String prefix) {
final ArrayList<File> list = new ArrayList<>();
final File platformFiles = new File(getPlatformBaseDir(), "netstats");
if (platformFiles.exists()) {
@@ -207,7 +219,7 @@
*/
@NonNull
public static NetworkStatsCollection readPlatformCollection(
- @NonNull String prefix, long bucketDuration) throws IOException {
+ @NonNull @Prefix String prefix, long bucketDuration) throws IOException {
final NetworkStatsCollection.Builder builder =
new NetworkStatsCollection.Builder(bucketDuration);
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index de76c8f..f4ca1b5 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -165,6 +165,7 @@
PROCESS_STATE_FOREGROUND,
PROCESS_STATE_BACKGROUND,
PROCESS_STATE_FOREGROUND_SERVICE,
+ PROCESS_STATE_CACHED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProcessState {
@@ -175,8 +176,9 @@
public static final int PROCESS_STATE_FOREGROUND = 1;
public static final int PROCESS_STATE_BACKGROUND = 2;
public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3;
+ public static final int PROCESS_STATE_CACHED = 4;
- public static final int PROCESS_STATE_COUNT = 4;
+ public static final int PROCESS_STATE_COUNT = 5;
private static final String[] sProcessStateNames = new String[PROCESS_STATE_COUNT];
@@ -186,6 +188,7 @@
sProcessStateNames[PROCESS_STATE_FOREGROUND] = "fg";
sProcessStateNames[PROCESS_STATE_BACKGROUND] = "bg";
sProcessStateNames[PROCESS_STATE_FOREGROUND_SERVICE] = "fgs";
+ sProcessStateNames[PROCESS_STATE_CACHED] = "cached";
}
private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 5f9fdbf..06c35b5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -680,6 +680,8 @@
return BatteryConsumer.PROCESS_STATE_BACKGROUND;
case BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE:
return BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
+ case BatteryStats.Uid.PROCESS_STATE_CACHED:
+ return BatteryConsumer.PROCESS_STATE_CACHED;
default:
return BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
}
@@ -2681,7 +2683,7 @@
public static final String[] RADIO_ACCESS_TECHNOLOGY_NAMES = {"Other", "LTE", "NR"};
/**
- * Returns the time in microseconds that the mobile radio has been active on a
+ * Returns the time in milliseconds that the mobile radio has been active on a
* given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
* transmission power level.
*
@@ -2700,6 +2702,46 @@
@ServiceState.FrequencyRange int frequencyRange, int signalStrength,
long elapsedRealtimeMs);
+ /**
+ * Returns the time in milliseconds that the mobile radio has been actively transmitting data on
+ * a given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+ * transmission power level.
+ *
+ * @param rat Radio Access Technology {@see RadioAccessTechnology}
+ * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+ * RADIO_ACCESS_TECHNOLOGY_NR. Use
+ * {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+ * Technologies.
+ * @param signalStrength the cellular signal strength. {@see CellSignalStrength#getLevel()}
+ * @param elapsedRealtimeMs current elapsed realtime
+ * @return time (in milliseconds) the mobile radio spent actively transmitting data in the
+ * specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+ * data unavailable.
+ * @hide
+ */
+ public abstract long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+ long elapsedRealtimeMs);
+
+ /**
+ * Returns the time in milliseconds that the mobile radio has been actively receiving data on a
+ * given Radio Access Technology (RAT), at a given frequency (NR RAT only), for a given
+ * transmission power level.
+ *
+ * @param rat Radio Access Technology {@see RadioAccessTechnology}
+ * @param frequencyRange frequency range {@see ServiceState.FrequencyRange}, only needed for
+ * RADIO_ACCESS_TECHNOLOGY_NR. Use
+ * {@link ServiceState.FREQUENCY_RANGE_UNKNOWN} for other Radio Access
+ * Technologies.
+ * @param elapsedRealtimeMs current elapsed realtime
+ * @return time (in milliseconds) the mobile radio spent actively receiving data in the
+ * specified state, while on battery. Returns {@link DURATION_UNAVAILABLE} if
+ * data unavailable.
+ * @hide
+ */
+ public abstract long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs);
+
static final String[] WIFI_SUPPL_STATE_NAMES = {
"invalid", "disconn", "disabled", "inactive", "scanning",
"authenticating", "associating", "associated", "4-way-handshake",
@@ -2720,6 +2762,13 @@
public static final long POWER_DATA_UNAVAILABLE = -1L;
/**
+ * Returned value if duration data is unavailable.
+ *
+ * {@hide}
+ */
+ public static final long DURATION_UNAVAILABLE = -1L;
+
+ /**
* Returns the battery consumption (in microcoulombs) of bluetooth, derived from on
* device power measurement data.
* Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
@@ -4093,6 +4142,10 @@
" Mmwave frequency (greater than 6GHz):\n"};
final String signalStrengthHeader =
" Signal Strength Time:\n";
+ final String txHeader =
+ " Tx Time:\n";
+ final String rxHeader =
+ " Rx Time: ";
final String[] signalStrengthDescription = new String[]{
" unknown: ",
" poor: ",
@@ -4144,6 +4197,29 @@
sb.append(")\n");
}
+ sb.append(prefix);
+ sb.append(txHeader);
+ for (int strength = 0; strength < numSignalStrength; strength++) {
+ final long timeMs = getActiveTxRadioDurationMs(rat, freqLvl, strength,
+ rawRealtimeMs);
+ if (timeMs <= 0) continue;
+ hasFreqData = true;
+ sb.append(prefix);
+ sb.append(signalStrengthDescription[strength]);
+ formatTimeMs(sb, timeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(timeMs, totalActiveTimesMs));
+ sb.append(")\n");
+ }
+
+ sb.append(prefix);
+ sb.append(rxHeader);
+ final long rxTimeMs = getActiveRxRadioDurationMs(rat, freqLvl, rawRealtimeMs);
+ formatTimeMs(sb, rxTimeMs);
+ sb.append("(");
+ sb.append(formatRatioLocked(rxTimeMs, totalActiveTimesMs));
+ sb.append(")\n");
+
if (hasFreqData) {
hasData = true;
pw.print(sb);
diff --git a/core/java/android/os/ParcelableHolder.java b/core/java/android/os/ParcelableHolder.java
index 368ee2d..a739ba3 100644
--- a/core/java/android/os/ParcelableHolder.java
+++ b/core/java/android/os/ParcelableHolder.java
@@ -179,7 +179,11 @@
* Read ParcelableHolder from a parcel.
*/
public void readFromParcel(@NonNull Parcel parcel) {
- this.mStability = parcel.readInt();
+ int wireStability = parcel.readInt();
+ if (this.mStability != wireStability) {
+ throw new IllegalArgumentException("Expected stability " + this.mStability
+ + " but got " + wireStability);
+ }
mParcelable = null;
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 6051712..522807b 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -292,6 +292,10 @@
procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
.FOREGROUND_SERVICE;
break;
+ case BatteryConsumer.PROCESS_STATE_CACHED:
+ procState = BatteryUsageStatsAtomsProto.BatteryConsumerData.PowerComponentUsageSlice
+ .CACHED;
+ break;
default:
throw new IllegalArgumentException("Unknown process state: " + processState);
}
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 77d1498..91d231e 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -119,6 +119,8 @@
skipEmptyComponents);
appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE,
skipEmptyComponents);
+ appendProcessStateData(sb, BatteryConsumer.PROCESS_STATE_CACHED,
+ skipEmptyComponents);
pw.print(sb);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 276578e..2448a05 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1703,12 +1703,40 @@
/**
* A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
- * an error occurred that prevented the user from being removed or set as ephemeral.
+ * an unknown error occurred that prevented the user from being removed or set as ephemeral.
*
* @hide
*/
@SystemApi
- public static final int REMOVE_RESULT_ERROR = 3;
+ public static final int REMOVE_RESULT_ERROR_UNKNOWN = -1;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * the user could not be removed due to a {@link #DISALLOW_REMOVE_MANAGED_PROFILE} or
+ * {@link #DISALLOW_REMOVE_USER} user restriction.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_USER_RESTRICTION = -2;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * user being removed does not exist.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_USER_NOT_FOUND = -3;
+
+ /**
+ * A response code from {@link #removeUserWhenPossible(UserHandle, boolean)} indicating that
+ * user being removed is a {@link UserHandle#SYSTEM} user which can't be removed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int REMOVE_RESULT_ERROR_SYSTEM_USER = -4;
/**
* Possible response codes from {@link #removeUserWhenPossible(UserHandle, boolean)}.
@@ -1719,7 +1747,10 @@
REMOVE_RESULT_REMOVED,
REMOVE_RESULT_DEFERRED,
REMOVE_RESULT_ALREADY_BEING_REMOVED,
- REMOVE_RESULT_ERROR,
+ REMOVE_RESULT_ERROR_USER_RESTRICTION,
+ REMOVE_RESULT_ERROR_USER_NOT_FOUND,
+ REMOVE_RESULT_ERROR_SYSTEM_USER,
+ REMOVE_RESULT_ERROR_UNKNOWN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface RemoveResult {}
@@ -4846,8 +4877,10 @@
* the {@link #DISALLOW_REMOVE_USER} or {@link #DISALLOW_REMOVE_MANAGED_PROFILE} restriction
*
* @return the {@link RemoveResult} code: {@link #REMOVE_RESULT_REMOVED},
- * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED}, or
- * {@link #REMOVE_RESULT_ERROR}.
+ * {@link #REMOVE_RESULT_DEFERRED}, {@link #REMOVE_RESULT_ALREADY_BEING_REMOVED},
+ * {@link #REMOVE_RESULT_ERROR_USER_RESTRICTION}, {@link #REMOVE_RESULT_ERROR_USER_NOT_FOUND},
+ * {@link #REMOVE_RESULT_ERROR_SYSTEM_USER}, or {@link #REMOVE_RESULT_ERROR_UNKNOWN}. All error
+ * codes have negative values.
*
* @hide
*/
@@ -4864,6 +4897,19 @@
}
/**
+ * Check if {@link #removeUserWhenPossible} returned a success code which means that the user
+ * has been removed or is slated for removal.
+ *
+ * @param result is {@link #RemoveResult} code return by {@link #removeUserWhenPossible}.
+ * @return {@code true} if it is a success code.
+ * @hide
+ */
+ @SystemApi
+ public static boolean isRemoveResultSuccessful(@RemoveResult int result) {
+ return result >= 0;
+ }
+
+ /**
* Updates the user's name.
*
* @param userId the user's integer id
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 7832dcc..c021c07 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -78,37 +78,10 @@
*/
String getMountedObbPath(in String rawPath) = 24;
/**
- * Decrypts any encrypted volumes.
- */
- int decryptStorage(in String password) = 26;
- /**
- * Encrypts storage.
- */
- int encryptStorage(int type, in String password) = 27;
- /**
- * Changes the encryption password.
- */
- int changeEncryptionPassword(int type, in String password) = 28;
- /**
* Returns list of all mountable volumes for the specified userId
*/
StorageVolume[] getVolumeList(int userId, in String callingPackage, int flags) = 29;
/**
- * Determines the encryption state of the volume.
- * @return a numerical value. See {@code ENCRYPTION_STATE_*} for possible
- * values.
- * Note that this has been replaced in most cases by the APIs in
- * StorageManager (see isEncryptable and below)
- * This is still useful to get the error state when encryption has failed
- * and CryptKeeper needs to throw up a screen advising the user what to do
- */
- int getEncryptionState() = 31;
- /**
- * Verify the encryption password against the stored volume. This method
- * may only be called by the system process.
- */
- int verifyEncryptionPassword(in String password) = 32;
- /**
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that it
* contains no relative "." or ".." paths or symlinks. Also ensures that
@@ -117,32 +90,6 @@
*/
void mkdirs(in String callingPkg, in String path) = 34;
/**
- * Determines the type of the encryption password
- * @return PasswordType
- */
- int getPasswordType() = 35;
- /**
- * Get password from vold
- * @return password or empty string
- */
- String getPassword() = 36;
- /**
- * Securely clear password from vold
- */
- oneway void clearPassword() = 37;
- /**
- * Set a field in the crypto header.
- * @param field field to set
- * @param contents contents to set in field
- */
- oneway void setField(in String field, in String contents) = 38;
- /**
- * Gets a field from the crypto header.
- * @param field field to get
- * @return contents of field
- */
- String getField(in String field) = 39;
- /**
* Report the time of the last maintenance operation such as fstrim.
* @return Timestamp of the last maintenance operation, in the
* System.currentTimeMillis() time base
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 312abf8..9971cbc 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -3044,14 +3044,4 @@
public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
/** @hide */
public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
-
- // Constants for the data available via StorageManagerService.getField.
- /** @hide */
- public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
- /** @hide */
- public static final String OWNER_INFO_KEY = "OwnerInfo";
- /** @hide */
- public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
- /** @hide */
- public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 1008a2d..4731504 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -600,6 +600,13 @@
public static final String NAMESPACE_SELECTION_TOOLBAR = "selection_toolbar";
/**
+ * Definitions for voice interaction related functions.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_VOICE_INTERACTION = "voice_interaction";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
index 227194e..a216ed5 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionResult.java
@@ -26,6 +26,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Represents a {@code AmbientContextEvent} detection result reported by the detection service.
@@ -127,7 +128,9 @@
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -144,26 +147,37 @@
}
/**
- * The package to deliver the response to.
+ * Adds a list of events to the builder.
*/
- public @NonNull Builder setPackageName(@NonNull String value) {
+ public @NonNull Builder addEvents(@NonNull List<AmbientContextEvent> values) {
checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
+ if (mEvents == null) {
+ mBuilderFieldsSet |= 0x1;
+ mEvents = new ArrayList<>();
+ }
+ mEvents.addAll(values);
+ return this;
+ }
+
+ /**
+ * Clears all events from the builder.
+ */
+ public @NonNull Builder clearEvents() {
+ checkNotUsed();
+ if (mEvents != null) {
+ mEvents.clear();
+ }
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionResult build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mEvents = new ArrayList<>();
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionResult o = new AmbientContextDetectionResult(
mEvents,
mPackageName);
@@ -171,7 +185,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
index 6224aa1..8cf3411 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionService.java
@@ -134,12 +134,18 @@
}
/**
- * Starts detection and provides detected events to the statusConsumer. The ongoing detection
- * will keep running, until onStopDetection is called. If there were previously requested
- * detection from the same package, the previous request will be replaced with the new request.
- * The implementation should keep track of whether the user consented each requested
- * AmbientContextEvent for the app. If not consented, the statusConsumer should get a response
- * with STATUS_ACCESS_DENIED.
+ * Called when a client app requests starting detection of the events in the request. The
+ * implementation should keep track of whether the user has explicitly consented to detecting
+ * the events using on-going ambient sensor (e.g. microphone), and agreed to share the
+ * detection results with this client app. If the user has not consented, the detection
+ * should not start, and the statusConsumer should get a response with STATUS_ACCESS_DENIED.
+ * If the user has made the consent and the underlying services are available, the
+ * implementation should start detection and provide detected events to the
+ * detectionResultConsumer. If the type of event needs immediate attention, the implementation
+ * should send result as soon as detected. Otherwise, the implementation can bulk send response.
+ * The ongoing detection will keep running, until onStopDetection is called. If there were
+ * previously requested detection from the same package, regardless of the type of events in
+ * the request, the previous request will be replaced with the new request.
*
* @param request The request with events to detect.
* @param packageName the requesting app's package name
diff --git a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
index 3e92f39..199e674 100644
--- a/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
+++ b/core/java/android/service/ambientcontext/AmbientContextDetectionServiceStatus.java
@@ -24,6 +24,8 @@
import com.android.internal.util.AnnotationValidations;
+import java.util.Objects;
+
/**
* Represents a status for the {@code AmbientContextDetectionService}.
*
@@ -121,7 +123,9 @@
private @NonNull String mPackageName;
private long mBuilderFieldsSet = 0L;
- public Builder() {
+ public Builder(@NonNull String packageName) {
+ Objects.requireNonNull(packageName);
+ mPackageName = packageName;
}
/**
@@ -134,27 +138,14 @@
return this;
}
- /**
- * The package to deliver the response to.
- */
- public @NonNull Builder setPackageName(@NonNull String value) {
- checkNotUsed();
- mBuilderFieldsSet |= 0x2;
- mPackageName = value;
- return this;
- }
-
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull AmbientContextDetectionServiceStatus build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x2; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mStatusCode = AmbientContextManager.STATUS_UNKNOWN;
}
- if ((mBuilderFieldsSet & 0x2) == 0) {
- mPackageName = "";
- }
AmbientContextDetectionServiceStatus o = new AmbientContextDetectionServiceStatus(
mStatusCode,
mPackageName);
@@ -162,7 +153,7 @@
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x2) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index a2938a8..ef792d4 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -252,6 +252,7 @@
final InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities();
final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
final MergedConfiguration mMergedConfiguration = new MergedConfiguration();
+ final Bundle mSyncSeqIdBundle = new Bundle();
private final Point mSurfaceSize = new Point();
private final Point mLastSurfaceSize = new Point();
private final Matrix mTmpMatrix = new Matrix();
@@ -391,7 +392,7 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId) {
Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED,
reportDraw ? 1 : 0,
mergedConfiguration);
@@ -1151,7 +1152,7 @@
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
View.VISIBLE, 0, mWinFrames, mMergedConfiguration, mSurfaceControl,
- mInsetsState, mTempControls);
+ mInsetsState, mTempControls, mSyncSeqIdBundle);
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@@ -1338,7 +1339,8 @@
mSurfaceCreated = true;
if (redrawNeeded) {
resetWindowPages();
- mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */,
+ Integer.MAX_VALUE);
processLocalColors(mPendingXOffset, mPendingXOffsetStep);
notifyColorsChanged();
}
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 9307e56..f31a690 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -99,7 +99,7 @@
private final @Layout.HyphenationFrequency int mHyphenationFrequency;
// The line break configuration for calculating text wrapping.
- private final @Nullable LineBreakConfig mLineBreakConfig;
+ private final @NonNull LineBreakConfig mLineBreakConfig;
/**
* A builder for creating {@link Params}.
@@ -119,7 +119,7 @@
Layout.HYPHENATION_FREQUENCY_NORMAL;
// The line break configuration for calculating text wrapping.
- private @Nullable LineBreakConfig mLineBreakConfig;
+ private @NonNull LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
/**
* Builder constructor.
@@ -212,7 +212,7 @@
// For the external developers, use Builder instead.
/** @hide */
public Params(@NonNull TextPaint paint,
- @Nullable LineBreakConfig lineBreakConfig,
+ @NonNull LineBreakConfig lineBreakConfig,
@NonNull TextDirectionHeuristic textDir,
@Layout.BreakStrategy int strategy,
@Layout.HyphenationFrequency int frequency) {
@@ -260,11 +260,12 @@
}
/**
- * Return the line break configuration for this text.
+ * Returns the {@link LineBreakConfig} for this text.
*
- * @return the current line break configuration, null if no line break configuration is set.
+ * @return the current line break configuration. The {@link LineBreakConfig} with default
+ * values will be returned if no line break configuration is set.
*/
- public @Nullable LineBreakConfig getLineBreakConfig() {
+ public @NonNull LineBreakConfig getLineBreakConfig() {
return mLineBreakConfig;
}
@@ -297,9 +298,9 @@
/** @hide */
public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint,
@NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
- @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) {
+ @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) {
if (mBreakStrategy == strategy && mHyphenationFrequency == frequency
- && isLineBreakEquals(mLineBreakConfig, lbConfig)
+ && mLineBreakConfig.equals(lbConfig)
&& mPaint.equalsForTextMeasurement(paint)) {
return mTextDir == textDir ? USABLE : NEED_RECOMPUTE;
} else {
@@ -308,29 +309,6 @@
}
/**
- * Check the two LineBreakConfig instances are equal.
- * This method assumes they are equal if one parameter is null and the other parameter has
- * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE.
- *
- * @param o1 the first LineBreakConfig instance.
- * @param o2 the second LineBreakConfig instance.
- * @return true if the two LineBreakConfig instances are equal.
- */
- private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) {
- if (Objects.equals(o1, o2)) {
- return true;
- }
- if (o1 == null && (o2 != null
- && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
- return true;
- } else if (o2 == null && (o1 != null
- && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
- return true;
- }
- return false;
- }
-
- /**
* Check if the same text layout.
*
* @return true if this and the given param result in the same text layout
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b10fc37..2f85d2b6 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -112,6 +112,7 @@
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
+ b.mLineBreakConfig = LineBreakConfig.NONE;
return b;
}
@@ -410,7 +411,8 @@
*
* @param lineBreakConfig the line break configuration for text wrapping.
* @return this builder, useful for chaining.
- * @see android.widget.TextView#setLineBreakConfig
+ * @see android.widget.TextView#setLineBreakStyle
+ * @see android.widget.TextView#setLineBreakWordStyle
*/
@NonNull
public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
@@ -454,7 +456,7 @@
@Nullable private int[] mRightIndents;
private int mJustificationMode;
private boolean mAddLastLineLineSpacing;
- private LineBreakConfig mLineBreakConfig;
+ private LineBreakConfig mLineBreakConfig = LineBreakConfig.NONE;
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 34e7ea7..fe6ae78 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -96,7 +96,7 @@
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, "false");
+ DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
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_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index c1413be..190adbd 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -249,19 +249,19 @@
return;
}
- Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (handwritingArea != null) {
- if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
- startHandwriting(connectedView);
- }
+ final Rect handwritingArea = getViewHandwritingArea(connectedView);
+ if (contains(handwritingArea, mState.mStylusDownX, mState.mStylusDownY)) {
+ startHandwriting(connectedView);
+ } else {
+ reset();
}
- reset();
}
/** For test only. */
@VisibleForTesting
public void startHandwriting(@NonNull View view) {
mImm.startStylusHandwriting(view);
+ reset();
}
/**
@@ -287,7 +287,7 @@
final View connectedView = getConnectedView();
if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
final Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (handwritingArea != null && contains(handwritingArea, x, y)) {
+ if (contains(handwritingArea, x, y)) {
return connectedView;
}
}
@@ -298,8 +298,7 @@
for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
final View view = viewInfo.getView();
if (!view.isAutoHandwritingEnabled()) continue;
- final Rect rect = viewInfo.getHandwritingArea();
- if (rect != null && contains(rect, x, y)) {
+ if (contains(viewInfo.getHandwritingArea(), x, y)) {
return viewInfo.getView();
}
}
@@ -315,12 +314,15 @@
private static Rect getViewHandwritingArea(@NonNull View view) {
final ViewParent viewParent = view.getParent();
if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
- Rect handwritingArea = view.getHandwritingArea();
- if (handwritingArea == null) {
- handwritingArea = new Rect(0, 0, view.getWidth(), view.getHeight());
+ final Rect localHandwritingArea = view.getHandwritingArea();
+ final Rect globalHandwritingArea = new Rect();
+ if (localHandwritingArea != null) {
+ globalHandwritingArea.set(localHandwritingArea);
+ } else {
+ globalHandwritingArea.set(0, 0, view.getWidth(), view.getHeight());
}
- if (viewParent.getChildVisibleRect(view, handwritingArea, null)) {
- return handwritingArea;
+ if (viewParent.getChildVisibleRect(view, globalHandwritingArea, null)) {
+ return globalHandwritingArea;
}
}
return null;
@@ -329,7 +331,8 @@
/**
* Return true if the (x, y) is inside by the given {@link Rect}.
*/
- private boolean contains(@NonNull Rect rect, float x, float y) {
+ private boolean contains(@Nullable Rect rect, float x, float y) {
+ if (rect == null) return false;
return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
}
@@ -481,17 +484,18 @@
if (!mIsDirty) {
return true;
}
- final Rect localRect = view.getHandwritingArea();
- if (localRect == null) {
+ final Rect handwritingArea = view.getHandwritingArea();
+ if (handwritingArea == null) {
return false;
}
ViewParent parent = view.getParent();
if (parent != null) {
- final Rect newRect = new Rect(localRect);
- if (parent.getChildVisibleRect(view, newRect, null /* offset */)) {
- mHandwritingArea = newRect;
- } else {
+ if (mHandwritingArea == null) {
+ mHandwritingArea = new Rect();
+ }
+ mHandwritingArea.set(handwritingArea);
+ if (!parent.getChildVisibleRect(view, mHandwritingArea, null /* offset */)) {
mHandwritingArea = null;
}
}
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 12421ed..1f6cee6 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -55,7 +55,8 @@
void resized(in ClientWindowFrames frames, boolean reportDraw,
in MergedConfiguration newMergedConfiguration,
- boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId);
+ boolean forceLayout, boolean alwaysConsumeSystemBars, int displayId,
+ int syncSeqId);
/**
* Called when the window insets configuration has changed.
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 5c7c844..fd86900 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -104,7 +104,8 @@
int requestedWidth, int requestedHeight, int viewVisibility,
int flags, out ClientWindowFrames outFrames,
out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
- out InsetsState insetsState, out InsetsSourceControl[] activeControls);
+ out InsetsState insetsState, out InsetsSourceControl[] activeControls,
+ out Bundle bundle);
/*
* Notify the window manager that an application is relaunching and
@@ -142,7 +143,8 @@
* is null if there is no sync required.
*/
@UnsupportedAppUsage
- oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction);
+ oneway void finishDrawing(IWindow window, in SurfaceControl.Transaction postDrawTransaction,
+ int seqId);
@UnsupportedAppUsage
oneway void setInTouchMode(boolean showFocus);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 64f5668..f3c65ea 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -64,6 +64,7 @@
import android.view.Surface.OutOfResourcesException;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.VirtualRefBasePtr;
import dalvik.system.CloseGuard;
@@ -2961,6 +2962,8 @@
@NonNull
public Transaction setScale(@NonNull SurfaceControl sc, float scaleX, float scaleY) {
checkPreconditions(sc);
+ Preconditions.checkArgument(scaleX >= 0, "Negative value passed in for scaleX");
+ Preconditions.checkArgument(scaleY >= 0, "Negative value passed in for scaleY");
nativeSetScale(mNativeObject, sc.mNativeObject, scaleX, scaleY);
return this;
}
@@ -3205,6 +3208,7 @@
public @NonNull Transaction setCrop(@NonNull SurfaceControl sc, @Nullable Rect crop) {
checkPreconditions(sc);
if (crop != null) {
+ Preconditions.checkArgument(crop.isValid(), "Crop isn't valid.");
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
} else {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c222991..1b8dc70 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12016,7 +12016,6 @@
/**
* Return the handwriting areas set on this view, in its local coordinates.
- * Notice: the caller of this method should not modify the Rect returned.
* @see #setHandwritingArea(Rect)
*
* @hide
@@ -12025,7 +12024,7 @@
public Rect getHandwritingArea() {
final ListenerInfo info = mListenerInfo;
if (info != null) {
- return info.mHandwritingArea;
+ return new Rect(info.mHandwritingArea);
}
return null;
}
@@ -15617,7 +15616,7 @@
* @param event the KeyEvent object that defines the button action
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+ if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
@@ -15674,7 +15673,7 @@
* @param event The KeyEvent object that defines the button action.
*/
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
+ if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) {
if ((mViewFlags & ENABLED_MASK) == DISABLED) {
return true;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e79bdce..b72725a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -552,7 +552,6 @@
private final Rect mVisRect = new Rect(); // used to retrieve visible rect of focused view.
private final Rect mTempRect = new Rect();
- private final Rect mTempRect2 = new Rect();
private final WindowLayout mWindowLayout = new WindowLayout();
@@ -830,6 +829,24 @@
private int mLastTransformHint = Integer.MIN_VALUE;
+ /**
+ * A temporary object used so relayoutWindow can return the latest SyncSeqId
+ * system. The SyncSeqId system was designed to work without synchronous relayout
+ * window, and actually synchronous relayout window presents a problem. We could have
+ * a sequence like this:
+ * 1. We send MSG_RESIZED to the client with a new syncSeqId to begin a new sync
+ * 2. Due to scheduling the client executes performTraversals before calling MSG_RESIZED
+ * 3. Coincidentally for some random reason it also calls relayout
+ * 4. It observes the new state from relayout, and so the next frame will contain the state
+ * However it hasn't received the seqId yet, and so under the designed operation of
+ * seqId flowing through MSG_RESIZED, the next frame wouldn't be synced. Since it
+ * contains our target sync state, we need to sync it! This problem won't come up once
+ * we get rid of synchronous relayout, until then, we use this bundle to channel the
+ * integer back over relayout.
+ */
+ private Bundle mRelayoutBundle = new Bundle();
+ private int mSyncSeqId;
+
private String mTag = TAG;
public ViewRootImpl(Context context, Display display) {
@@ -1205,8 +1222,7 @@
displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
UNSPECIFIED_LENGTH, UNSPECIFIED_LENGTH,
mInsetsController.getRequestedVisibilities(),
- getAttachedWindowFrame(), 1f /* compactScale */,
- mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
+ getAttachedWindowFrame(), 1f /* compactScale */, mTmpFrames);
setFrame(mTmpFrames.frame);
registerBackCallbackOnWindow();
if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
@@ -1711,6 +1727,7 @@
mPendingBackDropFrame.set(backdropFrame);
mForceNextWindowRelayout = forceNextWindowRelayout;
mPendingAlwaysConsumeSystemBars = args.argi2 != 0;
+ mSyncSeqId = args.argi4;
if (msg == MSG_RESIZED_REPORT) {
reportNextDraw();
@@ -3148,11 +3165,8 @@
// possible that checking the most recent value is actually more
// correct here.
if (!mStopped || wasReportNextDraw) {
- boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
- (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
- if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
- || mHeight != host.getMeasuredHeight() || dispatchApplyInsets ||
- updatedConfiguration) {
+ if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
+ || dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
lp.privateFlags);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
@@ -4128,7 +4142,7 @@
mDrawsNeededToReport = 0;
try {
- mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction);
+ mWindowSession.finishDrawing(mWindow, mSurfaceChangedTransaction, Integer.MAX_VALUE);
} catch (RemoteException e) {
Log.e(mTag, "Unable to report draw finished", e);
mSurfaceChangedTransaction.apply();
@@ -8071,7 +8085,7 @@
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mTmpFrames, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
- mTempControls);
+ mTempControls, mRelayoutBundle);
final int transformHint = SurfaceControl.rotationToBufferTransform(
(mDisplayInstallOrientation + mDisplay.getRotation()) % 4);
@@ -8497,7 +8511,7 @@
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(
- mWindow, null /* postDrawTransaction */);
+ mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
}
} catch (RemoteException e) {
}
@@ -8571,7 +8585,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void dispatchResized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId) {
final Rect frame = frames.frame;
final Rect backDropFrame = frames.backdropFrame;
if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
@@ -8602,6 +8616,7 @@
args.argi1 = forceLayout ? 1 : 0;
args.argi2 = alwaysConsumeSystemBars ? 1 : 0;
args.argi3 = displayId;
+ args.argi4 = seqId;
msg.obj = args;
mHandler.sendMessage(msg);
}
@@ -9986,11 +10001,11 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
viewAncestor.dispatchResized(frames, reportDraw, mergedConfiguration, forceLayout,
- alwaysConsumeSystemBars, displayId);
+ alwaysConsumeSystemBars, displayId, seqId);
}
}
diff --git a/core/java/android/view/WindowLayout.java b/core/java/android/view/WindowLayout.java
index ad9f21b..a3b1313 100644
--- a/core/java/android/view/WindowLayout.java
+++ b/core/java/android/view/WindowLayout.java
@@ -42,6 +42,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.util.Log;
+import android.window.ClientWindowFrames;
/**
* Computes window frames.
@@ -56,15 +57,17 @@
private final Rect mTempDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private final Rect mTempRect = new Rect();
- public boolean computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
+ public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
int requestedWidth, int requestedHeight, InsetsVisibilities requestedVisibilities,
- Rect attachedWindowFrame, float compatScale, Rect outDisplayFrame, Rect outParentFrame,
- Rect outFrame) {
+ Rect attachedWindowFrame, float compatScale, ClientWindowFrames outFrames) {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
+ final Rect outDisplayFrame = outFrames.displayFrame;
+ final Rect outParentFrame = outFrames.parentFrame;
+ final Rect outFrame = outFrames.frame;
// Compute bounds restricted by insets
final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
@@ -95,7 +98,7 @@
final DisplayCutout cutout = state.getDisplayCutout();
final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
- boolean clippedByDisplayCutout = false;
+ outFrames.isParentFrameClippedByDisplayCutout = false;
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
// Ensure that windows with a non-ALWAYS display cutout mode are laid out in
// the cutout safe zone.
@@ -158,7 +161,7 @@
if (!attachedInParent && !floatingInScreenWindow) {
mTempRect.set(outParentFrame);
outParentFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
- clippedByDisplayCutout = !mTempRect.equals(outParentFrame);
+ outFrames.isParentFrameClippedByDisplayCutout = !mTempRect.equals(outParentFrame);
}
outDisplayFrame.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
}
@@ -287,9 +290,7 @@
}
if (DEBUG) Log.d(TAG, "computeWindowFrames " + attrs.getTitle()
- + " outFrame=" + outFrame.toShortString()
- + " outParentFrame=" + outParentFrame.toShortString()
- + " outDisplayFrame=" + outDisplayFrame.toShortString()
+ + " outFrames=" + outFrames
+ " windowBounds=" + windowBounds.toShortString()
+ " attachedWindowFrame=" + (attachedWindowFrame != null
? attachedWindowFrame.toShortString()
@@ -302,8 +303,6 @@
+ " attrs=" + attrs
+ " state=" + state
+ " requestedVisibilities=" + requestedVisibilities);
-
- return clippedByDisplayCutout;
}
public static void computeSurfaceSize(WindowManager.LayoutParams attrs, Rect maxBounds,
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 2dc5fbd..b0da877 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -60,47 +60,41 @@
private static boolean sUseBLASTAdapter = false;
/**
- * The user is navigating with keys (not the touch screen), so
- * navigational focus should be shown.
- */
- public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
-
- /**
* This is the first time the window is being drawn,
* so the client must call drawingFinished() when done
*/
- public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+ public static final int RELAYOUT_RES_FIRST_TIME = 1;
/**
* The window manager has changed the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
+ public static final int RELAYOUT_RES_SURFACE_CHANGED = 1 << 1;
/**
* The window is being resized by dragging on the docked divider. The client should render
* at (0, 0) and extend its background to the background frame passed into
* {@link IWindow#resized}.
*/
- public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 0x8;
+ public static final int RELAYOUT_RES_DRAG_RESIZING_DOCKED = 1 << 2;
/**
* The window is being resized by dragging one of the window corners,
* in this case the surface would be fullscreen-sized. The client should
* render to the actual frame location (instead of (0,curScrollY)).
*/
- public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 0x10;
+ public static final int RELAYOUT_RES_DRAG_RESIZING_FREEFORM = 1 << 3;
/**
* The window manager has changed the size of the surface from the last call.
*/
- public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x20;
+ public static final int RELAYOUT_RES_SURFACE_RESIZED = 1 << 4;
/**
* In multi-window we force show the system bars. Because we don't want that the surface size
* changes in this mode, we instead have a flag whether the system bar sizes should always be
* consumed, so the app is treated like there is no virtual system bars at all.
*/
- public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 0x40;
+ public static final int RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS = 1 << 5;
/**
* This flag indicates the client should not directly submit it's next frame,
@@ -108,7 +102,7 @@
* {@link WindowManagerService#finishDrawing}. This is used by the WM
* BLASTSyncEngine to synchronize rendering of multiple windows.
*/
- public static final int RELAYOUT_RES_BLAST_SYNC = 0x80;
+ public static final int RELAYOUT_RES_BLAST_SYNC = 1 << 6;
/**
* Flag for relayout: the client will be later giving
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index a270c92..06588b2 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -22,6 +22,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
@@ -217,9 +218,13 @@
throw new IllegalArgumentException(
"Invalid window token (never added or removed already)");
}
+ removeSurface(state.mSurfaceControl);
+ }
+ /** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
+ protected void removeSurface(SurfaceControl sc) {
try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
- t.remove(state.mSurfaceControl).apply();
+ t.remove(sc).apply();
}
}
@@ -277,7 +282,7 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
final State state;
synchronized (this) {
state = mStateForWindow.get(window.asBinder());
@@ -327,8 +332,7 @@
outInsetsState.set(mInsetsState);
}
- // Include whether the window is in touch mode.
- return isInTouchMode() ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
+ return 0;
}
@Override
@@ -354,7 +358,7 @@
@Override
public void finishDrawing(android.view.IWindow window,
- android.view.SurfaceControl.Transaction postDrawTransaction) {
+ android.view.SurfaceControl.Transaction postDrawTransaction, int seqId) {
synchronized (this) {
final ResizeCompleteCallback c =
mResizeCompletionForWindow.get(window.asBinder());
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a8cc114..3c5007b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -3121,17 +3121,19 @@
}
/**
- * If autofill suggestions for a dialog-style UI are available for {@code view}, shows a dialog
- * allowing the user to select a suggestion and returns {@code true}.
+ * If autofill suggestions for a
+ * <a href="{@docRoot}reference/android/service/autofill/Dataset.html#FillDialogUI">
+ * dialog-style UI</a> are available for {@code view}, shows a dialog allowing the user to
+ * select a suggestion and returns {@code true}.
* <p>
* The dialog may not be available if the autofill service does not support it, or if the
* autofill request has not returned a response yet.
* <p>
- * It is recommended to call this method the first time a user focuses on an autofill-able form,
- * and to avoid showing the input method if the dialog is shown. If this method returns
- * {@code false}, you should then instead show the input method (assuming that is how the
- * view normally handles the focus event). If the user re-focuses on the view, you should not
- * call this method again so as to not disrupt usage of the input method.
+ * It is recommended apps to call this method the first time a user focuses on
+ * an autofill-able form, and to avoid showing the input method if the dialog is shown. If
+ * this method returns {@code false}, you should then instead show the input method (assuming
+ * that is how the view normally handles the focus event). If the user re-focuses on the view,
+ * you should not call this method again so as to not disrupt usage of the input method.
*
* @param view the view for which to show autofill suggestions. This is typically a view
* receiving a focus event. The autofill suggestions shown will include content for
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b076d39..3c8fcb9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -788,7 +788,8 @@
private Layout mLayout;
private boolean mLocalesChanged = false;
private int mTextSizeUnit = -1;
- private LineBreakConfig mLineBreakConfig = new LineBreakConfig();
+ private int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
+ private int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
// This is used to reflect the current user preference for changing font weight and making text
// more bold.
@@ -1457,13 +1458,12 @@
break;
case com.android.internal.R.styleable.TextView_lineBreakStyle:
- mLineBreakConfig.setLineBreakStyle(
- a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE));
+ mLineBreakStyle = a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE);
break;
case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
- mLineBreakConfig.setLineBreakWordStyle(
- a.getInt(attr, LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE));
+ mLineBreakWordStyle = a.getInt(attr,
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
break;
case com.android.internal.R.styleable.TextView_autoSizeTextType:
@@ -4301,13 +4301,12 @@
@LineBreakConfig.LineBreakStyle int lineBreakStyle,
@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
boolean updated = false;
- if (isLineBreakStyleSpecified && mLineBreakConfig.getLineBreakStyle() != lineBreakStyle) {
- mLineBreakConfig.setLineBreakStyle(lineBreakStyle);
+ if (isLineBreakStyleSpecified && mLineBreakStyle != lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
updated = true;
}
- if (isLineBreakWordStyleSpecified
- && mLineBreakConfig.getLineBreakWordStyle() != lineBreakWordStyle) {
- mLineBreakConfig.setLineBreakWordStyle(lineBreakWordStyle);
+ if (isLineBreakWordStyleSpecified && mLineBreakWordStyle != lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
updated = true;
}
if (updated && mLayout != null) {
@@ -4871,50 +4870,72 @@
}
/**
- * Sets line break configuration indicates which strategy needs to be used when calculating the
- * text wrapping.
- * <P>
- * There are two types of line break rules that can be configured at the same time. One is
- * line break style(lb) and the other is line break word style(lw). The line break style
- * affects rule-based breaking. The line break word style affects dictionary-based breaking
- * and provide phrase-based breaking opportunities. There are several types for the
- * line break style:
+ * Set the line break style for text wrapping.
+ *
+ * The line break style to indicates the line break strategies can be used when
+ * calculating the text wrapping. The line break style affects rule-based breaking. It
+ * specifies the strictness of line-breaking rules.
+ * There are several types for the line break style:
* {@link LineBreakConfig#LINE_BREAK_STYLE_LOOSE},
* {@link LineBreakConfig#LINE_BREAK_STYLE_NORMAL} and
- * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}.
- * The type for the line break word style is
- * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}.
- * The default values of the line break style and the line break word style are
- * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE} and
- * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE} respectively, indicating that no line
- * breaking rules are specified.
- * See <a href="https://drafts.csswg.org/css-text/#line-break-property">
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}. The default values of the line break style
+ * is {@link LineBreakConfig#LINE_BREAK_STYLE_NONE}, indicating no breaking rule is specified.
+ * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">
* the line-break property</a>
*
- * @param lineBreakConfig the line break config for text wrapping.
+ * @param lineBreakStyle the line break style for the text.
*/
- public void setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
- Objects.requireNonNull(lineBreakConfig);
- if (mLineBreakConfig.equals(lineBreakConfig)) {
- return;
- }
- mLineBreakConfig.set(lineBreakConfig);
- if (mLayout != null) {
- nullLayouts();
- requestLayout();
- invalidate();
+ public void setLineBreakStyle(@LineBreakConfig.LineBreakStyle int lineBreakStyle) {
+ if (mLineBreakStyle != lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
}
}
/**
- * Get the current line break configuration for text wrapping.
+ * Set the line break word style for text wrapping.
*
- * @return the current line break configuration to be used for text wrapping.
+ * The line break word style affects dictionary-based breaking and provide phrase-based
+ * breaking opportunities. The type for the line break word style is
+ * {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_PHRASE}. The default values of the line break
+ * word style is {@link LineBreakConfig#LINE_BREAK_WORD_STYLE_NONE}, indicating no breaking rule
+ * is specified.
+ * See <a href="https://www.w3.org/TR/css-text-3/#word-break-property">
+ * the word-break property</a>
+ *
+ * @param lineBreakWordStyle the line break word style for the tet
*/
- public @NonNull LineBreakConfig getLineBreakConfig() {
- LineBreakConfig lbConfig = new LineBreakConfig();
- lbConfig.set(mLineBreakConfig);
- return lbConfig;
+ public void setLineBreakWordStyle(@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
+ if (mLineBreakWordStyle != lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+ }
+
+ /**
+ * Get the current line break style for text wrapping.
+ *
+ * @return the current line break style to be used for text wrapping.
+ */
+ public @LineBreakConfig.LineBreakStyle int getLineBreakStyle() {
+ return mLineBreakStyle;
+ }
+
+ /**
+ * Get the current line word break style for text wrapping.
+ *
+ * @return the current line break word style to be used for text wrapping.
+ */
+ public @LineBreakConfig.LineBreakWordStyle int getLineBreakWordStyle() {
+ return mLineBreakWordStyle;
}
/**
@@ -4924,7 +4945,8 @@
* @see PrecomputedText
*/
public @NonNull PrecomputedText.Params getTextMetricsParams() {
- return new PrecomputedText.Params(new TextPaint(mTextPaint), mLineBreakConfig,
+ return new PrecomputedText.Params(new TextPaint(mTextPaint),
+ LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle),
getTextDirectionHeuristic(),
mBreakStrategy, mHyphenationFrequency);
}
@@ -4941,13 +4963,9 @@
mTextDir = params.getTextDirection();
mBreakStrategy = params.getBreakStrategy();
mHyphenationFrequency = params.getHyphenationFrequency();
- if (params.getLineBreakConfig() != null) {
- mLineBreakConfig.set(params.getLineBreakConfig());
- } else {
- // Set default value if the line break config in the PrecomputedText.Params is null.
- mLineBreakConfig.setLineBreakStyle(DEFAULT_LINE_BREAK_STYLE);
- mLineBreakConfig.setLineBreakWordStyle(DEFAULT_LINE_BREAK_WORD_STYLE);
- }
+ LineBreakConfig lineBreakConfig = params.getLineBreakConfig();
+ mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
+ mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -6486,7 +6504,8 @@
}
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
- mHyphenationFrequency, mLineBreakConfig);
+ mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
throw new IllegalArgumentException(
@@ -9383,7 +9402,8 @@
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
if (shouldEllipsize) {
builder.setEllipsize(mEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9498,7 +9518,8 @@
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9866,7 +9887,8 @@
.setJustificationMode(getJustificationMode())
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
.setTextDirection(getTextDirectionHeuristic())
- .setLineBreakConfig(mLineBreakConfig);
+ .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
+ mLineBreakStyle, mLineBreakWordStyle));
final StaticLayout layout = layoutBuilder.build();
diff --git a/core/java/android/window/ClientWindowFrames.java b/core/java/android/window/ClientWindowFrames.java
index acf9882..5b915cc 100644
--- a/core/java/android/window/ClientWindowFrames.java
+++ b/core/java/android/window/ClientWindowFrames.java
@@ -27,47 +27,55 @@
*/
public class ClientWindowFrames implements Parcelable {
/** The actual window bounds. */
- public final @NonNull Rect frame;
+ public final @NonNull Rect frame = new Rect();
/**
* The container frame that is usually the same as display size. It may exclude the area of
* insets if the window layout parameter has specified fit-insets-sides.
*/
- public final @NonNull Rect displayFrame;
+ public final @NonNull Rect displayFrame = new Rect();
+
+ /**
+ * The frame to be referenced while applying gravity and MATCH_PARENT.
+ */
+ public final @NonNull Rect parentFrame = new Rect();
/** The background area while the window is resizing. */
- public final @NonNull Rect backdropFrame;
+ public final @NonNull Rect backdropFrame = new Rect();
+
+ public boolean isParentFrameClippedByDisplayCutout;
public ClientWindowFrames() {
- frame = new Rect();
- displayFrame = new Rect();
- backdropFrame = new Rect();
}
public ClientWindowFrames(ClientWindowFrames other) {
- frame = new Rect(other.frame);
- displayFrame = new Rect(other.displayFrame);
- backdropFrame = new Rect(other.backdropFrame);
+ frame.set(other.frame);
+ displayFrame.set(other.displayFrame);
+ parentFrame.set(other.parentFrame);
+ backdropFrame.set(other.backdropFrame);
+ isParentFrameClippedByDisplayCutout = other.isParentFrameClippedByDisplayCutout;
}
private ClientWindowFrames(Parcel in) {
- frame = Rect.CREATOR.createFromParcel(in);
- displayFrame = Rect.CREATOR.createFromParcel(in);
- backdropFrame = Rect.CREATOR.createFromParcel(in);
+ readFromParcel(in);
}
/** Needed for AIDL out parameters. */
public void readFromParcel(Parcel in) {
frame.readFromParcel(in);
displayFrame.readFromParcel(in);
+ parentFrame.readFromParcel(in);
backdropFrame.readFromParcel(in);
+ isParentFrameClippedByDisplayCutout = in.readBoolean();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
frame.writeToParcel(dest, flags);
displayFrame.writeToParcel(dest, flags);
+ parentFrame.writeToParcel(dest, flags);
backdropFrame.writeToParcel(dest, flags);
+ dest.writeBoolean(isParentFrameClippedByDisplayCutout);
}
@Override
@@ -75,7 +83,9 @@
final StringBuilder sb = new StringBuilder(32);
return "ClientWindowFrames{frame=" + frame.toShortString(sb)
+ " display=" + displayFrame.toShortString(sb)
- + " backdrop=" + backdropFrame.toShortString(sb) + "}";
+ + " parentFrame=" + parentFrame.toShortString(sb)
+ + " backdrop=" + backdropFrame.toShortString(sb)
+ + " parentClippedByDisplayCutout=" + isParentFrameClippedByDisplayCutout + "}";
}
@Override
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 5dbb551..d046cef 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -53,7 +53,7 @@
private static final String TAG = "WindowOnBackDispatcher";
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
/** Convenience hashmap to quickly decide if a callback has been added. */
private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 9e07f97..cb16267 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
+import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayDeque;
@@ -562,10 +563,21 @@
void unbindJobThread() {
cancelTimeout();
I service = mService;
+ // TODO(b/224695239): This is actually checking wasConnected. Rename and/or fix
+ // implementation based on what this should actually be checking. At least the first
+ // check for calling unbind is the correct behavior, though.
boolean wasBound = service != null;
+ if (wasBound || mBinding) {
+ try {
+ mContext.unbindService(mServiceConnection);
+ } catch (IllegalArgumentException e) { // TODO(b/224697137): Fix the race condition
+ // that requires catching this (crashes if
+ // service isn't currently bound).
+ Slog.e(LOG_TAG, "Failed to unbind: " + e);
+ }
+ }
if (wasBound) {
dispatchOnServiceConnectionStatusChanged(service, false);
- mContext.unbindService(mServiceConnection);
service.asBinder().unlinkToDeath(this, 0);
mService = null;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5253956..3b46f62 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -166,7 +166,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 206;
+ static final int VERSION = 207;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -964,6 +964,16 @@
* Timers for each combination of frequency range and signal strength.
*/
public final StopwatchTimer[][] perStateTimers;
+ /**
+ * Counters tracking the time (in milliseconds) spent transmitting data in a given state.
+ */
+ @Nullable
+ private LongSamplingCounter[][] mPerStateTxDurationMs = null;
+ /**
+ * Counters tracking the time (in milliseconds) spent receiving data in at given frequency.
+ */
+ @Nullable
+ private LongSamplingCounter[] mPerFrequencyRxDurationMs = null;
RadioAccessTechnologyBatteryStats(int freqCount, Clock clock, TimeBase timeBase) {
perStateTimers =
@@ -1024,15 +1034,198 @@
}
/**
- * Reset display timers.
+ * Returns the duration in milliseconds spent in a given state since the last mark.
+ */
+ public long getTimeSinceMark(@ServiceState.FrequencyRange int frequencyRange,
+ int signalStrength, long elapsedRealtimeMs) {
+ return perStateTimers[frequencyRange][signalStrength].getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ }
+
+ /**
+ * Set mark for all timers.
+ */
+ public void setMark(long elapsedRealtimeMs) {
+ final int size = perStateTimers.length;
+ for (int i = 0; i < size; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ perStateTimers[i][j].setMark(elapsedRealtimeMs);
+ }
+ }
+ }
+
+ /**
+ * Returns numbers of frequencies tracked for this RAT.
+ */
+ public int getFrequencyRangeCount() {
+ return perStateTimers.length;
+ }
+
+ /**
+ * Add TX time for a given state.
+ */
+ public void incrementTxDuration(@ServiceState.FrequencyRange int frequencyRange,
+ int signalStrength, long durationMs) {
+ getTxDurationCounter(frequencyRange, signalStrength, true).addCountLocked(durationMs);
+ }
+
+ /**
+ * Add TX time for a given frequency.
+ */
+ public void incrementRxDuration(@ServiceState.FrequencyRange int frequencyRange,
+ long durationMs) {
+ getRxDurationCounter(frequencyRange, true).addCountLocked(durationMs);
+ }
+
+ /**
+ * Reset radio access technology timers and counts.
*/
public void reset(long elapsedRealtimeUs) {
final int size = perStateTimers.length;
for (int i = 0; i < size; i++) {
for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
perStateTimers[i][j].reset(false, elapsedRealtimeUs);
+ if (mPerStateTxDurationMs == null) continue;
+ mPerStateTxDurationMs[i][j].reset(false, elapsedRealtimeUs);
+ }
+ if (mPerFrequencyRxDurationMs == null) continue;
+ mPerFrequencyRxDurationMs[i].reset(false, elapsedRealtimeUs);
+ }
+ }
+
+ /**
+ * Write data to summary parcel
+ */
+ public void writeSummaryToParcel(Parcel out, long elapsedRealtimeUs) {
+ final int freqCount = perStateTimers.length;
+ out.writeInt(freqCount);
+ out.writeInt(CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS);
+ for (int i = 0; i < freqCount; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ perStateTimers[i][j].writeSummaryFromParcelLocked(out, elapsedRealtimeUs);
}
}
+
+ if (mPerStateTxDurationMs == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ for (int i = 0; i < freqCount; i++) {
+ for (int j = 0; j < CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS; j++) {
+ mPerStateTxDurationMs[i][j].writeSummaryFromParcelLocked(out);
+ }
+ }
+ }
+
+ if (mPerFrequencyRxDurationMs == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ for (int i = 0; i < freqCount; i++) {
+ mPerFrequencyRxDurationMs[i].writeSummaryFromParcelLocked(out);
+ }
+ }
+ }
+
+ /**
+ * Read data from summary parcel
+ */
+ public void readSummaryFromParcel(Parcel in) {
+ final int oldFreqCount = in.readInt();
+ final int oldSignalStrengthCount = in.readInt();
+ final int currFreqCount = perStateTimers.length;
+ final int currSignalStrengthCount = CellSignalStrength.NUM_SIGNAL_STRENGTH_BINS;
+
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+ if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+ new TimeBase());
+ // Consume perStateTimers data.
+ temp.readSummaryFromParcelLocked(in);
+ } else {
+ perStateTimers[freq][strength].readSummaryFromParcelLocked(in);
+ }
+ }
+ }
+
+ if (in.readInt() == 1) {
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ for (int strength = 0; strength < oldSignalStrengthCount; strength++) {
+ if (freq >= currFreqCount || strength >= currSignalStrengthCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer temp = new StopwatchTimer(null, null, -1, null,
+ new TimeBase());
+ // Consume mPerStateTxDurationMs data.
+ temp.readSummaryFromParcelLocked(in);
+ }
+ getTxDurationCounter(freq, strength, true).readSummaryFromParcelLocked(in);
+ }
+ }
+ }
+
+ if (in.readInt() == 1) {
+ for (int freq = 0; freq < oldFreqCount; freq++) {
+ if (freq >= currFreqCount) {
+ // Mismatch with the summary parcel. Consume the data but don't use it.
+ final StopwatchTimer
+ temp = new StopwatchTimer(null, null, -1, null, new TimeBase());
+ // Consume mPerFrequencyRxDurationMs data.
+ temp.readSummaryFromParcelLocked(in);
+ continue;
+ }
+ getRxDurationCounter(freq, true).readSummaryFromParcelLocked(in);
+ }
+ }
+ }
+
+ private LongSamplingCounter getTxDurationCounter(
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength, boolean make) {
+ if (mPerStateTxDurationMs == null) {
+ if (!make) return null;
+
+ final int freqCount = getFrequencyRangeCount();
+ final int signalStrengthCount = perStateTimers[0].length;
+ final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+ mPerStateTxDurationMs = new LongSamplingCounter[freqCount][signalStrengthCount];
+ for (int freq = 0; freq < freqCount; freq++) {
+ for (int strength = 0; strength < signalStrengthCount; strength++) {
+ mPerStateTxDurationMs[freq][strength] = new LongSamplingCounter(timeBase);
+ }
+ }
+ }
+ if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+ Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+ + ") requested in getTxDurationCounter");
+ return null;
+ }
+ if (signalStrength < 0 || signalStrength >= perStateTimers[0].length) {
+ Slog.w(TAG, "Unexpected signal strength (" + signalStrength
+ + ") requested in getTxDurationCounter");
+ return null;
+ }
+ return mPerStateTxDurationMs[frequencyRange][signalStrength];
+ }
+
+ private LongSamplingCounter getRxDurationCounter(
+ @ServiceState.FrequencyRange int frequencyRange, boolean make) {
+ if (mPerFrequencyRxDurationMs == null) {
+ if (!make) return null;
+
+ final int freqCount = getFrequencyRangeCount();
+ final TimeBase timeBase = perStateTimers[0][0].mTimeBase;
+ mPerFrequencyRxDurationMs = new LongSamplingCounter[freqCount];
+ for (int freq = 0; freq < freqCount; freq++) {
+ mPerFrequencyRxDurationMs[freq] = new LongSamplingCounter(timeBase);
+ }
+ }
+ if (frequencyRange < 0 || frequencyRange >= getFrequencyRangeCount()) {
+ Slog.w(TAG, "Unexpected frequency range (" + frequencyRange
+ + ") requested in getRxDurationCounter");
+ return null;
+ }
+ return mPerFrequencyRxDurationMs[frequencyRange];
}
}
@@ -1929,18 +2122,26 @@
private final TimeBase mTimeBase;
private final LongMultiStateCounter mCounter;
- private TimeMultiStateCounter(TimeBase timeBase, Parcel in, long timestampMs) {
+ private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
+ this(timeBase, new LongMultiStateCounter(stateCount), timestampMs);
+ }
+
+ private TimeMultiStateCounter(TimeBase timeBase, LongMultiStateCounter counter,
+ long timestampMs) {
mTimeBase = timeBase;
- mCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+ mCounter = counter;
mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
timeBase.add(this);
}
- private TimeMultiStateCounter(TimeBase timeBase, int stateCount, long timestampMs) {
- mTimeBase = timeBase;
- mCounter = new LongMultiStateCounter(stateCount);
- mCounter.setEnabled(mTimeBase.isRunning(), timestampMs);
- timeBase.add(this);
+ @Nullable
+ private static TimeMultiStateCounter readFromParcel(Parcel in, TimeBase timeBase,
+ int stateCount, long timestampMs) {
+ LongMultiStateCounter counter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+ if (counter.getStateCount() != stateCount) {
+ return null;
+ }
+ return new TimeMultiStateCounter(timeBase, counter, timestampMs);
}
private void writeToParcel(Parcel out) {
@@ -3510,11 +3711,8 @@
private TimeMultiStateCounter readTimeMultiStateCounter(Parcel in, TimeBase timeBase) {
if (in.readBoolean()) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- return counter;
- }
+ return TimeMultiStateCounter.readFromParcel(in, timeBase,
+ BatteryConsumer.PROCESS_STATE_COUNT, mClock.elapsedRealtime());
}
return null;
}
@@ -3537,9 +3735,10 @@
// invalid.
TimeMultiStateCounter[] counters = new TimeMultiStateCounter[numCounters];
for (int i = 0; i < numCounters; i++) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
+ final TimeMultiStateCounter counter = TimeMultiStateCounter.readFromParcel(in,
+ timeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ mClock.elapsedRealtime());
+ if (counter != null) {
counters[i] = counter;
} else {
valid = false;
@@ -8000,6 +8199,32 @@
elapsedRealtimeMs * 1000, STATS_SINCE_CHARGED) / 1000;
}
+ @Override
+ public long getActiveTxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, int signalStrength,
+ long elapsedRealtimeMs) {
+ final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+ if (stats == null) return DURATION_UNAVAILABLE;
+
+ final LongSamplingCounter counter = stats.getTxDurationCounter(frequencyRange,
+ signalStrength, false);
+ if (counter == null) return DURATION_UNAVAILABLE;
+
+ return counter.getCountLocked(STATS_SINCE_CHARGED);
+ }
+
+ @Override
+ public long getActiveRxRadioDurationMs(@RadioAccessTechnology int rat,
+ @ServiceState.FrequencyRange int frequencyRange, long elapsedRealtimeMs) {
+ final RadioAccessTechnologyBatteryStats stats = mPerRatBatteryStats[rat];
+ if (stats == null) return DURATION_UNAVAILABLE;
+
+ final LongSamplingCounter counter = stats.getRxDurationCounter(frequencyRange, false);
+ if (counter == null) return DURATION_UNAVAILABLE;
+
+ return counter.getCountLocked(STATS_SINCE_CHARGED);
+ }
+
@UnsupportedAppUsage
@Override public long getMobileRadioActiveTime(long elapsedRealtimeUs, int which) {
return mMobileRadioActiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
@@ -10744,11 +10969,9 @@
= new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
}
if (in.readBoolean()) {
- final TimeMultiStateCounter counter =
- new TimeMultiStateCounter(mBsi.mOnBatteryTimeBase, in, timestampMs);
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- mMobileRadioActiveTime = counter;
- }
+ mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+ mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ timestampMs);
}
mMobileRadioActiveCount = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
@@ -10794,11 +11017,9 @@
int stateCount = in.readInt();
if (stateCount != 0) {
- final TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mBsi.mOnBatteryTimeBase, in, timestampMs);
- if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
- mCpuActiveTimeMs = counter;
- }
+ mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+ mBsi.mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ timestampMs);
}
mCpuClusterTimesMs = new LongSamplingCounterArray(mBsi.mOnBatteryTimeBase, in);
@@ -13482,6 +13703,67 @@
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
mTmpRailStats.resetCellularTotalEnergyUsed();
}
+
+ // Proportionally smear Rx and Tx times across each RAt
+ final int levelCount = CellSignalStrength.getNumSignalStrengthLevels();
+ long[] perSignalStrengthActiveTimeMs = new long[levelCount];
+ long totalActiveTimeMs = 0;
+
+ for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+ final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+ if (ratStats == null) continue;
+
+ final int freqCount = ratStats.getFrequencyRangeCount();
+ for (int freq = 0; freq < freqCount; freq++) {
+ for (int level = 0; level < levelCount; level++) {
+ final long durationMs = ratStats.getTimeSinceMark(freq, level,
+ elapsedRealtimeMs);
+ perSignalStrengthActiveTimeMs[level] += durationMs;
+ totalActiveTimeMs += durationMs;
+ }
+ }
+ }
+
+ if (totalActiveTimeMs != 0) {
+ // Smear the provided Tx/Rx durations across each RAT, frequency, and signal
+ // strength.
+ for (int rat = 0; rat < RADIO_ACCESS_TECHNOLOGY_COUNT; rat++) {
+ final RadioAccessTechnologyBatteryStats ratStats = mPerRatBatteryStats[rat];
+ if (ratStats == null) continue;
+
+ final int freqCount = ratStats.getFrequencyRangeCount();
+ for (int freq = 0; freq < freqCount; freq++) {
+ long frequencyDurationMs = 0;
+ for (int level = 0; level < levelCount; level++) {
+ final long durationMs = ratStats.getTimeSinceMark(freq, level,
+ elapsedRealtimeMs);
+ final long totalLvlDurationMs =
+ perSignalStrengthActiveTimeMs[level];
+ if (totalLvlDurationMs == 0) continue;
+ final long totalTxLvlDurations =
+ deltaInfo.getTransmitDurationMillisAtPowerLevel(level);
+ // Smear HAL provided Tx power level duration based on active modem
+ // duration in a given state. (Add totalLvlDurationMs / 2 before
+ // the integer division with totalLvlDurationMs for rounding.)
+ final long proportionalTxDurationMs =
+ (durationMs * totalTxLvlDurations
+ + (totalLvlDurationMs / 2)) / totalLvlDurationMs;
+ ratStats.incrementTxDuration(freq, level, proportionalTxDurationMs);
+ frequencyDurationMs += durationMs;
+ }
+ final long totalRxDuration = deltaInfo.getReceiveTimeMillis();
+ // Smear HAL provided Rx power duration based on active modem
+ // duration in a given state. (Add totalActiveTimeMs / 2 before the
+ // integer division with totalActiveTimeMs for rounding.)
+ final long proportionalRxDurationMs =
+ (frequencyDurationMs * totalRxDuration + (totalActiveTimeMs
+ / 2)) / totalActiveTimeMs;
+ ratStats.incrementRxDuration(freq, proportionalRxDurationMs);
+ }
+
+ ratStats.setMark(elapsedRealtimeMs);
+ }
+ }
}
long totalAppRadioTimeUs = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
elapsedRealtimeMs * 1000);
@@ -16887,14 +17169,18 @@
mNextMaxDailyDeadlineMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
- mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
-
- /**
- * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
- * later when {@link #initMeasuredEnergyStatsLocked} is called.
- */
- mGlobalMeasuredEnergyStats = MeasuredEnergyStats.createAndReadSummaryFromParcel(
- mMeasuredEnergyStatsConfig, in);
+ final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+ final MeasuredEnergyStats measuredEnergyStats =
+ MeasuredEnergyStats.createAndReadSummaryFromParcel(mMeasuredEnergyStatsConfig, in);
+ if (config != null && Arrays.equals(config.getStateNames(),
+ getBatteryConsumerProcessStateNames())) {
+ /**
+ * WARNING: Supported buckets may have changed across boots. Bucket mismatch is handled
+ * later when {@link #initMeasuredEnergyStatsLocked} is called.
+ */
+ mMeasuredEnergyStatsConfig = config;
+ mGlobalMeasuredEnergyStats = measuredEnergyStats;
+ }
mStartCount++;
@@ -16926,6 +17212,13 @@
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
+
+ final int numRat = in.readInt();
+ for (int i = 0; i < numRat; i++) {
+ if (in.readInt() == 0) continue;
+ getRatBatteryStatsLocked(i).readSummaryFromParcel(in);
+ }
+
mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mMobileRadioActivePerAppTimer.readSummaryFromParcelLocked(in);
@@ -16986,7 +17279,6 @@
getScreenOffRpmTimerLocked(rpmName).readSummaryFromParcelLocked(in);
}
}
-
int NKW = in.readInt();
if (NKW > 10000) {
throw new ParcelFormatException("File corrupt: too many kernel wake locks " + NKW);
@@ -17114,11 +17406,9 @@
u.mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
if (in.readBoolean()) {
- TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mOnBatteryTimeBase, in, elapsedRealtimeMs);
- if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
- u.mMobileRadioActiveTime = counter;
- }
+ u.mMobileRadioActiveTime = TimeMultiStateCounter.readFromParcel(in,
+ mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ elapsedRealtimeMs);
}
u.mMobileRadioActiveCount.readSummaryFromParcelLocked(in);
}
@@ -17168,11 +17458,9 @@
int stateCount = in.readInt();
if (stateCount != 0) {
- final TimeMultiStateCounter counter = new TimeMultiStateCounter(
- mOnBatteryTimeBase, in, mClock.elapsedRealtime());
- if (stateCount == BatteryConsumer.PROCESS_STATE_COUNT) {
- u.mCpuActiveTimeMs = counter;
- }
+ u.mCpuActiveTimeMs = TimeMultiStateCounter.readFromParcel(in,
+ mOnBatteryTimeBase, BatteryConsumer.PROCESS_STATE_COUNT,
+ mClock.elapsedRealtime());
}
u.mCpuClusterTimesMs.readSummaryFromParcelLocked(in);
@@ -17431,6 +17719,17 @@
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
+ final int numRat = mPerRatBatteryStats.length;
+ out.writeInt(numRat);
+ for (int i = 0; i < numRat; i++) {
+ final RadioAccessTechnologyBatteryStats ratStat = mPerRatBatteryStats[i];
+ if (ratStat == null) {
+ out.writeInt(0);
+ continue;
+ }
+ out.writeInt(1);
+ ratStat.writeSummaryToParcel(out, nowRealtime);
+ }
mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mMobileRadioActivePerAppTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mMobileRadioActiveAdjustedTime.writeSummaryFromParcelLocked(out);
@@ -18007,9 +18306,15 @@
mLastWriteTimeMs = in.readLong();
mBatteryTimeToFullSeconds = in.readLong();
- mMeasuredEnergyStatsConfig = MeasuredEnergyStats.Config.createFromParcel(in);
- mGlobalMeasuredEnergyStats =
+
+ final MeasuredEnergyStats.Config config = MeasuredEnergyStats.Config.createFromParcel(in);
+ final MeasuredEnergyStats measuredEnergyStats =
MeasuredEnergyStats.createFromParcel(mMeasuredEnergyStatsConfig, in);
+ if (config != null && Arrays.equals(config.getStateNames(),
+ getBatteryConsumerProcessStateNames())) {
+ mMeasuredEnergyStatsConfig = config;
+ mGlobalMeasuredEnergyStats = measuredEnergyStats;
+ }
mRpmStats.clear();
int NRPMS = in.readInt();
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index 7262e84..7fb8696 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -194,6 +194,7 @@
return mSupportedMultiStateBuckets[index];
}
+ @NonNull
public String[] getStateNames() {
return mStateNames;
}
@@ -321,6 +322,10 @@
LongMultiStateCounter multiStateCounter = null;
if (in.readBoolean()) {
multiStateCounter = LongMultiStateCounter.CREATOR.createFromParcel(in);
+ if (mConfig == null
+ || multiStateCounter.getStateCount() != mConfig.getStateNames().length) {
+ multiStateCounter = null;
+ }
}
if (index < mAccumulatedChargeMicroCoulomb.length) {
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 6673f67..842d72a 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -51,10 +51,10 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId) {
if (reportDraw) {
try {
- mSession.finishDrawing(this, null /* postDrawTransaction */);
+ mSession.finishDrawing(this, null /* postDrawTransaction */, seqId);
} catch (RemoteException e) {
}
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 851e8e0..3494c9e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -53,7 +53,6 @@
VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags);
VerifyCredentialResponse verifyGatekeeperPasswordHandle(long gatekeeperPasswordHandle, long challenge, int userId);
void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
- boolean checkVoldPassword(int userId);
int getCredentialType(int userId);
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 521b2f6..a94b307 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -526,20 +526,6 @@
}
/**
- * Check to see if vold already has the password.
- * Note that this also clears vold's copy of the password.
- * @return Whether the vold password matches or not.
- */
- public boolean checkVoldPassword(int userId) {
- try {
- return getLockSettings().checkVoldPassword(userId);
- } catch (RemoteException re) {
- Log.e(TAG, "failed to check vold password", re);
- return false;
- }
- }
-
- /**
* Returns the password history hash factor, needed to check new password against password
* history with {@link #checkPasswordHistory(byte[], byte[], int)}
*/
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4aa00f6..3a76745 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -361,7 +361,7 @@
"libwuffs_mirror_release_c",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"android_content_res_ApkAssets.cpp",
"android_database_CursorWindow.cpp",
diff --git a/core/proto/android/os/batteryusagestats.proto b/core/proto/android/os/batteryusagestats.proto
index cc90e05..856bc83 100644
--- a/core/proto/android/os/batteryusagestats.proto
+++ b/core/proto/android/os/batteryusagestats.proto
@@ -76,6 +76,7 @@
FOREGROUND = 1;
BACKGROUND = 2;
FOREGROUND_SERVICE = 3;
+ CACHED = 4;
}
optional ProcessState process_state = 2;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index da5f899..2107f65 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5479,9 +5479,9 @@
<enum name="none" value="0" />
<!-- Use the least restrictive rule for line-breaking. -->
<enum name="loose" value="1" />
- <!-- Indicate breaking text with the most comment set of line-breaking rules. -->
+ <!-- Indicates breaking text with the most comment set of line-breaking rules. -->
<enum name="normal" value="2" />
- <!-- ndicates breaking text with the most strictest line-breaking rules. -->
+ <!-- Indicates breaking text with the most strictest line-breaking rules. -->
<enum name="strict" value="3" />
</attr>
<!-- Specify the phrase-based line break can be used when calculating the text wrapping.-->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 269aa1b..62b3054 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4857,6 +4857,7 @@
<item>0.25</item>
<item>0.5</item>
<item>0.75</item>
+ <item>0.875</item>
</string-array>
<!-- Messages that should not be shown to the user during face auth enrollment. This should be
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index 6a53f68..19bb718 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -188,6 +188,9 @@
case BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE:
label = "FGS";
break;
+ case BatteryConsumer.PROCESS_STATE_CACHED:
+ label = "cached";
+ break;
default:
continue;
}
diff --git a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
index 23b12cf..fd08e3c 100644
--- a/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
+++ b/core/tests/batterystatstests/BatteryUsageStatsProtoTests/src/com/android/internal/os/BatteryUsageStatsPulledTest.java
@@ -242,13 +242,17 @@
BatteryConsumer.PROCESS_STATE_BACKGROUND);
final BatteryConsumer.Key keyFgs = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key keyCached = uidBuilder.getKey(BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
uidBuilder.setConsumedPower(keyFg, 9100, BatteryConsumer.POWER_MODEL_POWER_PROFILE)
.setUsageDurationMillis(keyFg, 8100)
.setConsumedPower(keyBg, 9200, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
.setUsageDurationMillis(keyBg, 8200)
.setConsumedPower(keyFgs, 9300, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
- .setUsageDurationMillis(keyFgs, 8300);
+ .setUsageDurationMillis(keyFgs, 8300)
+ .setConsumedPower(keyCached, 9400, BatteryConsumer.POWER_MODEL_MEASURED_ENERGY)
+ .setUsageDurationMillis(keyFgs, 8400);
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid1)
.setPackageWithHighestDrain("myPackage1")
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index f5cbffb..7ccb9d9 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -17,6 +17,8 @@
package com.android.internal.os;
import static android.os.BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
+import static android.os.BatteryStats.POWER_DATA_UNAVAILABLE;
+import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
import static android.os.BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
@@ -24,7 +26,10 @@
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU;
import static com.android.internal.os.BatteryStatsImpl.ExternalStatsSync.UPDATE_DISPLAY;
+import static org.mockito.Mockito.mock;
+
import android.app.ActivityManager;
+import android.app.usage.NetworkStatsManager;
import android.os.BatteryStats;
import android.os.BatteryStats.HistoryItem;
import android.os.BatteryStats.Uid.Sensor;
@@ -34,6 +39,7 @@
import android.telephony.Annotation;
import android.telephony.CellSignalStrength;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.SparseIntArray;
@@ -48,6 +54,8 @@
import junit.framework.TestCase;
+import org.mockito.Mock;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -72,6 +80,13 @@
private static final int ISOLATED_UID = UserHandle.getUid(0, ISOLATED_APP_ID);
private static final WorkSource WS = new WorkSource(UID);
+ enum ModemState {
+ SLEEP, IDLE, RECEIVING, TRANSMITTING
+ }
+
+ @Mock
+ NetworkStatsManager mNetworkStatsManager;
+
/**
* Test BatteryStatsImpl.Uid.noteBluetoothScanResultLocked.
*/
@@ -1173,69 +1188,29 @@
}
@SmallTest
- public void testGetPerStateActiveRadioDurationMs() {
+ public void testGetPerStateActiveRadioDurationMs_noModemActivity() {
final MockClock clock = new MockClock(); // holds realtime and uptime in ms
final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
- final int ratCount = BatteryStats.RADIO_ACCESS_TECHNOLOGY_COUNT;
+ final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+ final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
for (int rat = 0; rat < ratCount; rat++) {
for (int freq = 0; freq < frequencyCount; freq++) {
+ // Should have no RX data without Modem Activity Info
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
expectedDurationsMs[rat][freq][txLvl] = 0;
+ // Should have no TX data without Modem Activity Info
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
}
}
}
- class ModemAndBatteryState {
- public long currentTimeMs = 100;
- public boolean onBattery = false;
- public boolean modemActive = false;
- @Annotation.NetworkType
- public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- @BatteryStats.RadioAccessTechnology
- public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
- @ServiceState.FrequencyRange
- public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
- public SparseIntArray currentSignalStrengths = new SparseIntArray();
-
- void setOnBattery(boolean onBattery) {
- this.onBattery = onBattery;
- bi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
- currentTimeMs * 1000);
- }
-
- void setModemActive(boolean active) {
- modemActive = active;
- final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
- : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
- bi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
- }
-
- void setRatType(@Annotation.NetworkType int dataType,
- @BatteryStats.RadioAccessTechnology int rat) {
- currentNetworkDataType = dataType;
- currentRat = rat;
- bi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
- currentFrequencyRange);
- }
-
- void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
- currentFrequencyRange = frequency;
- bi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
- ServiceState.STATE_IN_SERVICE, frequency);
- }
-
- void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
- currentSignalStrengths.put(rat, strength);
- final int size = currentSignalStrengths.size();
- final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
- bi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
- }
- }
- final ModemAndBatteryState state = new ModemAndBatteryState();
+ final ModemAndBatteryState state = new ModemAndBatteryState(bi, null);
IntConsumer incrementTime = inc -> {
state.currentTimeMs += inc;
@@ -1253,6 +1228,7 @@
expectedDurationsMs[currentRat][currentFrequencyRange][currentSignalStrength] += inc;
};
+
state.setOnBattery(false);
state.setModemActive(false);
state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -1260,95 +1236,367 @@
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// While not on battery, the timers should not increase.
state.setModemActive(true);
incrementTime.accept(100);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(200);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
incrementTime.accept(300);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
incrementTime.accept(400);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
incrementTime.accept(500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
// start counting up.
state.setOnBattery(true);
incrementTime.accept(600);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
-
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Changing LTE signal strength should be tracked.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(700);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
incrementTime.accept(800);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GOOD);
incrementTime.accept(900);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
CellSignalStrength.SIGNAL_STRENGTH_GREAT);
incrementTime.accept(1000);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Change in the signal strength of nonactive RAT should not affect anything.
state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
CellSignalStrength.SIGNAL_STRENGTH_POOR);
incrementTime.accept(1100);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Changing to OTHER Rat should start tracking the poor signal strength.
state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
incrementTime.accept(1200);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
incrementTime.accept(1300);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Now the NR Rat, HIGH frequency range, good signal strength should start counting.
state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
incrementTime.accept(1400);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Noting frequency change should not affect non NR Rat.
state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
incrementTime.accept(1500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
// Modem no longer active, should not be tracking any more.
state.setModemActive(false);
incrementTime.accept(1500);
- checkPerStateActiveRadioDurations(expectedDurationsMs, bi, state.currentTimeMs);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+ }
+ @SmallTest
+ public void testGetPerStateActiveRadioDurationMs_withModemActivity() {
+ final MockClock clock = new MockClock(); // holds realtime and uptime in ms
+ final MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clock);
+ bi.setPowerProfile(mock(PowerProfile.class));
+ final int ratCount = RADIO_ACCESS_TECHNOLOGY_COUNT;
+ final int frequencyCount = ServiceState.FREQUENCY_RANGE_MMWAVE + 1;
+ final int txLevelCount = CellSignalStrength.getNumSignalStrengthLevels();
+
+ final long[][][] expectedDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ final long[][] expectedRxDurationsMs = new long[ratCount][frequencyCount];
+ final long[][][] expectedTxDurationsMs = new long[ratCount][frequencyCount][txLevelCount];
+ for (int rat = 0; rat < ratCount; rat++) {
+ for (int freq = 0; freq < frequencyCount; freq++) {
+ if (rat != RADIO_ACCESS_TECHNOLOGY_NR
+ && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+ } else {
+ expectedRxDurationsMs[rat][freq] = 0;
+ }
+ expectedRxDurationsMs[rat][freq] = POWER_DATA_UNAVAILABLE;
+
+ for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+ expectedDurationsMs[rat][freq][txLvl] = 0;
+
+ if (rat != RADIO_ACCESS_TECHNOLOGY_NR
+ && freq != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+ } else {
+ expectedTxDurationsMs[rat][freq][txLvl] = 0;
+ }
+ expectedTxDurationsMs[rat][freq][txLvl] = POWER_DATA_UNAVAILABLE;
+ }
+ }
+ }
+
+ final ModemActivityInfo mai = new ModemActivityInfo(0L, 0L, 0L, new int[txLevelCount], 0L);
+ final ModemAndBatteryState state = new ModemAndBatteryState(bi, mai);
+
+ IntConsumer incrementTime = inc -> {
+ state.currentTimeMs += inc;
+ clock.realtime = clock.uptime = state.currentTimeMs;
+
+ // If the device is not on battery, no timers should increment.
+ if (!state.onBattery) return;
+ // If the modem is not active, no timers should increment.
+ if (!state.modemActive) return;
+
+ final int currRat = state.currentRat;
+ final int currFreqRange =
+ currRat == RADIO_ACCESS_TECHNOLOGY_NR ? state.currentFrequencyRange : 0;
+ int currSignalStrength = state.currentSignalStrengths.get(currRat);
+
+ expectedDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+
+ // Evaluate the HAL provided time in states.
+ switch (state.modemState) {
+ case SLEEP:
+ long sleepMs = state.modemActivityInfo.getSleepTimeMillis();
+ state.modemActivityInfo.setSleepTimeMillis(sleepMs + inc);
+ break;
+ case IDLE:
+ long idleMs = state.modemActivityInfo.getIdleTimeMillis();
+ state.modemActivityInfo.setIdleTimeMillis(idleMs + inc);
+ break;
+ case RECEIVING:
+ long rxMs = state.modemActivityInfo.getReceiveTimeMillis();
+ state.modemActivityInfo.setReceiveTimeMillis(rxMs + inc);
+ expectedRxDurationsMs[currRat][currFreqRange] += inc;
+ break;
+ case TRANSMITTING:
+ int[] txMs = state.modemActivityInfo.getTransmitTimeMillis();
+ txMs[currSignalStrength] += inc;
+ state.modemActivityInfo.setTransmitTimeMillis(txMs);
+ expectedTxDurationsMs[currRat][currFreqRange][currSignalStrength] += inc;
+ break;
+ }
+ };
+
+ state.setOnBattery(false);
+ state.setModemActive(false);
+ state.setRatType(TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // While not on battery, the timers should not increase.
+ state.setModemActive(true);
+ incrementTime.accept(100);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+ incrementTime.accept(200);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR,
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ incrementTime.accept(500);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_MMWAVE);
+ incrementTime.accept(300);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setRatType(TelephonyManager.NETWORK_TYPE_LTE,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE);
+ incrementTime.accept(400);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_MODERATE);
+ incrementTime.accept(500);
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Data will now be available.
+ for (int rat = 0; rat < ratCount; rat++) {
+ for (int freq = 0; freq < frequencyCount; freq++) {
+ if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+ || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedRxDurationsMs[rat][freq] = 0;
+ }
+ for (int txLvl = 0; txLvl < txLevelCount; txLvl++) {
+ if (rat == RADIO_ACCESS_TECHNOLOGY_NR
+ || freq == ServiceState.FREQUENCY_RANGE_UNKNOWN) {
+ // Only the NR RAT should have per frequency data.
+ expectedTxDurationsMs[rat][freq][txLvl] = 0;
+ }
+ }
+ }
+ }
+
+ // When set on battery, currently active state (RAT:LTE, Signal Strength:Moderate) should
+ // start counting up.
+ state.setOnBattery(true);
+ incrementTime.accept(300);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(500);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(600);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+ // Changing LTE signal strength should be tracked.
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ incrementTime.accept(300);
+ state.setModemState(ModemState.SLEEP);
+ incrementTime.accept(1000);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(700);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN);
+ incrementTime.accept(800);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(222);
+ state.setModemState(ModemState.IDLE);
+ incrementTime.accept(111);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(7777);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_GOOD);
+ incrementTime.accept(88);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(900);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_LTE,
+ CellSignalStrength.SIGNAL_STRENGTH_GREAT);
+ incrementTime.accept(123);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(333);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1000);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(555);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Change in the signal strength of nonactive RAT should not affect anything.
+ state.setSignalStrength(BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER,
+ CellSignalStrength.SIGNAL_STRENGTH_POOR);
+ incrementTime.accept(631);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(321);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(99);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Changing to OTHER Rat should start tracking the poor signal strength.
+ state.setRatType(TelephonyManager.NETWORK_TYPE_CDMA,
+ BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER);
+ incrementTime.accept(1200);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Noting frequency change should not affect non NR Rat.
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_HIGH);
+ incrementTime.accept(444);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1300);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Now the NR Rat, HIGH frequency range, good signal strength should start counting.
+ state.setRatType(TelephonyManager.NETWORK_TYPE_NR, BatteryStats.RADIO_ACCESS_TECHNOLOGY_NR);
+ incrementTime.accept(1400);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Frequency changed to low.
+ state.setFrequencyRange(ServiceState.FREQUENCY_RANGE_LOW);
+ incrementTime.accept(852);
+ state.setModemState(ModemState.RECEIVING);
+ incrementTime.accept(157);
+ state.setModemState(ModemState.TRANSMITTING);
+ incrementTime.accept(1500);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
+
+ // Modem no longer active, should not be tracking any more.
+ state.setModemActive(false);
+ incrementTime.accept(1500);
+ state.noteModemControllerActivity();
+ checkPerStateActiveRadioDurations(expectedDurationsMs, expectedRxDurationsMs,
+ expectedTxDurationsMs, bi, state.currentTimeMs);
}
private void setFgState(int uid, boolean fgOn, MockBatteryStatsImpl bi) {
@@ -1426,28 +1674,124 @@
}
private void checkPerStateActiveRadioDurations(long[][][] expectedDurationsMs,
+ long[][] expectedRxDurationsMs, long[][][] expectedTxDurationsMs,
BatteryStatsImpl bi, long currentTimeMs) {
for (int rat = 0; rat < expectedDurationsMs.length; rat++) {
final long[][] expectedRatDurationsMs = expectedDurationsMs[rat];
for (int freq = 0; freq < expectedRatDurationsMs.length; freq++) {
+ final long expectedRxDurationMs = expectedRxDurationsMs[rat][freq];
+
+ // Build a verbose fail message, just in case.
+ final StringBuilder rxFailSb = new StringBuilder();
+ rxFailSb.append("Wrong time in Rx state for RAT:");
+ rxFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ rxFailSb.append(", frequency:");
+ rxFailSb.append(ServiceState.frequencyRangeToString(freq));
+ assertEquals(rxFailSb.toString(), expectedRxDurationMs,
+ bi.getActiveRxRadioDurationMs(rat, freq, currentTimeMs));
+
final long[] expectedFreqDurationsMs = expectedRatDurationsMs[freq];
for (int strength = 0; strength < expectedFreqDurationsMs.length; strength++) {
final long expectedSignalStrengthDurationMs = expectedFreqDurationsMs[strength];
+ final long expectedTxDurationMs = expectedTxDurationsMs[rat][freq][strength];
final long actualDurationMs = bi.getActiveRadioDurationMs(rat, freq,
strength, currentTimeMs);
- // Build a verbose fail message, just in case.
- final StringBuilder sb = new StringBuilder();
- sb.append("Wrong time in state for RAT:");
- sb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
- sb.append(", frequency:");
- sb.append(ServiceState.frequencyRangeToString(freq));
- sb.append(", strength:");
- sb.append(strength);
+ final StringBuilder failSb = new StringBuilder();
+ failSb.append("Wrong time in state for RAT:");
+ failSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ failSb.append(", frequency:");
+ failSb.append(ServiceState.frequencyRangeToString(freq));
+ failSb.append(", strength:");
+ failSb.append(strength);
+ assertEquals(failSb.toString(), expectedSignalStrengthDurationMs,
+ actualDurationMs);
- assertEquals(sb.toString(), expectedSignalStrengthDurationMs, actualDurationMs);
+ final StringBuilder txFailSb = new StringBuilder();
+ txFailSb.append("Wrong time in Tx state for RAT:");
+ txFailSb.append(BatteryStats.RADIO_ACCESS_TECHNOLOGY_NAMES[rat]);
+ txFailSb.append(", frequency:");
+ txFailSb.append(ServiceState.frequencyRangeToString(freq));
+ txFailSb.append(", strength:");
+ txFailSb.append(strength);
+ assertEquals(txFailSb.toString(), expectedTxDurationMs,
+ bi.getActiveTxRadioDurationMs(rat, freq, strength, currentTimeMs));
}
}
}
}
+
+ private class ModemAndBatteryState {
+ public long currentTimeMs = 100;
+ public boolean onBattery = false;
+ public boolean modemActive = false;
+ @Annotation.NetworkType
+ public int currentNetworkDataType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ @BatteryStats.RadioAccessTechnology
+ public int currentRat = BatteryStats.RADIO_ACCESS_TECHNOLOGY_OTHER;
+ @ServiceState.FrequencyRange
+ public int currentFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN;
+ public SparseIntArray currentSignalStrengths = new SparseIntArray();
+ public ModemState modemState = ModemState.SLEEP;
+ public ModemActivityInfo modemActivityInfo;
+
+ private final MockBatteryStatsImpl mBsi;
+
+ ModemAndBatteryState(MockBatteryStatsImpl bsi, ModemActivityInfo mai) {
+ mBsi = bsi;
+ modemActivityInfo = mai;
+ }
+
+ void setOnBattery(boolean onBattery) {
+ this.onBattery = onBattery;
+ mBsi.updateTimeBasesLocked(onBattery, Display.STATE_OFF, currentTimeMs * 1000,
+ currentTimeMs * 1000);
+ mBsi.setOnBatteryInternal(onBattery);
+ noteModemControllerActivity();
+ }
+
+ void setModemActive(boolean active) {
+ modemActive = active;
+ final int state = active ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+ : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+ mBsi.noteMobileRadioPowerStateLocked(state, currentTimeMs * 1000_000L, UID);
+ noteModemControllerActivity();
+ }
+
+ void setRatType(@Annotation.NetworkType int dataType,
+ @BatteryStats.RadioAccessTechnology int rat) {
+ currentNetworkDataType = dataType;
+ currentRat = rat;
+ mBsi.notePhoneDataConnectionStateLocked(dataType, true, ServiceState.STATE_IN_SERVICE,
+ currentFrequencyRange);
+ }
+
+ void setFrequencyRange(@ServiceState.FrequencyRange int frequency) {
+ currentFrequencyRange = frequency;
+ mBsi.notePhoneDataConnectionStateLocked(currentNetworkDataType, true,
+ ServiceState.STATE_IN_SERVICE, frequency);
+ }
+
+ void setSignalStrength(@BatteryStats.RadioAccessTechnology int rat, int strength) {
+ currentSignalStrengths.put(rat, strength);
+ final int size = currentSignalStrengths.size();
+ final int newestGenSignalStrength = currentSignalStrengths.valueAt(size - 1);
+ mBsi.notePhoneSignalStrengthLocked(newestGenSignalStrength, currentSignalStrengths);
+ }
+
+ void setModemState(ModemState state) {
+ modemState = state;
+ }
+
+ void noteModemControllerActivity() {
+ if (modemActivityInfo == null) return;
+ modemActivityInfo.setTimestamp(currentTimeMs);
+ ModemActivityInfo copy = new ModemActivityInfo(modemActivityInfo.getTimestampMillis(),
+ modemActivityInfo.getSleepTimeMillis(), modemActivityInfo.getIdleTimeMillis(),
+ modemActivityInfo.getTransmitTimeMillis().clone(),
+ modemActivityInfo.getReceiveTimeMillis());
+ mBsi.noteModemControllerActivity(copy, POWER_DATA_UNAVAILABLE,
+ currentTimeMs, currentTimeMs, mNetworkStatsManager);
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 5adc9bd..483224c 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -20,6 +20,7 @@
import static android.os.BatteryConsumer.POWER_MODEL_MEASURED_ENERGY;
import static android.os.BatteryConsumer.POWER_MODEL_UNDEFINED;
import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
+import static android.os.BatteryConsumer.PROCESS_STATE_CACHED;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -83,7 +84,7 @@
final Parcel parcel = Parcel.obtain();
parcel.writeParcelable(outBatteryUsageStats, 0);
- assertThat(parcel.dataSize()).isLessThan(7000);
+ assertThat(parcel.dataSize()).isLessThan(8000);
parcel.setDataPosition(0);
@@ -155,10 +156,11 @@
assertThat(dump).contains("cpu(fg): 2333 apps: 1333 duration: 3s 332ms");
assertThat(dump).contains("cpu(bg): 2444 apps: 1444 duration: 4s 442ms");
assertThat(dump).contains("cpu(fgs): 2555 apps: 1555 duration: 5s 552ms");
+ assertThat(dump).contains("cpu(cached): 123 apps: 123 duration: 456ms");
assertThat(dump).contains("FOO: 20200 apps: 10200 duration: 20s 400ms");
- assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 ( screen=300 "
- + "cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
- + "cpu:fgs=1999 (9s 991ms) FOO=500 )");
+ assertThat(dump).contains("UID 271: 1200 fg: 1777 bg: 1888 fgs: 1999 cached: 123 "
+ + "( screen=300 cpu=400 (600ms) cpu:fg=1777 (7s 771ms) cpu:bg=1888 (8s 881ms) "
+ + "cpu:fgs=1999 (9s 991ms) cpu:cached=123 (456ms) FOO=500 )");
assertThat(dump).contains("User 42: 30.0 ( cpu=10.0 (30ms) FOO=20.0 )");
}
@@ -193,13 +195,15 @@
5321, 7432, 423, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 745,
POWER_MODEL_UNDEFINED,
956, 1167, 1478,
- true, 3554, 3776, 3998, 3554, 15542, 3776, 17762, 3998, 19982);
+ true, 3554, 3776, 3998, 444, 3554, 15542, 3776, 17762, 3998, 19982,
+ 444, 1110);
} else if (uidBatteryConsumer.getUid() == APP_UID2) {
assertUidBatteryConsumer(uidBatteryConsumer, 1332, "bar",
1111, 2222, 333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
BatteryConsumer.POWER_MODEL_POWER_PROFILE,
555, 666, 777,
- true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+ true, 1777, 1888, 1999, 321, 1777, 7771, 1888, 8881, 1999, 9991,
+ 321, 654);
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -267,17 +271,17 @@
1000, 2000,
300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
BatteryConsumer.POWER_MODEL_POWER_PROFILE, 500, 600, 800,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
10100, 10200, 10300, 10400,
- 1333, 3331, 1444, 4441, 1555, 5551);
+ 1333, 3331, 1444, 4441, 1555, 5551, 123, 456);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 30000,
20100, 20200, 20300, 20400,
- 2333, 3332, 2444, 4442, 2555, 5552);
+ 2333, 3332, 2444, 4442, 2555, 5552, 123, 456);
if (includeUserBatteryConsumer) {
builder.getOrCreateUserBatteryConsumerBuilder(USER_ID)
@@ -310,23 +314,23 @@
4321, 5432,
123, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 345, POWER_MODEL_MEASURED_ENERGY,
456, 567, 678,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
addUidBatteryConsumer(builder, batteryStats, APP_UID2, "bar",
1111, 2222,
333, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 444,
BatteryConsumer.POWER_MODEL_POWER_PROFILE, 555, 666, 777,
- 1777, 7771, 1888, 8881, 1999, 9991);
+ 1777, 7771, 1888, 8881, 1999, 9991, 321, 654);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS, 0,
10123, 10234, 10345, 10456,
- 4333, 3334, 5444, 4445, 6555, 5556);
+ 4333, 3334, 5444, 4445, 6555, 5556, 321, 654);
addAggregateBatteryConsumer(builder,
BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE, 12345,
20111, 20222, 20333, 20444,
- 7333, 3337, 8444, 4448, 9555, 5559);
+ 7333, 3337, 8444, 4448, 9555, 5559, 123, 456);
return builder;
}
@@ -337,7 +341,7 @@
int screenPowerModel, double cpuPower, int cpuPowerModel, double customComponentPower,
int cpuDuration, int customComponentDuration, double cpuPowerForeground,
int cpuDurationForeground, double cpuPowerBackground, int cpuDurationBackground,
- double cpuPowerFgs, int cpuDurationFgs) {
+ double cpuPowerFgs, int cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(uid);
final UidBatteryConsumer.Builder uidBuilder =
builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
@@ -365,6 +369,9 @@
final BatteryConsumer.Key cpuFgsKey = uidBuilder.getKey(
BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cachedKey = uidBuilder.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
uidBuilder
.setConsumedPower(cpuFgKey, cpuPowerForeground,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -374,7 +381,10 @@
.setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
.setConsumedPower(cpuFgsKey, cpuPowerFgs,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
- .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+ .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+ .setConsumedPower(cachedKey, cpuPowerCached,
+ BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+ .setUsageDurationMillis(cachedKey, cpuDurationCached);
}
}
@@ -382,7 +392,7 @@
double consumedPower, int cpuPower, int customComponentPower, int cpuDuration,
int customComponentDuration, double cpuPowerForeground, long cpuDurationForeground,
double cpuPowerBackground, long cpuDurationBackground, double cpuPowerFgs,
- long cpuDurationFgs) {
+ long cpuDurationFgs, double cpuPowerCached, long cpuDurationCached) {
final AggregateBatteryConsumer.Builder aggBuilder =
builder.getAggregateBatteryConsumerBuilder(scope)
.setConsumedPower(consumedPower)
@@ -406,6 +416,9 @@
final BatteryConsumer.Key cpuFgsKey = aggBuilder.getKey(
BatteryConsumer.POWER_COMPONENT_CPU,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cpuCachedKey = aggBuilder.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
aggBuilder
.setConsumedPower(cpuFgKey, cpuPowerForeground,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
@@ -415,7 +428,10 @@
.setUsageDurationMillis(cpuBgKey, cpuDurationBackground)
.setConsumedPower(cpuFgsKey, cpuPowerFgs,
BatteryConsumer.POWER_MODEL_POWER_PROFILE)
- .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs);
+ .setUsageDurationMillis(cpuFgsKey, cpuDurationFgs)
+ .setConsumedPower(cpuCachedKey, cpuPowerCached,
+ BatteryConsumer.POWER_MODEL_POWER_PROFILE)
+ .setUsageDurationMillis(cpuCachedKey, cpuDurationCached);
}
}
@@ -432,7 +448,7 @@
1000, 2000, 300, BatteryConsumer.POWER_MODEL_POWER_PROFILE, 400,
BatteryConsumer.POWER_MODEL_POWER_PROFILE,
500, 600, 800,
- true, 1777, 1888, 1999, 1777, 7771, 1888, 8881, 1999, 9991);
+ true, 1777, 1888, 1999, 123, 1777, 7771, 1888, 8881, 1999, 9991, 123, 456);
} else {
fail("Unexpected UID " + uidBatteryConsumer.getUid());
}
@@ -484,8 +500,10 @@
int cpuPowerModel, double customComponentPower, int cpuDuration,
int customComponentDuration, boolean processStateDataIncluded,
double totalPowerForeground, double totalPowerBackground, double totalPowerFgs,
- double cpuPowerForeground, int cpuDurationForeground, double cpuPowerBackground,
- int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs) {
+ double totalPowerCached, double cpuPowerForeground, int cpuDurationForeground,
+ double cpuPowerBackground,
+ int cpuDurationBackground, double cpuPowerFgs, int cpuDurationFgs,
+ int cpuPowerCached, int cpuDurationCached) {
assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(consumedPower);
assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo(
packageWithHighestDrain);
@@ -525,6 +543,10 @@
new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
PROCESS_STATE_FOREGROUND_SERVICE)))
.isEqualTo(totalPowerFgs);
+ assertThat(uidBatteryConsumer.getConsumedPower(
+ new BatteryConsumer.Dimensions(POWER_COMPONENT_ANY,
+ PROCESS_STATE_CACHED)))
+ .isEqualTo(totalPowerCached);
}
final BatteryConsumer.Key cpuFgKey = uidBatteryConsumer.getKey(
@@ -563,6 +585,19 @@
} else {
assertThat(cpuFgsKey).isNotNull();
}
+
+ final BatteryConsumer.Key cachedKey = uidBatteryConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_CPU,
+ BatteryConsumer.PROCESS_STATE_CACHED);
+ if (processStateDataIncluded) {
+ assertThat(cachedKey).isNotNull();
+ assertThat(uidBatteryConsumer.getConsumedPower(cachedKey))
+ .isEqualTo(cpuPowerCached);
+ assertThat(uidBatteryConsumer.getUsageDurationMillis(cachedKey))
+ .isEqualTo(cpuDurationCached);
+ } else {
+ assertThat(cpuFgsKey).isNotNull();
+ }
}
private void assertUserBatteryConsumer(UserBatteryConsumer userBatteryConsumer,
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
index 448f666..fdbf071 100644
--- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -145,10 +145,14 @@
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cached = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ BatteryConsumer.PROCESS_STATE_CACHED);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.081);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.0416666);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
}
@Test
@@ -261,10 +265,14 @@
final BatteryConsumer.Key fgs = uidConsumer.getKey(
BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+ final BatteryConsumer.Key cached = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+ BatteryConsumer.PROCESS_STATE_CACHED);
assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.4965352);
assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.3255208);
assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ assertThat(uidConsumer.getConsumedPower(cached)).isWithin(PRECISION).of(0);
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index b89e8bc..ec45a01 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda4");
+ "com.android.internal.os.LooperStatsTest$$ExternalSyntheticLambda5");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 2a82d8e..df51871 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -71,14 +71,6 @@
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.cellbroadcastreceiver",
- system_ext_specific: true,
- sub_dir: "permissions",
- src: "com.android.cellbroadcastreceiver.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.contacts",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.cellbroadcastreceiver.xml b/data/etc/com.android.cellbroadcastreceiver.xml
deleted file mode 100644
index bc62bbc..0000000
--- a/data/etc/com.android.cellbroadcastreceiver.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-<permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c3b0017..5628548 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -38,24 +38,6 @@
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
- <privapp-permissions package="com.android.cellbroadcastreceiver.module">
- <permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.STATUS_BAR"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.MODIFY_CELL_BROADCASTS"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
- </privapp-permissions>
-
- <privapp-permissions package="com.android.cellbroadcastservice">
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.externalstorage">
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
@@ -452,6 +434,7 @@
<permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.NEARBY_WIFI_DEVICES" />
+ <permission name="android.permission.MANAGE_WIFI_INTERFACES" />
<permission name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index df2b2a3..e898f57 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1309,6 +1309,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-711194343": {
+ "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"-706481945": {
"message": "TaskFragment parent info changed name=%s parentTaskId=%d",
"level": "VERBOSE",
@@ -2587,6 +2593,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/WindowState.java"
},
+ "599897753": {
+ "message": "Previous Activity is %s. Back type is %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"600140673": {
"message": "checkBootAnimationComplete: Waiting for anim complete",
"level": "INFO",
@@ -2671,12 +2683,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "664667685": {
- "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
- "level": "DEBUG",
- "group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
- },
"665256544": {
"message": "All windows drawn!",
"level": "DEBUG",
@@ -2887,6 +2893,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "948208142": {
+ "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"950074526": {
"message": "setLockTaskMode: Can't lock due to auth",
"level": "WARN",
@@ -3103,6 +3115,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/DisplayContent.java"
},
+ "1172542963": {
+ "message": "onBackNavigationDone backType=%s, task=%s, prevTaskTopActivity=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"1178653181": {
"message": "Old wallpaper still the target.",
"level": "VERBOSE",
@@ -3415,11 +3433,11 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1554795024": {
- "message": "Previous Activity is %s",
+ "1544805551": {
+ "message": "Skipping app transition animation. task=%s",
"level": "DEBUG",
"group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ "at": "com\/android\/server\/wm\/Task.java"
},
"1557732761": {
"message": "For Intent %s bringing to top: %s",
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7e68bc0..1a522bd 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -291,6 +291,14 @@
}
/**
+ * @return {@code true} if the rectangle is valid (left <= right and top <= bottom).
+ * @hide
+ */
+ public boolean isValid() {
+ return left <= right && top <= bottom;
+ }
+
+ /**
* @return the rectangle's width. This does not check for a valid rectangle
* (i.e. left <= right) so the result may be negative.
*/
diff --git a/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
index cffdf28..d083e44 100644
--- a/graphics/java/android/graphics/text/LineBreakConfig.java
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -26,7 +26,7 @@
/**
* Indicates the strategies can be used when calculating the text wrapping.
*
- * See <a href="https://drafts.csswg.org/css-text/#line-break-property">the line-break property</a>
+ * See <a href="https://www.w3.org/TR/css-text-3/#line-break-property">the line-break property</a>
*/
public final class LineBreakConfig {
@@ -78,21 +78,87 @@
@Retention(RetentionPolicy.SOURCE)
public @interface LineBreakWordStyle {}
- private @LineBreakStyle int mLineBreakStyle = LINE_BREAK_STYLE_NONE;
- private @LineBreakWordStyle int mLineBreakWordStyle = LINE_BREAK_WORD_STYLE_NONE;
+ /**
+ * A builder for creating {@link LineBreakConfig}.
+ */
+ public static final class Builder {
+ // The line break style for the LineBreakConfig.
+ private @LineBreakStyle int mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE;
- public LineBreakConfig() {
+ // The line break word style for the LineBreakConfig.
+ private @LineBreakWordStyle int mLineBreakWordStyle =
+ LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;
+
+ /**
+ * Builder constructor with line break parameters.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Set the line break style.
+ *
+ * @param lineBreakStyle the new line break style.
+ * @return this Builder
+ */
+ public @NonNull Builder setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ return this;
+ }
+
+ /**
+ * Set the line break word style.
+ *
+ * @param lineBreakWordStyle the new line break word style.
+ * @return this Builder
+ */
+ public @NonNull Builder setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
+ mLineBreakWordStyle = lineBreakWordStyle;
+ return this;
+ }
+
+ /**
+ * Build the {@link LineBreakConfig}
+ *
+ * @return the LineBreakConfig instance.
+ */
+ public @NonNull LineBreakConfig build() {
+ return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle);
+ }
}
/**
- * Set the line break configuration.
+ * Create the LineBreakConfig instance.
*
- * @param lineBreakConfig the new line break configuration.
+ * @param lineBreakStyle the line break style for text wrapping.
+ * @param lineBreakWordStyle the line break word style for text wrapping.
+ * @return the {@link LineBreakConfig} instance.
+ * @hide
*/
- public void set(@NonNull LineBreakConfig lineBreakConfig) {
- Objects.requireNonNull(lineBreakConfig);
- mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
- mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
+ public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
+ @LineBreakWordStyle int lineBreakWordStyle) {
+ LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
+ return builder.setLineBreakStyle(lineBreakStyle)
+ .setLineBreakWordStyle(lineBreakWordStyle)
+ .build();
+ }
+
+ /** @hide */
+ public static final LineBreakConfig NONE =
+ new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
+ .setLineBreakWordStyle(LINE_BREAK_WORD_STYLE_NONE).build();
+
+ private final @LineBreakStyle int mLineBreakStyle;
+ private final @LineBreakWordStyle int mLineBreakWordStyle;
+
+ /**
+ * Constructor with the line break parameters.
+ * Use the {@link LineBreakConfig.Builder} to create the LineBreakConfig instance.
+ */
+ private LineBreakConfig(@LineBreakStyle int lineBreakStyle,
+ @LineBreakWordStyle int lineBreakWordStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ mLineBreakWordStyle = lineBreakWordStyle;
}
/**
@@ -105,15 +171,6 @@
}
/**
- * Set the line break style.
- *
- * @param lineBreakStyle the new line break style.
- */
- public void setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
- mLineBreakStyle = lineBreakStyle;
- }
-
- /**
* Get the line break word style.
*
* @return The current line break word style to be used for the text wrapping.
@@ -122,15 +179,6 @@
return mLineBreakWordStyle;
}
- /**
- * Set the line break word style.
- *
- * @param lineBreakWordStyle the new line break word style.
- */
- public void setLineBreakWordStyle(@LineBreakWordStyle int lineBreakWordStyle) {
- mLineBreakWordStyle = lineBreakWordStyle;
- }
-
@Override
public boolean equals(Object o) {
if (o == null) return false;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 1d2b938..2aa6953 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -501,7 +501,7 @@
final TaskFragmentContainer container = getContainerWithActivity(
activity.getActivityToken());
// Don't launch placeholder if the container is occluded.
- if (container != getTopActiveContainer()) {
+ if (container != null && container != getTopActiveContainer()) {
return false;
}
diff --git a/libs/WindowManager/OWNERS b/libs/WindowManager/OWNERS
index 2c61df9..780e4c1 100644
--- a/libs/WindowManager/OWNERS
+++ b/libs/WindowManager/OWNERS
@@ -1,3 +1,6 @@
set noparent
include /services/core/java/com/android/server/wm/OWNERS
+
+# Give submodule owners in shell resource approval
+per-file Shell/res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 8d5fdfb..08cb252 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -52,14 +52,17 @@
*/
public class BackAnimationController implements RemoteCallable<BackAnimationController> {
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
- public static final boolean IS_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
"persist.debug.back_predictability_progress_threshold";
+ // By default, enable new back dispatching without any animations.
+ private static final int BACK_PREDICTABILITY_PROP =
+ SystemProperties.getInt("persist.debug.back_predictability", 1);
+ public static final boolean IS_ENABLED = BACK_PREDICTABILITY_PROP > 0;
private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP, -1);
private static final String TAG = "BackAnimationController";
+ @VisibleForTesting
+ boolean mEnableAnimations = (BACK_PREDICTABILITY_PROP & (1 << 1)) != 0;
/**
* Location of the initial touch event of the back gesture.
@@ -255,7 +258,7 @@
backNavigationInfo.getTaskWindowConfiguration());
}
mTransaction.apply();
- } else if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ } else if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CALLBACK) {
targetCallback = mBackNavigationInfo.getOnBackInvokedCallback();
@@ -309,7 +312,7 @@
BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
IOnBackInvokedCallback targetCallback = null;
- if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME) {
+ if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback;
} else if (backType == BackNavigationInfo.TYPE_CROSS_TASK
|| backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) {
@@ -330,8 +333,7 @@
return;
}
int backType = mBackNavigationInfo.getType();
- boolean shouldDispatchToLauncher = backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
- && mBackToLauncherCallback != null;
+ boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType);
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback();
@@ -356,6 +358,17 @@
}
}
+ private boolean shouldDispatchToLauncher(int backType) {
+ return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME
+ && mBackToLauncherCallback != null
+ && mEnableAnimations;
+ }
+
+ @VisibleForTesting
+ void setEnableAnimations(boolean shouldEnable) {
+ mEnableAnimations = shouldEnable;
+ }
+
private static void dispatchOnBackStarted(IOnBackInvokedCallback callback) {
if (callback == null) {
return;
@@ -468,7 +481,7 @@
return;
}
RemoteAnimationTarget animationTarget = backNavigationInfo.getDepartingAnimationTarget();
- if (animationTarget != null && mTriggerBack) {
+ if (animationTarget != null) {
if (animationTarget.leash != null && animationTarget.leash.isValid()) {
mTransaction.remove(animationTarget.leash);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 51067a4..4583389 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -344,7 +344,7 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration newMergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {}
+ boolean alwaysConsumeSystemBars, int displayId, int syncSeqId) {}
@Override
public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b52c8d1..daba774 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -98,6 +98,7 @@
private WindowContainerToken mWinToken2;
private int mDividePosition;
private boolean mInitialized = false;
+ private boolean mFreezeDividerWindow = false;
private int mOrientation;
private int mRotation;
@@ -225,11 +226,6 @@
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
initDividerPosition(mTempRect);
- if (mInitialized) {
- release();
- init();
- }
-
return true;
}
@@ -298,20 +294,37 @@
}
/** Releases the surface holding the current {@link DividerView}. */
- public void release() {
+ public void release(SurfaceControl.Transaction t) {
if (!mInitialized) return;
mInitialized = false;
- mSplitWindowManager.release();
+ mSplitWindowManager.release(t);
mDisplayImeController.removePositionProcessor(mImePositionProcessor);
mImePositionProcessor.reset();
}
+ public void release() {
+ release(null /* t */);
+ }
+
+ /** Releases and re-inflates {@link DividerView} on the root surface. */
+ public void update(SurfaceControl.Transaction t) {
+ if (!mInitialized) return;
+ mSplitWindowManager.release(t);
+ mImePositionProcessor.reset();
+ mSplitWindowManager.init(this, mInsetsState);
+ }
+
@Override
public void insetsChanged(InsetsState insetsState) {
mInsetsState.set(insetsState);
if (!mInitialized) {
return;
}
+ if (mFreezeDividerWindow) {
+ // DO NOT change its layout before transition actually run because it might cause
+ // flicker.
+ return;
+ }
mSplitWindowManager.onInsetsChanged(insetsState);
}
@@ -323,6 +336,10 @@
}
}
+ public void setFreezeDividerWindow(boolean freezeDividerWindow) {
+ mFreezeDividerWindow = freezeDividerWindow;
+ }
+
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -515,7 +532,9 @@
}
private int getSmallestWidthDp(Rect bounds) {
- final int minWidth = Math.min(bounds.width(), bounds.height());
+ mTempRect.set(bounds);
+ mTempRect.inset(getDisplayInsets(mContext));
+ final int minWidth = Math.min(mTempRect.width(), mTempRect.height());
final float density = mContext.getResources().getDisplayMetrics().density;
return (int) (minWidth / density);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 4903f9d..833d9d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -58,6 +58,9 @@
private SurfaceControl mLeash;
private DividerView mDividerView;
+ // Used to "pass" a transaction to WWM.remove so that view removal can be synchronized.
+ private SurfaceControl.Transaction mSyncTransaction = null;
+
public interface ParentContainerCallbacks {
void attachToParentSurface(SurfaceControl.Builder b);
void onLeashReady(SurfaceControl leash);
@@ -130,22 +133,38 @@
* Releases the surface control of the current {@link DividerView} and tear down the view
* hierarchy.
*/
- void release() {
+ void release(@Nullable SurfaceControl.Transaction t) {
if (mDividerView != null) {
mDividerView = null;
}
if (mViewHost != null){
+ mSyncTransaction = t;
mViewHost.release();
+ mSyncTransaction = null;
mViewHost = null;
}
if (mLeash != null) {
- new SurfaceControl.Transaction().remove(mLeash).apply();
+ if (t == null) {
+ new SurfaceControl.Transaction().remove(mLeash).apply();
+ } else {
+ t.remove(mLeash);
+ }
mLeash = null;
}
}
+ @Override
+ protected void removeSurface(SurfaceControl sc) {
+ // This gets called via SurfaceControlViewHost.release()
+ if (mSyncTransaction != null) {
+ mSyncTransaction.remove(sc);
+ } else {
+ super.removeSurface(sc);
+ }
+ }
+
void setInteractive(boolean interactive) {
if (mDividerView == null) return;
mDividerView.setInteractive(interactive);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index b2bbafe..99b32a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -42,6 +42,7 @@
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -50,6 +51,8 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
+import dagger.Lazy;
+
/**
* Controller to show/update compat UI components on Tasks based on whether the foreground
* activities are in compatibility mode.
@@ -102,6 +105,7 @@
private final DisplayImeController mImeController;
private final SyncTransactionQueue mSyncQueue;
private final ShellExecutor mMainExecutor;
+ private final Lazy<Transitions> mTransitionsLazy;
private final CompatUIImpl mImpl = new CompatUIImpl();
private CompatUICallback mCallback;
@@ -118,13 +122,15 @@
DisplayInsetsController displayInsetsController,
DisplayImeController imeController,
SyncTransactionQueue syncQueue,
- ShellExecutor mainExecutor) {
+ ShellExecutor mainExecutor,
+ Lazy<Transitions> transitionsLazy) {
mContext = context;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
mImeController = imeController;
mSyncQueue = syncQueue;
mMainExecutor = mainExecutor;
+ mTransitionsLazy = transitionsLazy;
mDisplayController.addDisplayWindowListener(this);
mImeController.addPositionProcessor(this);
mCompatUIHintsState = new CompatUIHintsState();
@@ -302,6 +308,7 @@
ShellTaskOrganizer.TaskListener taskListener) {
return new LetterboxEduWindowManager(context, taskInfo,
mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
+ mTransitionsLazy.get(),
this::onLetterboxEduDismissed);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
index 03986ee..3061eab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -18,6 +18,7 @@
import static com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
import static com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -42,7 +43,9 @@
class LetterboxEduAnimationController {
private static final String TAG = "LetterboxEduAnimation";
- private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
+ // If shell transitions are enabled, startEnterAnimation will be called after all transitions
+ // have finished, and therefore the start delay should be shorter.
+ private static final int ENTER_ANIM_START_DELAY_MILLIS = ENABLE_SHELL_TRANSITIONS ? 300 : 500;
private final TransitionAnimation mTransitionAnimation;
private final String mPackageName;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index 8aa4d0e..2e0b09e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -38,6 +38,7 @@
// The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
// 204 is simply 255 * 0.8.
static final int BACKGROUND_DIM_ALPHA = 204;
+
private View mDialogContainer;
private TextView mDialogTitle;
private Drawable mBackgroundDim;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index dda72ff..cc3a3b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -36,6 +36,7 @@
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
+import com.android.wm.shell.transition.Transitions;
/**
* Window manager for the Letterbox Education.
@@ -63,6 +64,8 @@
private final LetterboxEduAnimationController mAnimationController;
+ private final Transitions mTransitions;
+
// Remember the last reported state in case visibility changes due to keyguard or IME updates.
private boolean mEligibleForLetterboxEducation;
@@ -80,17 +83,19 @@
public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback) {
- this(context, taskInfo, syncQueue, taskListener, displayLayout, onDismissCallback,
- new LetterboxEduAnimationController(context));
+ DisplayLayout displayLayout, Transitions transitions,
+ Runnable onDismissCallback) {
+ this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
+ onDismissCallback, new LetterboxEduAnimationController(context));
}
@VisibleForTesting
LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
- DisplayLayout displayLayout, Runnable onDismissCallback,
+ DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
LetterboxEduAnimationController animationController) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
+ mTransitions = transitions;
mOnDismissCallback = onDismissCallback;
mAnimationController = animationController;
mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation;
@@ -132,8 +137,8 @@
mLayout = inflateLayout();
updateDialogMargins();
- mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
- this::onDialogEnterAnimationEnded);
+ // startEnterAnimation will be called immediately if shell-transitions are disabled.
+ mTransitions.runOnIdle(this::startEnterAnimation);
return mLayout;
}
@@ -158,8 +163,18 @@
R.layout.letterbox_education_dialog_layout, null);
}
+ private void startEnterAnimation() {
+ if (mLayout == null) {
+ // Dialog has already been released.
+ return;
+ }
+ mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
+ this::onDialogEnterAnimationEnded);
+ }
+
private void onDialogEnterAnimationEnded() {
if (mLayout == null) {
+ // Dialog has already been released.
return;
}
mLayout.setDismissOnClickListener(this::onDismiss);
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 bf0337d..1ee9407 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
@@ -96,6 +96,7 @@
import java.util.Optional;
import dagger.BindsOptionalOf;
+import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -210,9 +211,9 @@
static CompatUIController provideCompatUIController(Context context,
DisplayController displayController, DisplayInsetsController displayInsetsController,
DisplayImeController imeController, SyncTransactionQueue syncQueue,
- @ShellMainThread ShellExecutor mainExecutor) {
+ @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
return new CompatUIController(context, displayController, displayInsetsController,
- imeController, syncQueue, mainExecutor);
+ imeController, syncQueue, mainExecutor, transitionsLazy);
}
@WMSingleton
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 c2d5823..7397e52 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
@@ -194,7 +194,7 @@
public float getAspectRatioOrDefault(
@android.annotation.Nullable PictureInPictureParams params) {
return params != null && params.hasSetAspectRatio()
- ? params.getAspectRatio()
+ ? params.getAspectRatioFloat()
: getDefaultAspectRatio();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index c1e7825..5d6b041 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -1071,13 +1071,13 @@
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
final Rational currentAspectRatio =
- mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatioRational()
+ mPictureInPictureParams != null ? mPictureInPictureParams.getAspectRatio()
: null;
final boolean aspectRatioChanged = !Objects.equals(currentAspectRatio,
- params.getAspectRatioRational());
+ params.getAspectRatio());
mPictureInPictureParams = params;
if (aspectRatioChanged) {
- mPipBoundsState.setAspectRatio(params.getAspectRatio());
+ mPipBoundsState.setAspectRatio(params.getAspectRatioFloat());
}
return aspectRatioChanged;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index 3115f8a..11633a9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -253,11 +253,11 @@
private WindowManager.LayoutParams getDismissTargetLayoutParams() {
final Point windowSize = new Point();
mWindowManager.getDefaultDisplay().getRealSize(windowSize);
-
+ int height = Math.min(windowSize.y, mDismissAreaHeight);
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
- mDismissAreaHeight,
- 0, windowSize.y - mDismissAreaHeight,
+ height,
+ 0, windowSize.y - height,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
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 d880f82..9865548 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
@@ -75,7 +75,7 @@
public void setBoundsStateForEntry(ComponentName componentName, ActivityInfo activityInfo,
PictureInPictureParams params, PipBoundsAlgorithm pipBoundsAlgorithm) {
super.setBoundsStateForEntry(componentName, activityInfo, params, pipBoundsAlgorithm);
- setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatio(), true);
+ setDesiredTvExpandedAspectRatio(params.getExpandedAspectRatioFloat(), true);
}
/** Resets the TV PiP state for a new activity. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index e88eef9..177b4a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -24,6 +24,7 @@
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
@@ -32,6 +33,7 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -68,6 +70,7 @@
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.recents.RecentTasksController;
@@ -196,11 +199,12 @@
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
- if (isSplitScreenVisible()) {
- int taskId = mStageCoordinator.getTaskId(splitPosition);
- return mTaskOrganizer.getRunningTaskInfo(taskId);
+ if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
+ return null;
}
- return null;
+
+ final int taskId = mStageCoordinator.getTaskId(splitPosition);
+ return mTaskOrganizer.getRunningTaskInfo(taskId);
}
public boolean isTaskInSplitScreen(int taskId) {
@@ -350,6 +354,18 @@
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
if (apps == null || apps.length == 0) {
+ final ActivityManager.RunningTaskInfo pairedTaskInfo =
+ getTaskInfo(SplitLayout.reversePosition(position));
+ final ComponentName pairedActivity =
+ pairedTaskInfo != null ? pairedTaskInfo.baseActivity : null;
+ final ComponentName intentActivity =
+ intent.getIntent() != null ? intent.getIntent().getComponent() : null;
+ if (pairedActivity != null && pairedActivity.equals(intentActivity)) {
+ // Switch split position if dragging the same activity to another side.
+ setSideStagePosition(SplitLayout.reversePosition(
+ mStageCoordinator.getSideStagePosition()));
+ }
+
// Do nothing when the animation was cancelled.
t.apply();
return;
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 48dd1fe..ec1ddf0 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
@@ -29,6 +29,7 @@
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.transitTypeToString;
import static android.view.WindowManagerPolicyConstants.SPLIT_DIVIDER_LAYER;
+import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
@@ -1171,6 +1172,8 @@
updateUnfoldBounds();
return;
}
+
+ mSplitLayout.update(null /* t */);
onLayoutSizeChanged(mSplitLayout);
}
}
@@ -1198,7 +1201,6 @@
if (!ENABLE_SHELL_TRANSITIONS) return;
final SurfaceControl.Transaction t = mTransactionPool.acquire();
- setDividerVisibility(false, t);
mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
mSplitLayout.rotateTo(toRotation, mDisplayLayout.stableInsets());
updateWindowBounds(mSplitLayout, wct);
@@ -1255,8 +1257,15 @@
@Nullable TransitionRequestInfo request) {
final ActivityManager.RunningTaskInfo triggerTask = request.getTriggerTask();
if (triggerTask == null) {
- // Still want to monitor everything while in split-screen, so return non-null.
- return mMainStage.isActive() ? new WindowContainerTransaction() : null;
+ if (mMainStage.isActive()) {
+ if (request.getType() == TRANSIT_CHANGE && request.getDisplayChange() != null) {
+ mSplitLayout.setFreezeDividerWindow(true);
+ }
+ // Still want to monitor everything while in split-screen, so return non-null.
+ return new WindowContainerTransaction();
+ } else {
+ return null;
+ }
} else if (triggerTask.displayId != mDisplayId) {
// Skip handling task on the other display.
return null;
@@ -1352,8 +1361,14 @@
// If we're not in split-mode, just abort so something else can handle it.
if (!mMainStage.isActive()) return false;
+ mSplitLayout.setFreezeDividerWindow(false);
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
+ mSplitLayout.update(startTransaction);
+ }
+
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
if (taskInfo == null || !taskInfo.hasParentTask()) continue;
final StageTaskListener stage = getStageOfTask(taskInfo);
@@ -1368,10 +1383,6 @@
Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called"
+ " with " + taskInfo.taskId + " before startAnimation().");
}
- } else if (info.getType() == TRANSIT_CHANGE
- && change.getStartRotation() != change.getEndRotation()) {
- // Show the divider after transition finished.
- setDividerVisibility(true, finishTransaction);
}
}
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 1bef552e..49f907b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -62,6 +62,7 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.HardwareBuffer;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -243,7 +244,7 @@
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "TaskSnapshot#relayout");
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0,
tmpFrames, tmpMergedConfiguration, surfaceControl, tmpInsetsState,
- tmpControls);
+ tmpControls, new Bundle());
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RemoteException e) {
snapshotSurface.clearWindowSynced();
@@ -517,7 +518,7 @@
private void reportDrawn() {
try {
- mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */, Integer.MAX_VALUE);
} catch (RemoteException e) {
clearWindowSynced();
}
@@ -534,7 +535,7 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfiguration, boolean forceLayout,
- boolean alwaysConsumeSystemBars, int displayId) {
+ boolean alwaysConsumeSystemBars, int displayId, int seqId) {
if (mOuter != null) {
mOuter.mSplashScreenExecutor.execute(() -> {
if (mergedConfiguration != null
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 fb3cd87..435d670 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
@@ -109,6 +109,9 @@
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+ /** List of {@link Runnable} instances to run when the last active transition has finished. */
+ private final ArrayList<Runnable> mRunWhenIdleQueue = new ArrayList<>();
+
private float mTransitionAnimationScaleSetting = 1.0f;
private static final class ActiveTransition {
@@ -224,6 +227,21 @@
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
+ /**
+ * Runs the given {@code runnable} when the last active transition has finished, or immediately
+ * if there are currently no active transitions.
+ *
+ * <p>This method should be called on the Shell main-thread, where the given {@code runnable}
+ * will be executed when the last active transition is finished.
+ */
+ public void runOnIdle(Runnable runnable) {
+ if (mActiveTransitions.isEmpty()) {
+ runnable.run();
+ } else {
+ mRunWhenIdleQueue.add(runnable);
+ }
+ }
+
/** @return true if the transition was triggered by opening something vs closing something */
public static boolean isOpeningType(@WindowManager.TransitionType int type) {
return type == TRANSIT_OPEN
@@ -520,6 +538,11 @@
if (mActiveTransitions.size() <= activeIdx) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
+ "finished");
+ // Run all runnables from the run-when-idle queue.
+ for (int i = 0; i < mRunWhenIdleQueue.size(); i++) {
+ mRunWhenIdleQueue.get(i).run();
+ }
+ mRunWhenIdleQueue.clear();
return;
}
// Start animating the next active transition
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 9054685..3e7ee25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -78,6 +78,7 @@
MockitoAnnotations.initMocks(this);
mController = new BackAnimationController(
mShellExecutor, mTransaction, mActivityTaskManager, mContext);
+ mController.setEnableAnimations(true);
}
private void createNavigationInfo(RemoteAnimationTarget topAnimationTarget,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 9bb54a1..2e5078d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -61,7 +61,7 @@
public void testInitRelease() {
mSplitWindowManager.init(mSplitLayout, new InsetsState());
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
- mSplitWindowManager.release();
+ mSplitWindowManager.release(null /* t */);
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index a31b287..4607d8a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -53,6 +53,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
+import com.android.wm.shell.transition.Transitions;
import org.junit.Before;
import org.junit.Test;
@@ -62,6 +63,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import dagger.Lazy;
+
/**
* Tests for {@link CompatUIController}.
*
@@ -82,6 +85,7 @@
private @Mock ShellTaskOrganizer.TaskListener mMockTaskListener;
private @Mock SyncTransactionQueue mMockSyncQueue;
private @Mock ShellExecutor mMockExecutor;
+ private @Mock Lazy<Transitions> mMockTransitionsLazy;
private @Mock CompatUIWindowManager mMockCompatLayout;
private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
@@ -102,7 +106,8 @@
doReturn(true).when(mMockLetterboxEduLayout).createLayout(anyBoolean());
doReturn(true).when(mMockLetterboxEduLayout).updateCompatInfo(any(), any(), anyBoolean());
mController = new CompatUIController(mContext, mMockDisplayController,
- mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor) {
+ mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor,
+ mMockTransitionsLazy) {
@Override
CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
ShellTaskOrganizer.TaskListener taskListener) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
index 337b738..7d51b52 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
@@ -54,6 +54,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.transition.Transitions;
import org.junit.After;
import org.junit.Before;
@@ -86,11 +87,14 @@
private ArgumentCaptor<WindowManager.LayoutParams> mWindowAttrsCaptor;
@Captor
private ArgumentCaptor<Runnable> mEndCallbackCaptor;
+ @Captor
+ private ArgumentCaptor<Runnable> mRunOnIdleCaptor;
@Mock private LetterboxEduAnimationController mAnimationController;
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@Mock private SurfaceControlViewHost mViewHost;
+ @Mock private Transitions mTransitions;
@Mock private Runnable mOnDismissCallback;
private SharedPreferences mSharedPreferences;
@@ -204,6 +208,23 @@
}
@Test
+ public void testCreateLayout_windowManagerReleasedBeforeTransitionsIsIdle_doesNotStartAnim() {
+ LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
+
+ assertTrue(windowManager.createLayout(/* canShow= */ true));
+
+ assertTrue(mSharedPreferences.getBoolean(mPrefKey, /* default= */ false));
+
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ windowManager.release();
+
+ mRunOnIdleCaptor.getValue().run();
+
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+ }
+
+ @Test
public void testUpdateCompatInfo_updatesLayoutCorrectly() {
LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */ true);
@@ -303,6 +324,13 @@
}
private void verifyAndFinishEnterAnimation(LetterboxEduDialogLayout layout) {
+ verify(mTransitions).runOnIdle(mRunOnIdleCaptor.capture());
+
+ // startEnterAnimation isn't called until run-on-idle runnable is called.
+ verify(mAnimationController, never()).startEnterAnimation(any(), any());
+
+ mRunOnIdleCaptor.getValue().run();
+
verify(mAnimationController).startEnterAnimation(eq(layout), mEndCallbackCaptor.capture());
mEndCallbackCaptor.getValue().run();
}
@@ -320,7 +348,8 @@
boolean isTaskbarEduShowing) {
LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
createTaskInfo(eligible), mSyncTransactionQueue, mTaskListener,
- createDisplayLayout(), mOnDismissCallback, mAnimationController);
+ createDisplayLayout(), mTransitions, mOnDismissCallback,
+ mAnimationController);
spyOn(windowManager);
doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index dbf93b4..a0b1297 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -46,6 +46,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -93,7 +94,7 @@
* Tests for the shell transitions.
*
* Build/Install/Run:
- * atest WMShellUnitTests:ShellTransitionTests
+ * atest WMShellUnitTests:ShellTransitionTests
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -600,6 +601,83 @@
assertTrue(DefaultTransitionHandler.isRotationSeamless(seamlessDisplay, displays));
}
+ @Test
+ public void testRunWhenIdle() {
+ Transitions transitions = createTestTransitions();
+ transitions.replaceDefaultHandlerForTest(mDefaultHandler);
+
+ Runnable runnable1 = mock(Runnable.class);
+ Runnable runnable2 = mock(Runnable.class);
+ Runnable runnable3 = mock(Runnable.class);
+ Runnable runnable4 = mock(Runnable.class);
+
+ transitions.runOnIdle(runnable1);
+
+ // runnable1 is executed immediately because there are no active transitions.
+ verify(runnable1, times(1)).run();
+
+ clearInvocations(runnable1);
+
+ IBinder transitToken1 = new Binder();
+ transitions.requestStartTransition(transitToken1,
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
+ TransitionInfo info1 = new TransitionInfoBuilder(TRANSIT_OPEN)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken1, info1, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ transitions.runOnIdle(runnable2);
+ transitions.runOnIdle(runnable3);
+
+ // runnable2 and runnable3 aren't executed immediately because there is an active
+ // transaction.
+
+ IBinder transitToken2 = new Binder();
+ transitions.requestStartTransition(transitToken2,
+ new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
+ TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_CLOSE)
+ .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
+ transitions.onTransitionReady(transitToken2, info2, mock(SurfaceControl.Transaction.class),
+ mock(SurfaceControl.Transaction.class));
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ // first transition finished
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken1), any(), any());
+ verify(mOrganizer, times(0)).finishTransition(eq(transitToken2), any(), any());
+ // But now the "queued" transition is running
+ assertEquals(1, mDefaultHandler.activeCount());
+
+ // runnable2 and runnable3 are still not executed because the second transition is still
+ // active.
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+
+ mDefaultHandler.finishAll();
+ mMainExecutor.flushAll();
+ verify(mOrganizer, times(1)).finishTransition(eq(transitToken2), any(), any());
+
+ // runnable2 and runnable3 are executed after the second transition finishes because there
+ // are no other active transitions, runnable1 isn't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(1)).run();
+ verify(runnable3, times(1)).run();
+
+ clearInvocations(runnable2);
+ clearInvocations(runnable3);
+
+ transitions.runOnIdle(runnable4);
+
+ // runnable4 is executed immediately because there are no active transitions, all other
+ // runnables aren't executed again.
+ verify(runnable1, times(0)).run();
+ verify(runnable2, times(0)).run();
+ verify(runnable3, times(0)).run();
+ verify(runnable4, times(1)).run();
+ }
+
class TransitionInfoBuilder {
final TransitionInfo mInfo;
@@ -749,7 +827,7 @@
IWindowManager mockWM = mock(IWindowManager.class);
final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
try {
- doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
+ doReturn(new int[]{DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
} catch (RemoteException e) {
// No remote stuff happening, so this can't be hit
}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 63b831d..c80fb18 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -118,7 +118,7 @@
"libz",
],
},
- linux_glibc: {
+ host_linux: {
srcs: [
"CursorWindow.cpp",
],
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index bcfe9c3..30ca7d15 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -135,7 +135,7 @@
skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false);
SkAndroidFrameworkTraceUtil::setEnableTracing(
- base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, false));
+ base::GetBoolProperty(PROPERTY_SKIA_ATRACE_ENABLED, true));
runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8c98c72..2357dfe 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -133,6 +133,7 @@
}
void DrawFrameTask::postAndWait() {
+ ATRACE_CALL();
AutoMutex _lock(mLock);
mRenderThread->queue().post([this]() { run(); });
mSignal.wait(mLock);
diff --git a/libs/storage/IMountService.cpp b/libs/storage/IMountService.cpp
index 055dbb2..99508a2 100644
--- a/libs/storage/IMountService.cpp
+++ b/libs/storage/IMountService.cpp
@@ -48,8 +48,6 @@
TRANSACTION_isObbMounted,
TRANSACTION_getMountedObbPath,
TRANSACTION_isExternalStorageEmulated,
- TRANSACTION_decryptStorage,
- TRANSACTION_encryptStorage,
};
class BpMountService: public BpInterface<IMountService>
@@ -517,40 +515,6 @@
path = reply.readString16();
return true;
}
-
- int32_t decryptStorage(const String16& password)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
- data.writeString16(password);
- if (remote()->transact(TRANSACTION_decryptStorage, data, &reply) != NO_ERROR) {
- ALOGD("decryptStorage could not contact remote\n");
- return -1;
- }
- int32_t err = reply.readExceptionCode();
- if (err < 0) {
- ALOGD("decryptStorage caught exception %d\n", err);
- return err;
- }
- return reply.readInt32();
- }
-
- int32_t encryptStorage(const String16& password)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMountService::getInterfaceDescriptor());
- data.writeString16(password);
- if (remote()->transact(TRANSACTION_encryptStorage, data, &reply) != NO_ERROR) {
- ALOGD("encryptStorage could not contact remote\n");
- return -1;
- }
- int32_t err = reply.readExceptionCode();
- if (err < 0) {
- ALOGD("encryptStorage caught exception %d\n", err);
- return err;
- }
- return reply.readInt32();
- }
};
IMPLEMENT_META_INTERFACE(MountService, "android.os.storage.IStorageManager")
diff --git a/libs/storage/include/storage/IMountService.h b/libs/storage/include/storage/IMountService.h
index 5b07318..5a9c39b 100644
--- a/libs/storage/include/storage/IMountService.h
+++ b/libs/storage/include/storage/IMountService.h
@@ -70,8 +70,6 @@
const sp<IObbActionListener>& token, const int32_t nonce) = 0;
virtual bool isObbMounted(const String16& filename) = 0;
virtual bool getMountedObbPath(const String16& filename, String16& path) = 0;
- virtual int32_t decryptStorage(const String16& password) = 0;
- virtual int32_t encryptStorage(const String16& password) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/media/java/android/media/tv/CommandRequest.java b/media/java/android/media/tv/CommandRequest.java
index ffb6e07..3245fb5 100644
--- a/media/java/android/media/tv/CommandRequest.java
+++ b/media/java/android/media/tv/CommandRequest.java
@@ -24,6 +24,8 @@
* A request for command from broadcast signal.
*/
public final class CommandRequest extends BroadcastInfoRequest implements Parcelable {
+ public static final String ARGUMENT_TYPE_XML = "xml";
+ public static final String ARGUMENT_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -41,35 +43,38 @@
}
};
- private final String mNameSpace;
+ private final String mNamespace;
private final String mName;
private final String mArguments;
+ private final String mArgumentType;
static CommandRequest createFromParcelBody(Parcel in) {
return new CommandRequest(in);
}
- public CommandRequest(int requestId, @RequestOption int option, @NonNull String nameSpace,
- @NonNull String name, @NonNull String arguments) {
+ public CommandRequest(int requestId, @RequestOption int option, @NonNull String namespace,
+ @NonNull String name, @NonNull String arguments, @NonNull String argumentType) {
super(REQUEST_TYPE, requestId, option);
- mNameSpace = nameSpace;
+ mNamespace = namespace;
mName = name;
mArguments = arguments;
+ mArgumentType = argumentType;
}
CommandRequest(Parcel source) {
super(REQUEST_TYPE, source);
- mNameSpace = source.readString();
+ mNamespace = source.readString();
mName = source.readString();
mArguments = source.readString();
+ mArgumentType = source.readString();
}
/**
* Gets the namespace of the command.
*/
@NonNull
- public String getNameSpace() {
- return mNameSpace;
+ public String getNamespace() {
+ return mNamespace;
}
/**
@@ -89,6 +94,15 @@
return mArguments;
}
+ /**
+ * Gets the argument type of the command.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getArgumentType() {
+ return mArgumentType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -97,8 +111,9 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
- dest.writeString(mNameSpace);
+ dest.writeString(mNamespace);
dest.writeString(mName);
dest.writeString(mArguments);
+ dest.writeString(mArgumentType);
}
}
diff --git a/media/java/android/media/tv/CommandResponse.java b/media/java/android/media/tv/CommandResponse.java
index c8853f1..8e448cd 100644
--- a/media/java/android/media/tv/CommandResponse.java
+++ b/media/java/android/media/tv/CommandResponse.java
@@ -25,6 +25,8 @@
* A response for command from broadcast signal.
*/
public final class CommandResponse extends BroadcastInfoResponse implements Parcelable {
+ public static final String RESPONSE_TYPE_XML = "xml";
+ public static final String RESPONSE_TYPE_JSON = "json";
private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE =
TvInputManager.BROADCAST_INFO_TYPE_COMMAND;
@@ -43,20 +45,23 @@
};
private final String mResponse;
+ private final String mResponseType;
static CommandResponse createFromParcelBody(Parcel in) {
return new CommandResponse(in);
}
- public CommandResponse(int requestId, int sequence,
- @ResponseResult int responseResult, @Nullable String response) {
+ public CommandResponse(int requestId, int sequence, @ResponseResult int responseResult,
+ @Nullable String response, @NonNull String responseType) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mResponse = response;
+ mResponseType = responseType;
}
CommandResponse(Parcel source) {
super(RESPONSE_TYPE, source);
mResponse = source.readString();
+ mResponseType = source.readString();
}
/**
@@ -68,6 +73,15 @@
return mResponse;
}
+ /**
+ * Gets the type of the command response.
+ * It could be either JSON or XML.
+ */
+ @NonNull
+ public String getResponseType() {
+ return mResponseType;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -77,5 +91,6 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mResponse);
+ dest.writeString(mResponseType);
}
}
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 5957528..078e832 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -80,6 +80,11 @@
/**
* Gets the version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index 35836be..f38ea9d 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -74,14 +74,20 @@
}
/**
- * Gets the Version number of requested session.
+ * Gets the Version number of requested session. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
}
/**
- * Gets the raw data of session.
+ * Gets the raw data of session. The sessionData field represents payload data of the session
+ * after session header, which includes version and sessionId.
*/
@NonNull
public Bundle getSessionData() {
diff --git a/media/java/android/media/tv/StreamEventResponse.java b/media/java/android/media/tv/StreamEventResponse.java
index f952ce9..28dff37 100644
--- a/media/java/android/media/tv/StreamEventResponse.java
+++ b/media/java/android/media/tv/StreamEventResponse.java
@@ -43,7 +43,7 @@
};
private final int mEventId;
- private final long mNpt;
+ private final long mNptMillis;
private final byte[] mData;
static StreamEventResponse createFromParcelBody(Parcel in) {
@@ -51,17 +51,17 @@
}
public StreamEventResponse(int requestId, int sequence, @ResponseResult int responseResult,
- int eventId, long npt, @Nullable byte[] data) {
+ int eventId, long nptMillis, @Nullable byte[] data) {
super(RESPONSE_TYPE, requestId, sequence, responseResult);
mEventId = eventId;
- mNpt = npt;
+ mNptMillis = nptMillis;
mData = data;
}
private StreamEventResponse(@NonNull Parcel source) {
super(RESPONSE_TYPE, source);
mEventId = source.readInt();
- mNpt = source.readLong();
+ mNptMillis = source.readLong();
int dataLength = source.readInt();
mData = new byte[dataLength];
source.readByteArray(mData);
@@ -76,9 +76,10 @@
/**
* Returns the NPT(Normal Play Time) value when the event occurred or will occur.
+ * <p>The time unit of NPT is millisecond.
*/
- public long getNpt() {
- return mNpt;
+ public long getNptMillis() {
+ return mNptMillis;
}
/**
@@ -98,7 +99,7 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mEventId);
- dest.writeLong(mNpt);
+ dest.writeLong(mNptMillis);
dest.writeInt(mData.length);
dest.writeByteArray(mData);
}
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index 37df4ea..a1a6b51 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -91,7 +91,12 @@
}
/**
- * Gets the version number of requested table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index e9f1136..afc9bee 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -76,7 +76,12 @@
}
/**
- * Gets the Version number of table.
+ * Gets the version number of requested table. If it is null, value will be -1.
+ * <p>The consistency of version numbers between request and response depends on
+ * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
+ * different from the version of the request. Otherwise, response with a different version from
+ * its request will be considered invalid.
*/
public int getVersion() {
return mVersion;
diff --git a/media/java/android/media/tv/TimelineResponse.java b/media/java/android/media/tv/TimelineResponse.java
index fbeb0c4..7de30f5 100644
--- a/media/java/android/media/tv/TimelineResponse.java
+++ b/media/java/android/media/tv/TimelineResponse.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -79,8 +80,8 @@
* that conveys Time Values on it.
*/
@Nullable
- public String getSelector() {
- return mSelector;
+ public Uri getSelector() {
+ return Uri.parse(mSelector);
}
/**
diff --git a/packages/BackupRestoreConfirmation/res/values/strings.xml b/packages/BackupRestoreConfirmation/res/values/strings.xml
index 3fb3fd4..5c90fd0 100644
--- a/packages/BackupRestoreConfirmation/res/values/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values/strings.xml
@@ -44,8 +44,6 @@
<string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
<!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
<string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
- <!-- Text for message to user that they must supply an encryption password to use for a full backup operation because their phone is locked. -->
- <string name="backup_enc_password_required">Since your device is encrypted, you are required to encrypt your backup. Please enter a password below:</string>
<!-- Text for message to user when performing a full restore operation, explaining that they must enter the password originally used to encrypt the full backup data. -->
<string name="restore_enc_password_text">If the restore data is encrypted, please enter the password below:</string>
diff --git a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
index d6b6bf8..3c790f0 100644
--- a/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
+++ b/packages/BackupRestoreConfirmation/src/com/android/backupconfirm/BackupRestoreConfirmation.java
@@ -27,8 +27,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Slog;
@@ -66,10 +64,8 @@
Handler mHandler;
IBackupManager mBackupManager;
- IStorageManager mStorageManager;
FullObserver mObserver;
int mToken;
- boolean mIsEncrypted;
boolean mDidAcknowledge;
String mAction;
@@ -144,7 +140,6 @@
}
mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
- mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
mHandler = new ObserverHandler(getApplicationContext());
final Object oldObserver = getLastNonConfigurationInstance();
@@ -248,20 +243,13 @@
mDenyButton.setEnabled(!mDidAcknowledge);
}
- // We vary the password prompt depending on whether one is predefined, and whether
- // the device is encrypted.
- mIsEncrypted = deviceIsEncrypted();
+ // We vary the password prompt depending on whether one is predefined.
if (!haveBackupPassword()) {
curPwDesc.setVisibility(View.GONE);
mCurPassword.setVisibility(View.GONE);
if (layoutId == R.layout.confirm_backup) {
TextView encPwDesc = findViewById(R.id.enc_password_desc);
- if (mIsEncrypted) {
- encPwDesc.setText(R.string.backup_enc_password_required);
- monitorEncryptionPassword();
- } else {
- encPwDesc.setText(R.string.backup_enc_password_optional);
- }
+ encPwDesc.setText(R.string.backup_enc_password_optional);
}
}
}
@@ -312,20 +300,6 @@
}
}
- boolean deviceIsEncrypted() {
- try {
- return mStorageManager.getEncryptionState()
- != StorageManager.ENCRYPTION_STATE_NONE
- && mStorageManager.getPasswordType()
- != StorageManager.CRYPT_TYPE_DEFAULT;
- } catch (Exception e) {
- // If we can't talk to the storagemanager service we have a serious problem; fail
- // "secure" i.e. assuming that the device is encrypted.
- Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage());
- return true;
- }
- }
-
boolean haveBackupPassword() {
try {
return mBackupManager.hasBackupPassword();
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 55a1998..67fc6c2 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -82,7 +82,7 @@
<string name="permission_notification">Notifications</string>
<!-- Description of notification permission of COMPUTER profile [CHAR LIMIT=NONE] -->
- <string name="permission_notification_summary">Can read all notifications, including information like contracts, messages, and photos</string>
+ <string name="permission_notification_summary">Can read all notifications, including information like contacts, messages, and photos</string>
<!-- Storage permission will be granted of COMPUTER profile [CHAR LIMIT=30] -->
<string name="permission_storage">Photos and media</string>
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index ca080ce..bf518b2 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -1061,9 +1061,9 @@
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
try {
- mService.setUidForeground(uid, uidForeground);
+ mService.noteUidForeground(uid, uidForeground);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
index efe626d..c86f7fd 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
@@ -91,7 +91,7 @@
in INetworkStatsProvider provider);
/** Mark given UID as being in foreground for stats purposes. */
- void setUidForeground(int uid, boolean uidForeground);
+ void noteUidForeground(int uid, boolean uidForeground);
/** Advise persistence threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
index f681ba1..06f2a62 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStats.java
@@ -327,16 +327,11 @@
* @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is
* for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only
* counting iface stats.
- * @param set usage state of this {@link Entry}. Should be one of the following
- * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+ * @param set usage state of this {@link Entry}.
* @param tag tag of this {@link Entry}.
- * @param metered metered state of this {@link Entry}. Should be one of the following
- * values: {link #METERED_YES}, {link #METERED_NO}.
- * @param roaming roaming state of this {@link Entry}. Should be one of the following
- * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
- * @param defaultNetwork default network status of this {@link Entry}. Should be one
- * of the following values: {link #DEFAULT_NETWORK_YES},
- * {link #DEFAULT_NETWORK_NO}.
+ * @param metered metered state of this {@link Entry}.
+ * @param roaming roaming state of this {@link Entry}.
+ * @param defaultNetwork default network status of this {@link Entry}.
* @param rxBytes Number of bytes received for this {@link Entry}. Statistics should
* represent the contents of IP packets, including IP headers.
* @param rxPackets Number of packets received for this {@link Entry}. Statistics should
@@ -401,8 +396,7 @@
}
/**
- * @return the set state of this entry. Should be one of the following
- * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}.
+ * @return the set state of this entry.
*/
@State public int getSet() {
return set;
@@ -416,24 +410,21 @@
}
/**
- * @return the metered state. Should be one of the following
- * values: {link #METERED_YES}, {link #METERED_NO}.
+ * @return the metered state.
*/
@Meteredness public int getMetered() {
return metered;
}
/**
- * @return the roaming state. Should be one of the following
- * values: {link #ROAMING_YES}, {link #ROAMING_NO}.
+ * @return the roaming state.
*/
@Roaming public int getRoaming() {
return roaming;
}
/**
- * @return the default network state. Should be one of the following
- * values: {link #DEFAULT_NETWORK_YES}, {link #DEFAULT_NETWORK_NO}.
+ * @return the default network state.
*/
@DefaultNetwork public int getDefaultNetwork() {
return defaultNetwork;
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index 7eaa01e..01ff02d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,7 @@
oneway interface INetworkStatsProviderCallback {
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void notifyAlertReached();
- void notifyWarningOrLimitReached();
+ void notifyWarningReached();
+ void notifyLimitReached();
void unregister();
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
index 23fc069..d37a53d 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java
@@ -152,19 +152,19 @@
try {
// Reuse the code path to notify warning reached with limit reached
// since framework handles them in the same way.
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyWarningReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
}
/**
- * Notify system that the quota set by {@link #onSetLimit} or limit set by
+ * Notify system that the limit set by {@link #onSetLimit} or limit set by
* {@link #onSetWarningAndLimit} has been reached.
*/
public void notifyLimitReached() {
try {
- getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ getProviderCallbackBinderOrThrow().notifyLimitReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
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 1d22908..e3794e4 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -1194,7 +1194,7 @@
}
@VisibleForTesting
- public void setUidForeground(int uid, boolean uidForeground) {
+ public void noteUidForeground(int uid, boolean uidForeground) {
PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
@@ -2393,10 +2393,17 @@
}
@Override
- public void notifyWarningOrLimitReached() {
- Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
+ public void notifyWarningReached() {
+ Log.d(TAG, mTag + ": notifyWarningReached");
BinderUtils.withCleanCallingIdentity(() ->
- mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached());
+ mNetworkPolicyManager.notifyStatsProviderWarningReached());
+ }
+
+ @Override
+ public void notifyLimitReached() {
+ Log.d(TAG, mTag + ": notifyLimitReached");
+ BinderUtils.withCleanCallingIdentity(() ->
+ mNetworkPolicyManager.notifyStatsProviderLimitReached());
}
@Override
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bd70396..579e3d7 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1344,7 +1344,9 @@
<string name="notice_header" translatable="false"></string>
<!-- Name of the phone device. [CHAR LIMIT=30] -->
- <string name="media_transfer_this_device_name">This phone</string>
+ <string name="media_transfer_this_device_name" product="default">This phone</string>
+ <!-- Name of the tablet device. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_device_name" product="tablet">This tablet</string>
<!-- Name of the phone device with an active remote session. [CHAR LIMIT=30] -->
<string name="media_transfer_this_phone">This phone</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 3d91c5a..7f300caf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1117,7 +1117,8 @@
final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
- || (mIsActiveDeviceA2dp && !isOnCall)) {
+ || (mIsActiveDeviceA2dp && !isOnCall)
+ || mIsActiveDeviceLeAudio) {
if (isTwsBatteryAvailable(leftBattery, rightBattery) && !shortSummary) {
stringRes = R.string.bluetooth_active_battery_level_untethered;
} else if (batteryLevelPercentageString != null && !shortSummary) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index e203cba..19df1e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -246,6 +246,13 @@
return R.drawable.ic_bt_le_audio;
}
+ public int getAudioLocation(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
+ }
+ return mService.getAudioLocation(device);
+ }
+
@RequiresApi(Build.VERSION_CODES.S)
protected void finalize() {
if (DEBUG) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e7765e6..e93371d 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -536,6 +536,7 @@
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
+ <uses-permission android:name="android.permission.MANAGE_WIFI_INTERFACES" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission needed for CTS test - ConcurrencyTest#testP2pExternalApprover
P2P external approver API sets require MANAGE_WIFI_NETWORK_SELECTION permission. -->
diff --git a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 9b43cf6..779ab81 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_check.xml b/packages/SystemUI/res/drawable/media_output_status_check.xml
index 1b750f8..5fbc42b 100644
--- a/packages/SystemUI/res/drawable/media_output_status_check.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_check.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_item_status"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 05c6358..0599e23 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
- android:fillColor="@color/media_dialog_inactive_item_main_content"
+ android:fillColor="@color/media_dialog_item_main_content"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
index 91d81a2..cb63300 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_date.xml
@@ -19,6 +19,7 @@
android:id="@+id/date_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
android:gravity="center_horizontal"
android:textColor="@android:color/white"
android:shadowColor="@color/keyguard_shadow_color"
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
index 3900ea5..76fe58c 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_weather.xml
@@ -19,6 +19,7 @@
android:id="@+id/weather_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:paddingHorizontal="@dimen/dream_overlay_complication_shadow_padding"
android:textColor="@android:color/white"
android:shadowColor="@color/keyguard_shadow_color"
android:shadowRadius="?attr/shadowRadius"
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index eeb37c7..20747fa 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -83,7 +83,7 @@
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="16sp"/>
<TextView
android:id="@+id/subtitle"
@@ -91,7 +91,7 @@
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- android:textColor="@color/media_dialog_inactive_item_main_content"
+ android:textColor="@color/media_dialog_item_main_content"
android:textSize="14sp"
android:fontFamily="@*android:string/config_bodyFontFamily"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 4b96d5d..3a638b1 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -67,10 +67,12 @@
<!-- media output dialog-->
<color name="media_dialog_background">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
- <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ffcccccc</color>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index c56ba7b..02a4070 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -37,6 +37,7 @@
<dimen name="controls_task_view_right_margin">8dp</dimen>
<dimen name="split_shade_header_height">42dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">42dp</dimen>
<!-- Distance that the full shade transition takes in order to complete by tapping on a button
like "expand". -->
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index f267088..bdd7049 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -24,6 +24,7 @@
<dimen name="keyguard_split_shade_top_margin">72dp</dimen>
<dimen name="split_shade_header_height">56dp</dimen>
+ <dimen name="status_bar_header_height_keyguard">56dp</dimen>
<dimen name="qs_media_session_height_expanded">184dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 1edaaad..49fc848 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -176,10 +176,12 @@
<!-- media output dialog-->
<color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
- <color name="media_dialog_active_item_main_content">@color/material_dynamic_primary10</color>
- <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_primary40</color>
- <color name="media_dialog_item_status">@color/material_dynamic_primary10</color>
+ <color name="media_dialog_item_main_content">@color/material_dynamic_primary20</color>
<color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+ <color name="media_dialog_connected_item_background">@color/material_dynamic_primary90</color>
+ <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+ <color name="media_dialog_button_background">@color/material_dynamic_primary40</color>
+ <color name="media_dialog_solid_button_text">@color/material_dynamic_neutral95</color>
<!-- controls -->
<color name="control_primary_text">#E6FFFFFF</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 52ec516..ffae601 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1376,6 +1376,7 @@
<dimen name="dream_overlay_complication_weather_text_size">18sp</dimen>
<dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
<dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
+ <dimen name="dream_overlay_complication_shadow_padding">2dp</dimen>
<!-- The position of the end guide, which dream overlay complications can align their start with
if their end is aligned with the parent end. Represented as the percentage over from the
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3ae21e0..f5c1382 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -486,7 +486,7 @@
<style name="MediaOutputItemInactiveTitle">
<item name="android:textSize">16sp</item>
- <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
+ <item name="android:textColor">@color/media_dialog_item_main_content</item>
</style>
<style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1ef6dea..3858f9c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -326,7 +326,6 @@
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private final Executor mBackgroundExecutor;
private SensorPrivacyManager mSensorPrivacyManager;
- private int mFaceAuthUserId;
/**
* Short delay before restarting fingerprint authentication after a successful try. This should
@@ -1030,8 +1029,8 @@
boolean cameraPrivacyEnabled = false;
if (mSensorPrivacyManager != null) {
cameraPrivacyEnabled = mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- mFaceAuthUserId);
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA);
}
if (msgId == FaceManager.FACE_ERROR_CANCELED
@@ -2599,7 +2598,6 @@
// This would need to be updated for multi-sensor devices
final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
&& mFaceSensorProperties.get(0).supportsFaceDetection;
- mFaceAuthUserId = userId;
if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
index 4b86862..498e715 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
@@ -119,9 +119,13 @@
if (useInvertedAlphaColor) {
canvas.drawColor(bgColor)
}
+
+ // We may clear the color(if useInvertedAlphaColor is true) of the rounded corner rects
+ // before drawing rounded corners. If the cutout happens to be inside one of these rects, it
+ // will be cleared, so we have to draw rounded corners before cutout.
+ drawRoundedCorners(canvas)
// Cutouts are drawn in DisplayCutoutBaseView.onDraw()
super.onDraw(canvas)
- drawRoundedCorners(canvas)
debugTransparentRegionPaint?.let {
calculateTransparentRect()
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 7e1a026..807ff21 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -254,8 +254,8 @@
mMirrorViewGeometryVsyncCallback =
l -> {
- if (isWindowVisible() && mMirrorSurface != null) {
- calculateSourceBounds(mMagnificationFrame, mScale);
+ if (isWindowVisible() && mMirrorSurface != null && calculateSourceBounds(
+ mMagnificationFrame, mScale)) {
// The final destination for the magnification surface should be at 0,0
// since the ViewRootImpl's position will change
mTmpRect.set(0, 0, mMagnificationFrame.width(),
@@ -350,6 +350,7 @@
mMirrorWindowControl.destroyControl();
}
mMirrorViewBounds.setEmpty();
+ mSourceBounds.setEmpty();
updateSystemUIStateIfNeeded();
mContext.unregisterComponentCallbacks(this);
}
@@ -728,8 +729,12 @@
/**
* Calculates the desired source bounds. This will be the area under from the center of the
* displayFrame, factoring in scale.
+ *
+ * @return {@code true} if the source bounds is changed.
*/
- private void calculateSourceBounds(Rect displayFrame, float scale) {
+ private boolean calculateSourceBounds(Rect displayFrame, float scale) {
+ final Rect oldSourceBounds = mTmpRect;
+ oldSourceBounds.set(mSourceBounds);
int halfWidth = displayFrame.width() / 2;
int halfHeight = displayFrame.height() / 2;
int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
@@ -757,6 +762,7 @@
mSourceBounds.offsetTo(mSourceBounds.left,
mWindowBounds.height() - mSourceBounds.height());
}
+ return !mSourceBounds.equals(oldSourceBounds);
}
private void calculateMagnificationFrameBoundary() {
@@ -1079,7 +1085,7 @@
pw.println(" mMagnificationFrame:"
+ (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:"
- + (isWindowVisible() ? mSourceBounds : "empty"));
+ + (mSourceBounds.isEmpty() ? "empty" : mSourceBounds));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 64c2d2e..c100a07 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -726,8 +726,8 @@
boolean isCameraPrivacyEnabled = false;
if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
- && mSensorPrivacyManager.isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- mCurrentDialogArgs.argi1 /* userId */)) {
+ && mSensorPrivacyManager.isSensorPrivacyEnabled(
+ SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA)) {
isCameraPrivacyEnabled = true;
}
// TODO(b/141025588): Create separate methods for handling hard and soft errors.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index b8b4092..dfb27ef 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -89,6 +89,7 @@
private boolean mPaused = false;
private boolean mScreenOff = false;
private int mLastSensorValue = -1;
+ private DozeMachine.State mState = DozeMachine.State.UNINITIALIZED;
/**
* Debug value used for emulating various display brightness buckets:
@@ -135,6 +136,7 @@
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ mState = newState;
switch (newState) {
case INITIALIZED:
resetBrightnessToDefault();
@@ -262,8 +264,9 @@
*/
private int clampToDimBrightnessForScreenOff(int brightness) {
final boolean screenTurningOff =
- mDozeParameters.shouldClampToDimBrightness()
- || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP;
+ (mDozeParameters.shouldClampToDimBrightness()
+ || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP)
+ && mState == DozeMachine.State.INITIALIZED;
if (screenTurningOff
&& mWakefulnessLifecycle.getLastSleepReason() == GO_TO_SLEEP_REASON_TIMEOUT) {
return Math.max(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c01d2c3..acad30b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -20,6 +20,7 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -123,11 +124,11 @@
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -1557,6 +1558,7 @@
public void setOccluded(boolean isOccluded, boolean animate) {
Trace.beginSection("KeyguardViewMediator#setOccluded");
if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
mHandler.removeMessages(SET_OCCLUDED);
Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
mHandler.sendMessage(msg);
@@ -1706,14 +1708,6 @@
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
}
-
- if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
- if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
- // Without this, settings is not enabled until the lock screen first appears
- setShowingLocked(false);
- hideLocked();
- return;
- }
}
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
@@ -2813,6 +2807,7 @@
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
Trace.beginSection("KeyguardViewMediator#startKeyguardExitAnimation");
+ mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
Message msg = mHandler.obtainMessage(START_KEYGUARD_EXIT_ANIM,
new StartKeyguardExitAnimParams(transit, startTime, fadeoutDuration, apps,
wallpapers, nonApps, finishedCallback));
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0b23ad5..a646482 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -119,7 +119,9 @@
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
mContainerLayout.setOnClickListener(null);
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
+ mSubTitleText.setTextColor(mController.getColorItemContent());
+ mTwoLineTitleText.setTextColor(mController.getColorItemContent());
mSeekBar.getProgressDrawable().setColorFilter(
new PorterDuffColorFilter(mController.getColorSeekbarProgress(),
PorterDuff.Mode.SRC_IN));
@@ -140,7 +142,7 @@
&& !mController.hasAdjustVolumeUserRestriction()) {
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
- mController.getColorInactiveItem(),
+ mController.getColorItemContent(),
PorterDuff.Mode.SRC_IN));
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
false /* showSeekBar*/,
@@ -155,7 +157,7 @@
mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_failed));
- mStatusIcon.setColorFilter(mController.getColorInactiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
setTwoLineLayout(device, false /* bFocused */,
false /* showSeekBar */, false /* showProgressBar */,
true /* showSubtitle */, true /* showStatus */);
@@ -163,7 +165,7 @@
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -173,13 +175,13 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(false, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorActiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
initSeekbar(device);
} else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
- mStatusIcon.setColorFilter(mController.getColorActiveItem());
- mTitleText.setTextColor(mController.getColorActiveItem());
+ mStatusIcon.setColorFilter(mController.getColorItemContent());
+ mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, true /* showStatus */);
@@ -192,7 +194,7 @@
mCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {
onCheckBoxClicked(true, device);
});
- setCheckBoxColor(mCheckBox, mController.getColorInactiveItem());
+ setCheckBoxColor(mCheckBox, mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), false /* bFocused */,
false /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -214,7 +216,7 @@
@Override
void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
- mTitleText.setTextColor(mController.getColorInactiveItem());
+ mTitleText.setTextColor(mController.getColorItemContent());
mCheckBox.setVisibility(View.GONE);
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
false /* bFocused */);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 62d5c8e..df0c14b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -170,14 +170,16 @@
void setSingleLineLayout(CharSequence title, boolean bFocused, boolean showSeekBar,
boolean showProgressBar, boolean showStatus) {
mTwoLineLayout.setVisibility(View.GONE);
+ boolean isActive = showSeekBar || showProgressBar;
final Drawable backgroundDrawable =
- showSeekBar || showProgressBar
+ isActive
? mContext.getDrawable(R.drawable.media_output_item_background_active)
.mutate() : mContext.getDrawable(
R.drawable.media_output_item_background)
.mutate();
backgroundDrawable.setColorFilter(new PorterDuffColorFilter(
- mController.getColorItemBackground(),
+ isActive ? mController.getColorConnectedItemBackground()
+ : mController.getColorItemBackground(),
PorterDuff.Mode.SRC_IN));
mItemLayout.setBackground(backgroundDrawable);
mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
@@ -366,7 +368,7 @@
.mutate();
drawable.setColorFilter(
new PorterDuffColorFilter(Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content),
+ R.color.media_dialog_item_main_content),
PorterDuff.Mode.SRC_IN));
return drawable;
}
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 a8141c0..dcb1c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -216,6 +216,7 @@
PorterDuff.Mode.SRC_IN);
mDoneButton.getBackground().setColorFilter(buttonColorFilter);
mStopButton.getBackground().setColorFilter(buttonColorFilter);
+ mDoneButton.setTextColor(mAdapter.getController().getColorPositiveButtonText());
}
mHeaderIcon.setVisibility(View.VISIBLE);
mHeaderIcon.setImageIcon(icon);
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 0b6c68d..ea7f7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -110,11 +110,12 @@
private MediaOutputMetricLogger mMetricLogger;
- private int mColorActiveItem;
- private int mColorInactiveItem;
+ private int mColorItemContent;
private int mColorSeekbarProgress;
private int mColorButtonBackground;
private int mColorItemBackground;
+ private int mColorConnectedItemBackground;
+ private int mColorPositiveButtonText;
@Inject
public MediaOutputController(@NonNull Context context, String packageName,
@@ -133,16 +134,18 @@
mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
mDialogLaunchAnimator = dialogLaunchAnimator;
mNearbyMediaDevicesManager = nearbyMediaDevicesManagerOptional.orElse(null);
- mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_active_item_main_content);
- mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_inactive_item_main_content);
+ mColorItemContent = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_item_main_content);
mColorSeekbarProgress = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent1_200);
+ R.color.media_dialog_seekbar_progress);
mColorButtonBackground = Utils.getColorStateListDefaultColor(mContext,
- R.color.media_dialog_item_background);
+ R.color.media_dialog_button_background);
mColorItemBackground = Utils.getColorStateListDefaultColor(mContext,
- android.R.color.system_accent2_50);
+ R.color.media_dialog_item_background);
+ mColorConnectedItemBackground = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_connected_item_background);
+ mColorPositiveButtonText = Utils.getColorStateListDefaultColor(mContext,
+ R.color.media_dialog_solid_button_text);
}
void start(@NonNull Callback cb) {
@@ -322,8 +325,7 @@
}
void setColorFilter(Drawable drawable, boolean isActive) {
- drawable.setColorFilter(new PorterDuffColorFilter(isActive
- ? mColorActiveItem : mColorInactiveItem,
+ drawable.setColorFilter(new PorterDuffColorFilter(mColorItemContent,
PorterDuff.Mode.SRC_IN));
}
@@ -358,26 +360,32 @@
ColorScheme mCurrentColorScheme = new ColorScheme(wallpaperColors,
isDarkTheme);
if (isDarkTheme) {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(2);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(2);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent2().get(7); // A2-600
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorItemBackground = mCurrentColorScheme.getNeutral2().get(9); // N2-800
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent2().get(9); // A2-800
+ mColorPositiveButtonText = mCurrentColorScheme.getAccent2().get(9); // A2-800
} else {
- mColorActiveItem = mCurrentColorScheme.getNeutral1().get(10);
- mColorInactiveItem = mCurrentColorScheme.getAccent1().get(7);
- mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(3);
- mColorButtonBackground = mCurrentColorScheme.getAccent1().get(3);
- mColorItemBackground = mCurrentColorScheme.getAccent2().get(0);
+ mColorItemContent = mCurrentColorScheme.getAccent1().get(9); // A1-800
+ mColorSeekbarProgress = mCurrentColorScheme.getAccent1().get(4); // A1-300
+ mColorButtonBackground = mCurrentColorScheme.getAccent1().get(7); // A1-600
+ mColorItemBackground = mCurrentColorScheme.getAccent2().get(1); // A2-50
+ mColorConnectedItemBackground = mCurrentColorScheme.getAccent1().get(2); // A1-100
+ mColorPositiveButtonText = mCurrentColorScheme.getNeutral1().get(1); // N1-50
}
}
- public int getColorActiveItem() {
- return mColorActiveItem;
+ public int getColorConnectedItemBackground() {
+ return mColorConnectedItemBackground;
}
- public int getColorInactiveItem() {
- return mColorInactiveItem;
+ public int getColorPositiveButtonText() {
+ return mColorPositiveButtonText;
+ }
+
+ public int getColorItemContent() {
+ return mColorItemContent;
}
public int getColorSeekbarProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
index 71cacac..3d5b3a3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
@@ -32,6 +32,7 @@
import android.view.ViewGroup
import android.view.WindowManager
import com.android.internal.widget.CachingIconView
+import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.gesture.TapGestureDetector
@@ -150,40 +151,36 @@
appNameOverride: CharSequence? = null,
) {
val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
- appIconView.contentDescription = appNameOverride ?: getAppName(appPackageName)
-
- val appIcon = appIconDrawableOverride ?: getAppIcon(appPackageName)
- val visibility = if (appIcon != null) {
- View.VISIBLE
- } else {
- View.GONE
- }
- appIconView.setImageDrawable(appIcon)
- appIconView.visibility = visibility
+ val appInfo = getAppInfo(appPackageName)
+ appIconView.contentDescription = appNameOverride ?: appInfo.appName
+ appIconView.setImageDrawable(appIconDrawableOverride ?: appInfo.appIcon)
}
- /** Returns the icon of the app playing the media or null if we can't find it. */
- private fun getAppIcon(appPackageName: String?): Drawable? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationIcon(appPackageName)
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find icon for package $appPackageName", e)
- null
+ /**
+ * Returns the app name and icon of the app playing media, or a default name and icon if we
+ * can't find the app name/icon.
+ */
+ private fun getAppInfo(appPackageName: String?): AppInfo {
+ if (appPackageName != null) {
+ try {
+ return AppInfo(
+ appName = context.packageManager.getApplicationInfo(
+ appPackageName, PackageManager.ApplicationInfoFlags.of(0)
+ ).loadLabel(context.packageManager).toString(),
+ appIcon = context.packageManager.getApplicationIcon(appPackageName)
+ )
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Cannot find package $appPackageName", e)
+ }
}
- }
-
- /** Returns the name of the app playing the media or null if we can't find it. */
- private fun getAppName(appPackageName: String?): String? {
- appPackageName ?: return null
- return try {
- context.packageManager.getApplicationInfo(
- appPackageName, PackageManager.ApplicationInfoFlags.of(0)
- ).loadLabel(context.packageManager).toString()
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Cannot find name for package $appPackageName", e)
- null
- }
+ return AppInfo(
+ appName = context.getString(R.string.media_output_dialog_unknown_launch_app_name),
+ appIcon = context.resources.getDrawable(R.drawable.ic_cast).apply {
+ this.setTint(
+ Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary)
+ )
+ }
+ )
}
private fun onScreenTapped(e: MotionEvent) {
@@ -205,3 +202,8 @@
const val REASON_TIMEOUT = "TIMEOUT"
const val REASON_SCREEN_TAP = "SCREEN_TAP"
}
+
+private data class AppInfo(
+ val appName: String,
+ val appIcon: Drawable
+)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index d1b569f..4640205 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -241,7 +241,13 @@
private void addNonFirstPageAnimators(int page) {
Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
- mNonFirstPageQSAnimators.put(page, pair);
+ if (pair != null) {
+ // pair is null in one of two cases:
+ // * mPagedTileLayout is null, meaning we are still setting up.
+ // * the page has no tiles
+ // In either case, don't add the animators to the map.
+ mNonFirstPageQSAnimators.put(page, pair);
+ }
}
@Override
@@ -518,6 +524,13 @@
SideLabelTileLayout qqsLayout = (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
View view = mQs.getView();
List<String> specs = mPagedLayout.getSpecsForPage(page);
+ if (specs.isEmpty()) {
+ // specs should not be empty in a valid secondary page, as we scrolled to it.
+ // We may crash later on because there's a null animator.
+ specs = mQsPanelController.getHost().mTileSpecs;
+ Log.e(TAG, "Trying to create animators for empty page " + page + ". Tiles: " + specs);
+ // return null;
+ }
int row = -1;
int lastTileTop = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 8c08873..f2dd770 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -102,7 +102,7 @@
private int mTopViewMeasureHeight;
@NonNull
- private List<String> mRssiIgnoredSlots;
+ private List<String> mRssiIgnoredSlots = List.of();
private boolean mIsSingleCarrier;
private boolean mHasCenterCutout;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ccec0c2..16ddb0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -293,6 +293,14 @@
}
}
+ /**
+ * Cleanup
+ */
+ public void destroy() {
+ mHandler.removeCallbacksAndMessages(null);
+ mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ }
+
private void handleAlignStateChanged(int alignState) {
String alignmentIndication = "";
if (alignState == DockManager.ALIGN_STATE_POOR) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 94a6d3e..66c1d87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -507,12 +507,11 @@
Math.max(cx + cy, cx + (h - cy)),
Math.max((w - cx) + cy, (w - cx) + (h - cy)));
- riv.setRevealParameters(cx, cy, r);
- riv.setPendingIntent(pendingIntent);
+ riv.getController().setRevealParams(new RemoteInputView.RevealParams(cx, cy, r));
riv.getController().setPendingIntent(pendingIntent);
- riv.setRemoteInput(inputs, input, editedSuggestionInfo);
riv.getController().setRemoteInput(input);
riv.getController().setRemoteInputs(inputs);
+ riv.getController().setEditedSuggestionInfo(editedSuggestionInfo);
riv.focusAnimated();
if (userMessageContent != null) {
riv.setEditTextContent(userMessageContent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3dd717d..eaa66bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -226,10 +226,7 @@
? MathUtils.lerp(shortestWidth, getWidth(), fractionToShade)
: getWidth();
ActivatableNotificationView anv = (ActivatableNotificationView) this;
- NotificationBackgroundView bg = anv.getBackgroundNormal();
- if (bg != null) {
- anv.getBackgroundNormal().setActualWidth((int) actualWidth);
- }
+ anv.setBackgroundWidth((int) actualWidth);
if (mShelfIcons != null) {
mShelfIcons.setActualLayoutWidth((int) actualWidth);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 465ab93..3013ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -188,7 +188,7 @@
setContentDescription(state.contentDescription);
int newVisibility = state.visible && !mForceHidden ? View.VISIBLE : View.GONE;
- if (newVisibility != mMobileGroup.getVisibility()) {
+ if (newVisibility != mMobileGroup.getVisibility() && STATE_ICON == mVisibleState) {
mMobileGroup.setVisibility(newVisibility);
needsLayout = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index fca2aa1..577d536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -163,10 +163,13 @@
}
/**
- * @return The background of this view.
+ * @param width The actual width to apply to the background view.
*/
- public NotificationBackgroundView getBackgroundNormal() {
- return mBackgroundNormal;
+ public void setBackgroundWidth(int width) {
+ if (mBackgroundNormal == null) {
+ return;
+ }
+ mBackgroundNormal.setActualWidth(width);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9cb5dc5..adb4ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -413,7 +413,10 @@
if (mExpandedRemoteInput != null) {
mExpandedRemoteInput.onNotificationUpdateOrReset();
if (mExpandedRemoteInput.isActive()) {
- mPreviousExpandedRemoteInputIntent = mExpandedRemoteInput.getPendingIntent();
+ if (mExpandedRemoteInputController != null) {
+ mPreviousExpandedRemoteInputIntent =
+ mExpandedRemoteInputController.getPendingIntent();
+ }
mCachedExpandedRemoteInput = mExpandedRemoteInput;
mCachedExpandedRemoteInputViewController = mExpandedRemoteInputController;
mExpandedRemoteInput.dispatchStartTemporaryDetach();
@@ -460,7 +463,10 @@
if (mHeadsUpRemoteInput != null) {
mHeadsUpRemoteInput.onNotificationUpdateOrReset();
if (mHeadsUpRemoteInput.isActive()) {
- mPreviousHeadsUpRemoteInputIntent = mHeadsUpRemoteInput.getPendingIntent();
+ if (mHeadsUpRemoteInputController != null) {
+ mPreviousHeadsUpRemoteInputIntent =
+ mHeadsUpRemoteInputController.getPendingIntent();
+ }
mCachedHeadsUpRemoteInput = mHeadsUpRemoteInput;
mCachedHeadsUpRemoteInputViewController = mHeadsUpRemoteInputController;
mHeadsUpRemoteInput.dispatchStartTemporaryDetach();
@@ -961,14 +967,16 @@
private void transferRemoteInputFocus(int visibleType) {
if (visibleType == VISIBLE_TYPE_HEADSUP
- && mHeadsUpRemoteInput != null
- && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
- mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+ && mHeadsUpRemoteInputController != null
+ && mExpandedRemoteInputController != null
+ && mExpandedRemoteInputController.isActive()) {
+ mHeadsUpRemoteInputController.stealFocusFrom(mExpandedRemoteInputController);
}
if (visibleType == VISIBLE_TYPE_EXPANDED
- && mExpandedRemoteInput != null
- && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
- mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+ && mExpandedRemoteInputController != null
+ && mHeadsUpRemoteInputController != null
+ && mHeadsUpRemoteInputController.isActive()) {
+ mExpandedRemoteInputController.stealFocusFrom(mHeadsUpRemoteInputController);
}
}
@@ -1313,7 +1321,6 @@
// If we find a matching action in the new notification, focus, otherwise close.
Notification.Action[] actions = entry.getSbn().getNotification().actions;
if (existingPendingIntent != null) {
- result.mView.setPendingIntent(existingPendingIntent);
result.mController.setPendingIntent(existingPendingIntent);
}
if (result.mController.updatePendingIntentFromActions(actions)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index be1aa10..ade95a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -758,29 +758,38 @@
mDebugTextUsedYPositions.clear();
}
int y = mTopPadding;
- drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding");
+ drawDebugInfo(canvas, y, Color.RED, /* label= */ "mTopPadding = "+y);
y = getLayoutHeight();
- drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight()");
+ drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = "+y);
y = (int) mMaxLayoutHeight;
- drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight");
+ drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = "+y);
if (mKeyguardBottomPadding >= 0) {
y = getHeight() - (int) mKeyguardBottomPadding;
drawDebugInfo(canvas, y, Color.GRAY,
- /* label= */ "getHeight() - mKeyguardBottomPadding");
+ /* label= */ "getHeight() - mKeyguardBottomPadding = "+y);
}
y = getHeight() - getEmptyBottomMargin();
- drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeight() - getEmptyBottomMargin()");
+ drawDebugInfo(canvas, y, Color.GREEN,
+ /* label= */ "getHeight() - getEmptyBottomMargin() = "+y);
y = (int) (mAmbientState.getStackY());
- drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY()");
+ drawDebugInfo(canvas, y, Color.CYAN, /* label= */ "mAmbientState.getStackY() = "+y);
y = (int) (mAmbientState.getStackY() + mAmbientState.getStackHeight());
drawDebugInfo(canvas, y, Color.BLUE,
- /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight()");
+ /* label= */ "mAmbientState.getStackY() + mAmbientState.getStackHeight() = "+y);
+
+ y = (int) mAmbientState.getStackY() + mContentHeight;
+ drawDebugInfo(canvas, y, Color.MAGENTA,
+ /* label= */ "mAmbientState.getStackY() + mContentHeight = " + y);
+
+ y = (int) mAmbientState.getStackY() + mIntrinsicContentHeight;
+ drawDebugInfo(canvas, y, Color.YELLOW,
+ /* label= */ "mAmbientState.getStackY() + mIntrinsicContentHeight = " + y);
}
private void drawDebugInfo(Canvas canvas, int y, int color, String label) {
@@ -1292,14 +1301,13 @@
mOnStackYChanged.accept(listenerNeedsAnimation);
}
if (mQsExpansionFraction <= 0 && !shouldSkipHeightUpdate()) {
- final float endHeight = updateStackEndHeight(
- getHeight(), getEmptyBottomMargin(), mTopPadding);
+ final float endHeight = updateStackEndHeight();
updateStackHeight(endHeight, fraction);
}
}
- public float updateStackEndHeight(float height, float bottomMargin, float topPadding) {
- final float stackEndHeight = Math.max(0f, height - bottomMargin - topPadding);
+ private float updateStackEndHeight() {
+ final float stackEndHeight = Math.max(0f, mIntrinsicContentHeight);
mAmbientState.setStackEndHeight(stackEndHeight);
return stackEndHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 952cd9a..e1f8c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -202,12 +202,10 @@
float newHeight = state.height;
float newNotificationEnd = newYTranslation + newHeight;
boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
- final boolean shadeClosedWithHUN =
- ambientState.isShadeOpening() && !ambientState.isShadeExpanded();
if (mClipNotificationScrollToTop
&& (!state.inShelf || (isHeadsUp && !firstHeadsUp))
&& newYTranslation < clipStart
- && shadeClosedWithHUN) {
+ && !ambientState.isShadeExpanded()) {
// The previous view is overlapping on top, clip!
float overlapAmount = clipStart - newYTranslation;
state.clipTopAmount = (int) overlapAmount;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 48949f92..4d6d05f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -22,8 +22,6 @@
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.RemoteInput;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -75,7 +73,6 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -111,21 +108,15 @@
private ProgressBar mProgressBar;
private ImageView mDelete;
private ImageView mDeleteBg;
- // TODO(b/193539698): remove reveal param fields, turn them into parameters where needed
- private int mRevealCx;
- private int mRevealCy;
- private int mRevealR;
private boolean mColorized;
private int mTint;
private boolean mResetting;
+ @Nullable private RevealParams mRevealParams;
// TODO(b/193539698): move these to a Controller
private RemoteInputController mController;
private final UiEventLogger mUiEventLogger;
private NotificationEntry mEntry;
- private PendingIntent mPendingIntent;
- private RemoteInput mRemoteInput;
- private RemoteInput[] mRemoteInputs;
private boolean mRemoved;
private NotificationViewWrapper mWrapper;
@@ -397,9 +388,8 @@
// During removal, we get reattached and lose focus. Not hiding in that
// case to prevent flicker.
if (!mRemoved) {
- if (animate && mRevealR > 0) {
- Animator reveal = ViewAnimationUtils.createCircularReveal(
- this, mRevealCx, mRevealCy, mRevealR, 0);
+ if (animate && mRevealParams != null && mRevealParams.radius > 0) {
+ Animator reveal = mRevealParams.createCircularHideAnimator(this);
reveal.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
reveal.setDuration(StackStateAnimator.ANIMATION_DURATION_CLOSE_REMOTE_INPUT);
reveal.addListener(new AnimatorListenerAdapter() {
@@ -454,30 +444,12 @@
mController.removeSpinning(mEntry.getKey(), mToken);
}
- public void setPendingIntent(PendingIntent pendingIntent) {
- mPendingIntent = pendingIntent;
+ public void setHintText(CharSequence hintText) {
+ mEditText.setHint(hintText);
}
- /**
- * Sets the remote input for this view.
- *
- * @param remoteInputs The remote inputs that need to be sent to the app.
- * @param remoteInput The remote input that needs to be activated.
- * @param editedSuggestionInfo The smart reply that should be inserted in the remote input, or
- * {@code null} if the user is not editing a smart reply.
- */
- public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput,
- @Nullable EditedSuggestionInfo editedSuggestionInfo) {
- mRemoteInputs = remoteInputs;
- mRemoteInput = remoteInput;
- mEditText.setHint(mRemoteInput.getLabel());
- mEditText.setSupportedMimeTypes(remoteInput.getAllowedDataTypes());
-
- mEntry.editedSuggestionInfo = editedSuggestionInfo;
- if (editedSuggestionInfo != null) {
- mEntry.remoteInputText = editedSuggestionInfo.originalText;
- mEntry.remoteInputAttachment = null;
- }
+ public void setSupportedMimeTypes(Collection<String> mimeTypes) {
+ mEditText.setSupportedMimeTypes(mimeTypes);
}
/** Populates the text field of the remote input with the given content. */
@@ -486,9 +458,8 @@
}
public void focusAnimated() {
- if (getVisibility() != VISIBLE) {
- Animator animator = ViewAnimationUtils.createCircularReveal(
- this, mRevealCx, mRevealCy, 0, mRevealR);
+ if (getVisibility() != VISIBLE && mRevealParams != null) {
+ Animator animator = mRevealParams.createCircularRevealAnimator(this);
animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.start();
@@ -587,30 +558,12 @@
return mEditText.isFocused() && mEditText.isEnabled();
}
- // TODO(b/193539698): move this to the controller
- public void stealFocusFrom(RemoteInputView other) {
- other.close();
- setPendingIntent(other.mPendingIntent);
- setRemoteInput(other.mRemoteInputs, other.mRemoteInput, mEntry.editedSuggestionInfo);
- setRevealParameters(other.mRevealCx, other.mRevealCy, other.mRevealR);
- getController().setPendingIntent(other.mPendingIntent);
- getController().setRemoteInput(other.mRemoteInput);
- getController().setRemoteInputs(other.mRemoteInputs);
- focus();
- }
-
- public PendingIntent getPendingIntent() {
- return mPendingIntent;
- }
-
public void setRemoved() {
mRemoved = true;
}
- public void setRevealParameters(int cx, int cy, int r) {
- mRevealCx = cx;
- mRevealCy = cy;
- mRevealR = r;
+ public void setRevealParameters(@Nullable RevealParams revealParams) {
+ mRevealParams = revealParams;
}
@Override
@@ -938,4 +891,24 @@
}
}
+
+ public static class RevealParams {
+ final int centerX;
+ final int centerY;
+ final int radius;
+
+ public RevealParams(int centerX, int centerY, int radius) {
+ this.centerX = centerX;
+ this.centerY = centerY;
+ this.radius = radius;
+ }
+
+ Animator createCircularRevealAnimator(View view) {
+ return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, radius, 0);
+ }
+
+ Animator createCircularHideAnimator(View view) {
+ return ViewAnimationUtils.createCircularReveal(view, centerX, centerY, 0, radius);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
index ef0a5b4..f845101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
@@ -33,7 +33,9 @@
import com.android.systemui.statusbar.NotificationRemoteInputManager
import com.android.systemui.statusbar.RemoteInputController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo
import com.android.systemui.statusbar.policy.RemoteInputView.NotificationRemoteInputEvent
+import com.android.systemui.statusbar.policy.RemoteInputView.RevealParams
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewScope
import javax.inject.Inject
@@ -41,6 +43,8 @@
fun bind()
fun unbind()
+ val isActive: Boolean
+
/**
* A [NotificationRemoteInputManager.BouncerChecker] that will be used to determine if the
* device needs to be unlocked before sending the RemoteInput.
@@ -55,6 +59,14 @@
/** Other [RemoteInput]s from the notification associated with this Controller. */
var remoteInputs: Array<RemoteInput>?
+ var revealParams: RevealParams?
+
+ /**
+ * Sets the smart reply that should be inserted in the remote input, or `null` if the user is
+ * not editing a smart reply.
+ */
+ fun setEditedSuggestionInfo(info: EditedSuggestionInfo?)
+
/**
* Tries to find an action in {@param actions} that matches the current pending intent
* of this view and updates its state to that of the found action
@@ -68,6 +80,19 @@
/** Unregisters a listener previously registered via [addOnSendRemoteInputListener] */
fun removeOnSendRemoteInputListener(listener: OnSendRemoteInputListener)
+
+ fun close()
+
+ fun focus()
+
+ fun stealFocusFrom(other: RemoteInputViewController) {
+ other.close()
+ remoteInput = other.remoteInput
+ remoteInputs = other.remoteInputs
+ revealParams = other.revealParams
+ pendingIntent = other.pendingIntent
+ focus()
+ }
}
/** Listener for send events */
@@ -100,15 +125,41 @@
private var isBound = false
- override var pendingIntent: PendingIntent? = null
override var bouncerChecker: NotificationRemoteInputManager.BouncerChecker? = null
+
override var remoteInput: RemoteInput? = null
+ set(value) {
+ field = value
+ value?.takeIf { isBound }?.let {
+ view.setHintText(it.label)
+ view.setSupportedMimeTypes(it.allowedDataTypes)
+ }
+ }
+
+ override var pendingIntent: PendingIntent? = null
override var remoteInputs: Array<RemoteInput>? = null
+ override var revealParams: RevealParams? = null
+ set(value) {
+ field = value
+ if (isBound) {
+ view.setRevealParameters(value)
+ }
+ }
+
+ override val isActive: Boolean get() = view.isActive
+
override fun bind() {
if (isBound) return
isBound = true
+ // TODO: refreshUI method?
+ remoteInput?.let {
+ view.setHintText(it.label)
+ view.setSupportedMimeTypes(it.allowedDataTypes)
+ }
+ view.setRevealParameters(revealParams)
+
view.addOnEditTextFocusChangedListener(onFocusChangeListener)
view.addOnSendRemoteInputListener(onSendRemoteInputListener)
}
@@ -121,6 +172,14 @@
view.removeOnSendRemoteInputListener(onSendRemoteInputListener)
}
+ override fun setEditedSuggestionInfo(info: EditedSuggestionInfo?) {
+ entry.editedSuggestionInfo = info
+ if (info != null) {
+ entry.remoteInputText = info.originalText
+ entry.remoteInputAttachment = null
+ }
+ }
+
override fun updatePendingIntentFromActions(actions: Array<Notification.Action>?): Boolean {
actions ?: return false
val current: Intent = pendingIntent?.intent ?: return false
@@ -132,8 +191,7 @@
pendingIntent = actionIntent
remoteInput = input
remoteInputs = inputs
- view.pendingIntent = actionIntent
- view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */)
+ setEditedSuggestionInfo(null)
return true
}
return false
@@ -148,6 +206,14 @@
onSendListeners.remove(listener)
}
+ override fun close() {
+ view.close()
+ }
+
+ override fun focus() {
+ view.focus()
+ }
+
private val onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
remoteInputQuickSettingsDisabler.setRemoteInputActive(hasFocus)
}
@@ -217,11 +283,12 @@
* @return returns intent with granted URI permissions that should be used immediately
*/
private fun prepareRemoteInput(remoteInput: RemoteInput): Intent =
- if (entry.remoteInputAttachment == null) prepareRemoteInputFromText(remoteInput)
- else prepareRemoteInputFromData(
- remoteInput,
- entry.remoteInputMimeType,
- entry.remoteInputUri)
+ if (entry.remoteInputAttachment == null)
+ prepareRemoteInputFromText(remoteInput)
+ else prepareRemoteInputFromData(
+ remoteInput,
+ entry.remoteInputMimeType,
+ entry.remoteInputUri)
private fun prepareRemoteInputFromText(remoteInput: RemoteInput): Intent {
val results = Bundle()
@@ -232,11 +299,7 @@
view.clearAttachment()
entry.remoteInputUri = null
entry.remoteInputMimeType = null
- if (entry.editedSuggestionInfo == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
- } else {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
- }
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
@@ -266,11 +329,12 @@
entry.remoteInputText = fullText
// mirror prepareRemoteInputFromText for text input
- if (entry.editedSuggestionInfo == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_FREE_FORM_INPUT)
- } else if (entry.remoteInputAttachment == null) {
- RemoteInput.setResultsSource(fillInIntent, RemoteInput.SOURCE_CHOICE)
- }
+ RemoteInput.setResultsSource(fillInIntent, remoteInputResultsSource)
return fillInIntent
}
+
+ private val remoteInputResultsSource
+ get() = entry.editedSuggestionInfo
+ ?.let { RemoteInput.SOURCE_CHOICE }
+ ?: RemoteInput.SOURCE_FREE_FORM_INPUT
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
new file mode 100644
index 0000000..c0538c1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.util.animation
+
+import kotlin.math.roundToLong
+
+/** A generic util class for animations in SysUI. */
+class AnimationUtil {
+ companion object {
+ /**
+ * Returns the number of milliseconds there are in [numFrames] for a 60 fps device.
+ *
+ * Note that this method can be used on any device, not just 60 fps devices. Animation
+ * lengths are typically specified in terms of number of frames for a 60 fps device, and
+ * the value "5 frames" is often more meaningful than "83ms". This method allows us to
+ * write animation code in terms of the more meaningful "5" number.
+ *
+ * @param numFrames must be >= 0.
+ */
+ fun getMsForFrames(numFrames: Int): Long {
+ if (numFrames < 0) {
+ throw IllegalArgumentException("numFrames must be >= 0")
+ }
+ return (numFrames * 1000f / 60f).roundToLong()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a49c4d7..c684b66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -172,11 +172,10 @@
@Test
public void enableWindowMagnification_notifySourceBoundsChanged() {
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
- Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
- /* magnificationFrameOffsetRatioY= */ 0, null);
- });
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN, /* magnificationFrameOffsetRatioX= */ 0,
+ /* magnificationFrameOffsetRatioY= */ 0, null));
// Waits for the surface created
verify(mWindowMagnifierCallback, timeout(LAYOUT_CHANGE_TIMEOUT_MS)).onSourceBoundsChanged(
@@ -184,6 +183,16 @@
}
@Test
+ public void enableWindowMagnification_disabled_notifySourceBoundsChanged() {
+ enableWindowMagnification_notifySourceBoundsChanged();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.deleteWindowMagnification(null));
+ Mockito.reset(mWindowMagnifierCallback);
+
+ enableWindowMagnification_notifySourceBoundsChanged();
+ }
+
+ @Test
public void enableWindowMagnification_withAnimation_schedulesFrame() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(2.0f, 10,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index badafa4..f4b378e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -27,6 +27,7 @@
import static com.android.systemui.doze.DozeMachine.State.FINISH;
import static com.android.systemui.doze.DozeMachine.State.INITIALIZED;
import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
@@ -468,37 +469,39 @@
public void transitionToDoze_shouldClampBrightness_afterTimeout_clampsToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
// If we're dozing after a timeout, and playing the unlocked screen animation, we should
// stay at or below dim brightness, because the screen dims just before timeout.
assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
+
+ // Once we transition to Doze, use the doze brightness
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
}
@Test
public void transitionToDoze_shouldClampBrightness_notAfterTimeout_doesNotClampToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(true);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(true);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
// If we're playing the unlocked screen off animation after a power button press, we should
// leave the brightness alone.
assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
+
+ mScreen.transitionTo(INITIALIZED, DOZE);
+ assertEquals(mServiceFake.screenBrightness, DEFAULT_BRIGHTNESS);
}
@Test
public void transitionToDoze_noClampBrightness_afterTimeout_noScreenOff_doesNotClampToDim() {
when(mWakefulnessLifecycle.getLastSleepReason()).thenReturn(
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
@@ -514,11 +517,9 @@
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE);
assertTrue(mServiceFake.screenBrightness <= DIM_BRIGHTNESS);
}
@@ -529,7 +530,6 @@
PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON);
when(mWakefulnessLifecycle.getWakefulness()).thenReturn(
WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
- when(mDozeParameters.shouldControlUnlockedScreenOff()).thenReturn(false);
when(mDozeParameters.shouldClampToDimBrightness()).thenReturn(false);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
index ccce577..962d78c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
@@ -81,6 +81,9 @@
whenever(packageManager.getApplicationIcon(PACKAGE_NAME)).thenReturn(appIconFromPackageName)
whenever(applicationInfo.loadLabel(packageManager)).thenReturn(APP_NAME)
whenever(packageManager.getApplicationInfo(
+ any(), any<PackageManager.ApplicationInfoFlags>()
+ )).thenThrow(PackageManager.NameNotFoundException())
+ whenever(packageManager.getApplicationInfo(
eq(PACKAGE_NAME), any<PackageManager.ApplicationInfoFlags>()
)).thenReturn(applicationInfo)
context.setMockPackageManager(packageManager)
@@ -189,6 +192,28 @@
verify(windowManager, never()).removeView(any())
}
+
+ @Test
+ fun displayChip_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
+
+ @Test
+ fun displayChip_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+ )
+
+ assertThat(chipView.getAppIconView().drawable).isNotNull()
+ }
@Test
fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
@@ -212,6 +237,28 @@
}
@Test
+ fun displayChip_nullAppNameAndNullPackageName_stillHasContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
+ fun displayChip_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
+ controllerCommon.displayChip(getState())
+ val chipView = getChipView()
+
+ controllerCommon.setIcon(
+ chipView, appPackageName = "fakePackageName", appNameOverride = null
+ )
+
+ assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+ }
+
+ @Test
fun displayChip_nullAppName_iconContentDescriptionIsFromPackageName() {
controllerCommon.displayChip(getState())
val chipView = getChipView()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 3c1a73e..ad643fe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -226,6 +226,10 @@
@After
public void tearDown() throws Exception {
mTextView.setAnimationsEnabled(true);
+ if (mController != null) {
+ mController.destroy();
+ mController = null;
+ }
}
private void createController() {
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 ca8529d..52bacd2 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
@@ -39,13 +39,18 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+/**
+ * TODO(b/224771204) Create test cases
+ */
@SmallTest
@RunWith(AndroidTestingRunner.class)
+@Ignore
public class KeyguardCoordinatorTest extends SysuiTestCase {
private static final int NOTIF_USER_ID = 0;
private static final int CURR_USER_ID = 1;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index eafcc35..56541f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -161,17 +161,6 @@
}
@Test
- public void testUpdateStackEndHeight_forEndOfStackHeightAnimation() {
- final float nsslHeight = 10f;
- final float bottomMargin = 1f;
- final float topPadding = 1f;
-
- mStackScroller.updateStackEndHeight(nsslHeight, bottomMargin, topPadding);
- final float stackEndHeight = nsslHeight - bottomMargin - topPadding;
- assertTrue(mAmbientState.getStackEndHeight() == stackEndHeight);
- }
-
- @Test
public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
final float dozeAmount = 0.5f;
mAmbientState.setDozeAmount(dozeAmount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 20a3fda..3a0a7c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -114,15 +114,13 @@
mContext.unregisterReceiver(mReceiver);
}
- private void setTestPendingIntent(RemoteInputView view, RemoteInputViewController controller) {
+ private void setTestPendingIntent(RemoteInputViewController controller) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(TEST_ACTION), PendingIntent.FLAG_MUTABLE);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).build();
RemoteInput[] inputs = {input};
- view.setPendingIntent(pendingIntent);
controller.setPendingIntent(pendingIntent);
- view.setRemoteInput(inputs, input, null /* editedSuggestionInfo */);
controller.setRemoteInput(input);
controller.setRemoteInputs(inputs);
}
@@ -137,7 +135,7 @@
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
view.focus();
@@ -177,7 +175,7 @@
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
view.focus();
@@ -235,7 +233,7 @@
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
// Open view, send a reply
view.focus();
@@ -265,7 +263,7 @@
RemoteInputView view = RemoteInputView.inflate(mContext, null, row.getEntry(), mController);
RemoteInputViewController controller = bindController(view, row.getEntry());
- setTestPendingIntent(view, controller);
+ setTestPendingIntent(controller);
// Open view, attach an image
view.focus();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
new file mode 100644
index 0000000..92afb03
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.util.animation
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import java.lang.IllegalArgumentException
+
+@SmallTest
+class AnimationUtilTest : SysuiTestCase() {
+ @Test
+ fun getMsForFrames_5frames_returns83() {
+ assertThat(AnimationUtil.getMsForFrames(5)).isEqualTo(83L)
+ }
+
+ @Test
+ fun getMsForFrames_7frames_returns117() {
+ assertThat(AnimationUtil.getMsForFrames(7)).isEqualTo(117L)
+ }
+
+ @Test
+ fun getMsForFrames_30frames_returns500() {
+ assertThat(AnimationUtil.getMsForFrames(30)).isEqualTo(500L)
+ }
+
+ @Test
+ fun getMsForFrames_60frames_returns1000() {
+ assertThat(AnimationUtil.getMsForFrames(60)).isEqualTo(1000L)
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun getMsForFrames_negativeFrames_throwsException() {
+ AnimationUtil.getMsForFrames(-1)
+ }
+}
diff --git a/proto/src/camera.proto b/proto/src/camera.proto
index 4082118..38d74e4 100644
--- a/proto/src/camera.proto
+++ b/proto/src/camera.proto
@@ -66,5 +66,5 @@
// The dynamic range profile of the stream
optional int64 dynamic_range_profile = 14;
// The stream use case
- optional int32 stream_use_case = 15;
+ optional int64 stream_use_case = 15;
}
diff --git a/services/api/current.txt b/services/api/current.txt
index 5a28802..780fccf 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -47,6 +47,9 @@
package com.android.server.pm {
public interface PackageManagerLocal {
+ method public void reconcileSdkData(@Nullable String, @NonNull String, @NonNull java.util.List<java.lang.String>, int, int, int, @NonNull String, int) throws java.io.IOException;
+ field public static final int FLAG_STORAGE_CE = 2; // 0x2
+ field public static final int FLAG_STORAGE_DE = 1; // 0x1
}
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index e10151d..1af35af 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -89,8 +89,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.storage.IStorageManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -325,7 +323,6 @@
private final ActivityManagerInternal mActivityManagerInternal;
private PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
- private final IStorageManager mStorageManager;
private final BackupManagerConstants mConstants;
private final BackupWakeLock mWakelock;
private final BackupHandler mBackupHandler;
@@ -536,7 +533,6 @@
mBackupPasswordManager = null;
mPackageManagerBinder = null;
mActivityManager = null;
- mStorageManager = null;
mBackupManagerBinder = null;
mScheduledBackupEligibility = null;
}
@@ -560,7 +556,6 @@
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
Objects.requireNonNull(parent, "parent cannot be null");
mBackupManagerBinder = BackupManagerService.asInterface(parent.asBinder());
@@ -2077,26 +2072,6 @@
}
}
- /** For adb backup/restore. */
- public boolean deviceIsEncrypted() {
- try {
- return mStorageManager.getEncryptionState()
- != StorageManager.ENCRYPTION_STATE_NONE
- && mStorageManager.getPasswordType()
- != StorageManager.CRYPT_TYPE_DEFAULT;
- } catch (Exception e) {
- // If we can't talk to the storagemanager service we have a serious problem; fail
- // "secure" i.e. assuming that the device is encrypted.
- Slog.e(
- TAG,
- addUserIdToLogMessage(
- mUserId,
- "Unable to communicate with storagemanager service: "
- + e.getMessage()));
- return true;
- }
- }
-
// ----- Full-data backup scheduling -----
/**
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 7ee307e..ec58e17 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -320,12 +320,6 @@
try {
boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
- // Only allow encrypted backups of encrypted devices
- if (mUserBackupManagerService.deviceIsEncrypted() && !encrypting) {
- Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
- return;
- }
-
OutputStream finalOutput = ofstream;
// Verify that the given password matches the currently-active
diff --git a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
index 116c739..8e0e395 100644
--- a/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
+++ b/services/cloudsearch/java/com/android/server/cloudsearch/CloudSearchPerUserService.java
@@ -107,6 +107,10 @@
@GuardedBy("mLock")
public void onSearchLocked(@NonNull SearchRequest searchRequest,
@NonNull ICloudSearchManagerCallback callback) {
+ if (mRemoteComponentName == null) {
+ return;
+ }
+
String filterList = searchRequest.getSearchConstraints().containsKey(
SearchRequest.CONSTRAINT_SEARCH_PROVIDER_FILTER)
? searchRequest.getSearchConstraints().getString(
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index f32eebc..2a83a3c 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -49,7 +49,7 @@
* The following is the list of the APIs provided by {@link CompanionApplicationController} (to be
* utilized by {@link CompanionDeviceManagerService}):
* <ul>
- * <li> {@link #bindCompanionApplication(int, String)}
+ * <li> {@link #bindCompanionApplication(int, String, boolean)}
* <li> {@link #unbindCompanionApplication(int, String)}
* <li> {@link #notifyCompanionApplicationDeviceAppeared(AssociationInfo)}
* <li> {@link #notifyCompanionApplicationDeviceDisappeared(AssociationInfo)}
@@ -103,8 +103,12 @@
mCompanionServicesRegister.invalidate(userId);
}
- void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName) {
- if (DEBUG) Log.i(TAG, "bind() u" + userId + "/" + packageName);
+ void bindCompanionApplication(@UserIdInt int userId, @NonNull String packageName,
+ boolean bindImportant) {
+ if (DEBUG) {
+ Log.i(TAG, "bind() u" + userId + "/" + packageName
+ + " important=" + bindImportant);
+ }
final List<ComponentName> companionServices =
mCompanionServicesRegister.forPackage(userId, packageName);
@@ -125,7 +129,8 @@
}
serviceConnectors = CollectionUtils.map(companionServices, componentName ->
- new CompanionDeviceServiceConnector(mContext, userId, componentName));
+ CompanionDeviceServiceConnector.newInstance(mContext, userId,
+ componentName, bindImportant));
mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index eaa99f7..13a5a28 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -254,9 +254,12 @@
final int userId = association.getUserId();
final String packageName = association.getPackageName();
+ // Set bindImportant to true when the association is self-managed to avoid the target
+ // service being killed.
+ final boolean bindImportant = association.isSelfManaged();
if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
- mCompanionAppController.bindCompanionApplication(userId, packageName);
+ mCompanionAppController.bindCompanionApplication(userId, packageName, bindImportant);
} else if (DEBUG) {
Log.i(TAG, "u" + userId + "\\" + packageName + " is already bound");
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index f2a58b7..4c7b9b8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -16,6 +16,7 @@
package com.android.server.companion;
+import static android.content.Context.BIND_ALMOST_PERCEPTIBLE;
import static android.content.Context.BIND_IMPORTANT;
import static android.os.Process.THREAD_PRIORITY_DEFAULT;
@@ -44,20 +45,43 @@
class CompanionDeviceServiceConnector extends ServiceConnector.Impl<ICompanionDeviceService> {
private static final String TAG = "CompanionDevice_ServiceConnector";
private static final boolean DEBUG = false;
- private static final int BINDING_FLAGS = BIND_IMPORTANT;
/** Listener for changes to the state of the {@link CompanionDeviceServiceConnector} */
interface Listener {
void onBindingDied(@UserIdInt int userId, @NonNull String packageName);
}
- private final @UserIdInt int mUserId;
- private final @NonNull ComponentName mComponentName;
- private @Nullable Listener mListener;
+ @UserIdInt
+ private final int mUserId;
+ @NonNull
+ private final ComponentName mComponentName;
+ @Nullable
+ private Listener mListener;
- CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
- @NonNull ComponentName componentName) {
- super(context, buildIntent(componentName), BINDING_FLAGS, userId, null);
+ /**
+ * Create a CompanionDeviceServiceConnector instance.
+ *
+ * When bindImportant is false, the binding flag will be BIND_ALMOST_PERCEPTIBLE
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = 225). The target service will be treated
+ * as important as a perceptible app (IMPORTANCE_VISIBLE = 200), and will be unbound when
+ * the app is removed from task manager.
+ * When bindImportant is true, the binding flag will be BIND_IMPORTANT
+ * (oom_score_adj = PERCEPTIBLE_MEDIUM_APP = -700). The target service will
+ * have the highest priority to avoid being killed (IMPORTANCE_FOREGROUND = 100).
+ *
+ * One time permission's importance level to keep session alive is
+ * IMPORTANCE_FOREGROUND_SERVICE = 125. In order to kill the one time permission session, the
+ * service importance level should be higher than 125.
+ */
+ static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
+ @UserIdInt int userId, @NonNull ComponentName componentName, boolean bindImportant) {
+ final int bindingFlags = bindImportant ? BIND_IMPORTANT : BIND_ALMOST_PERCEPTIBLE;
+ return new CompanionDeviceServiceConnector(context, userId, componentName, bindingFlags);
+ }
+
+ private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
+ @NonNull ComponentName componentName, int bindingFlags) {
+ super(context, buildIntent(componentName), bindingFlags, userId, null);
mUserId = userId;
mComponentName = componentName;
}
diff --git a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
index 1ba198a..823743d 100644
--- a/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
+++ b/services/companion/java/com/android/server/companion/presence/BluetoothCompanionDeviceConnectionListener.java
@@ -94,7 +94,7 @@
int reason) {
if (DEBUG) {
Log.i(TAG, "onDevice_Disconnected() " + btDeviceToString(device));
- Log.d(TAG, " reason=" + disconnectReasonText(reason));
+ Log.d(TAG, " reason=" + disconnectReasonToString(reason));
}
final MacAddress macAddress = MacAddress.fromString(device.getAddress());
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index be2b7f7..f1fa982 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -131,7 +131,7 @@
final UserManager userManager = context.getSystemService(UserManager.class);
final int result = userManager.removeUserWhenPossible(
UserHandle.of(userId), /* overrideDevicePolicy= */ false);
- if (result == UserManager.REMOVE_RESULT_ERROR) {
+ if (!UserManager.isRemoveResultSuccessful(result)) {
Slogf.e(TAG, "Can't remove user %d", userId);
return false;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7075ed3..677fc79 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3129,203 +3129,6 @@
}
}
- @Override
- public int getEncryptionState() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.fdeComplete();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
- }
- }
-
- @Override
- public int decryptStorage(String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "decrypting storage...");
- }
-
- try {
- mVold.fdeCheckPassword(password);
- mHandler.postDelayed(() -> {
- try {
- mVold.fdeRestart();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- }
- }, DateUtils.SECOND_IN_MILLIS);
- return 0;
- } catch (ServiceSpecificException e) {
- Slog.e(TAG, "fdeCheckPassword failed", e);
- return e.errorCode;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
- }
- }
-
- @Override
- public int encryptStorage(int type, String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
- password = "";
- } else if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "encrypting storage...");
- }
-
- try {
- mVold.fdeEnable(type, password, 0);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
-
- return 0;
- }
-
- /** Set the password for encrypting the main key.
- * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
- * @param password The password to set.
- */
- @Override
- public int changeEncryptionPassword(int type, String password) {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (StorageManager.isFileEncryptedNativeOnly()) {
- // Not supported on FBE devices
- return -1;
- }
-
- if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
- password = "";
- } else if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "changing encryption password...");
- }
-
- try {
- mVold.fdeChangePassword(type, password);
- return 0;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Validate a user-supplied password string with cryptfs
- */
- @Override
- public int verifyEncryptionPassword(String password) throws RemoteException {
- // Only the system process is permitted to validate passwords
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
- throw new SecurityException("no permission to access the crypt keeper");
- }
-
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
- if (DEBUG_EVENTS) {
- Slog.i(TAG, "validating encryption password...");
- }
-
- try {
- mVold.fdeVerifyPassword(password);
- return 0;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Get the type of encryption used to encrypt the main key.
- * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
- */
- @Override
- public int getPasswordType() {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- try {
- return mVold.fdeGetPasswordType();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return -1;
- }
- }
-
- /**
- * Set a field in the crypto header.
- * @param field field to set
- * @param contents contents to set in field
- */
- @Override
- public void setField(String field, String contents) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (!StorageManager.isBlockEncrypted()) {
- // Only supported on FDE devices
- return;
- }
-
- try {
- mVold.fdeSetField(field, contents);
- return;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return;
- }
- }
-
- /**
- * Gets a field from the crypto header.
- * @param field field to get
- * @return contents of field
- */
- @Override
- public String getField(String field) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "no permission to access the crypt keeper");
-
- if (!StorageManager.isBlockEncrypted()) {
- // Only supported on FDE devices
- return null;
- }
-
- try {
- return mVold.fdeGetField(field);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return null;
- }
- }
-
/**
* Is userdata convertible to file based encryption?
* @return non zero for convertible
@@ -3408,33 +3211,6 @@
}
@Override
- public String getPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "only keyguard can retrieve password");
-
- try {
- return mVold.fdeGetPassword();
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return null;
- }
- }
-
- @Override
- public void clearPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
- "only keyguard can clear password");
-
- try {
- mVold.fdeClearPassword();
- return;
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return;
- }
- }
-
- @Override
public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 569d480..2dfe947 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1302,7 +1302,7 @@
pw.print(" mLastBroadcastState="); pw.println(mLastBroadcastState);
pw.print(" mNightMode="); pw.print(mNightMode); pw.print(" (");
- pw.print(Shell.nightModeToStr(mNightMode)); pw.print(") ");
+ pw.print(Shell.nightModeToStr(mNightMode, mNightModeCustomType)); pw.print(") ");
pw.print(" mOverrideOn/Off="); pw.print(mOverrideNightModeOn);
pw.print("/"); pw.print(mOverrideNightModeOff);
@@ -1917,7 +1917,8 @@
public static final String NIGHT_MODE_STR_YES = "yes";
public static final String NIGHT_MODE_STR_NO = "no";
public static final String NIGHT_MODE_STR_AUTO = "auto";
- public static final String NIGHT_MODE_STR_CUSTOM = "custom";
+ public static final String NIGHT_MODE_STR_CUSTOM_SCHEDULE = "custom_schedule";
+ public static final String NIGHT_MODE_STR_CUSTOM_BEDTIME = "custom_bedtime";
public static final String NIGHT_MODE_STR_UNKNOWN = "unknown";
private final IUiModeManager mInterface;
@@ -1931,7 +1932,7 @@
pw.println("UiModeManager service (uimode) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" night [yes|no|auto|custom]");
+ pw.println(" night [yes|no|auto|custom_schedule|custom_bedtime]");
pw.println(" Set or read night mode.");
pw.println(" car [yes|no]");
pw.println(" Set or read car mode.");
@@ -2001,14 +2002,19 @@
}
final int mode = strToNightMode(modeStr);
+ final int customType = strToNightModeCustomType(modeStr);
if (mode >= 0) {
mInterface.setNightMode(mode);
+ if (mode == UiModeManager.MODE_NIGHT_CUSTOM) {
+ mInterface.setNightModeCustomType(customType);
+ }
printCurrentNightMode();
return 0;
} else {
err.println("Error: mode must be '" + NIGHT_MODE_STR_YES + "', '"
+ NIGHT_MODE_STR_NO + "', or '" + NIGHT_MODE_STR_AUTO
- + "', or '" + NIGHT_MODE_STR_CUSTOM + "'");
+ + "', or '" + NIGHT_MODE_STR_CUSTOM_SCHEDULE + "', or '"
+ + NIGHT_MODE_STR_CUSTOM_BEDTIME + "'");
return -1;
}
}
@@ -2016,11 +2022,12 @@
private void printCurrentNightMode() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final int currMode = mInterface.getNightMode();
- final String currModeStr = nightModeToStr(currMode);
+ final int customType = mInterface.getNightModeCustomType();
+ final String currModeStr = nightModeToStr(currMode, customType);
pw.println("Night mode: " + currModeStr);
}
- private static String nightModeToStr(int mode) {
+ private static String nightModeToStr(int mode, int customType) {
switch (mode) {
case UiModeManager.MODE_NIGHT_YES:
return NIGHT_MODE_STR_YES;
@@ -2029,7 +2036,12 @@
case UiModeManager.MODE_NIGHT_AUTO:
return NIGHT_MODE_STR_AUTO;
case MODE_NIGHT_CUSTOM:
- return NIGHT_MODE_STR_CUSTOM;
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE) {
+ return NIGHT_MODE_STR_CUSTOM_SCHEDULE;
+ }
+ if (customType == UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
+ return NIGHT_MODE_STR_CUSTOM_BEDTIME;
+ }
default:
return NIGHT_MODE_STR_UNKNOWN;
}
@@ -2043,13 +2055,25 @@
return UiModeManager.MODE_NIGHT_NO;
case NIGHT_MODE_STR_AUTO:
return UiModeManager.MODE_NIGHT_AUTO;
- case NIGHT_MODE_STR_CUSTOM:
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
return UiModeManager.MODE_NIGHT_CUSTOM;
default:
return -1;
}
}
+ private static int strToNightModeCustomType(String customTypeStr) {
+ switch (customTypeStr) {
+ case NIGHT_MODE_STR_CUSTOM_BEDTIME:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_BEDTIME;
+ case NIGHT_MODE_STR_CUSTOM_SCHEDULE:
+ return UiModeManager.MODE_NIGHT_CUSTOM_TYPE_SCHEDULE;
+ default:
+ return -1;
+ }
+ }
+
private int handleCarMode() throws RemoteException {
final PrintWriter err = getErrPrintWriter();
final String modeStr = getNextArg();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 48e3264..b0ab53907 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3801,6 +3801,18 @@
@GuardedBy("mAm")
void performScheduleRestartLocked(ServiceRecord r, @NonNull String scheduling,
@NonNull String reason, @UptimeMillisLong long now) {
+
+ // If the service is waiting to become a foreground service, remove the pending
+ // SERVICE_FOREGROUND_TIMEOUT_MSG msg, and set fgWaiting to false, so next time the service
+ // is brought up, scheduleServiceForegroundTransitionTimeoutLocked() can be called again and
+ // a new SERVICE_FOREGROUND_TIMEOUT_MSG is scheduled in SERVICE_START_FOREGROUND_TIMEOUT
+ // again.
+ if (r.fgRequired && r.fgWaiting) {
+ mAm.mHandler.removeMessages(
+ ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
+ r.fgWaiting = false;
+ }
+
mAm.mHandler.removeCallbacks(r.restarter);
mAm.mHandler.postAtTime(r.restarter, r.nextRestartTime);
r.nextRestartTime = now + r.restartDelay;
@@ -5678,7 +5690,7 @@
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
- if (!r.fgRequired || r.destroying) {
+ if (!r.fgRequired || !r.fgWaiting || r.destroying) {
return;
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 7cd45fe..ea1e335 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -28,7 +28,6 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.BatteryConsumer.POWER_COMPONENT_ANY;
import static android.os.BatteryConsumer.PROCESS_STATE_BACKGROUND;
-import static android.os.BatteryConsumer.PROCESS_STATE_COUNT;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND;
import static android.os.BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.os.BatteryConsumer.PROCESS_STATE_UNSPECIFIED;
@@ -38,7 +37,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNAMESPACE_PREFIX;
-import static com.android.server.am.BaseAppStateTracker.ONE_MINUTE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -71,7 +69,6 @@
import com.android.internal.util.ArrayUtils;
import com.android.server.am.AppBatteryTracker.AppBatteryPolicy;
import com.android.server.am.AppRestrictionController.UidBatteryUsageProvider;
-import com.android.server.am.BaseAppStateTracker.Injector;
import com.android.server.pm.UserManagerInternal;
import java.io.PrintWriter;
@@ -684,7 +681,7 @@
static final int BATTERY_USAGE_INDEX_FOREGROUND = PROCESS_STATE_FOREGROUND;
static final int BATTERY_USAGE_INDEX_BACKGROUND = PROCESS_STATE_BACKGROUND;
static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = PROCESS_STATE_FOREGROUND_SERVICE;
- static final int BATTERY_USAGE_COUNT = PROCESS_STATE_COUNT;
+ static final int BATTERY_USAGE_COUNT = 4;
static final Dimensions[] BATT_DIMENS = new Dimensions[] {
new Dimensions(AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_POWER_COMPONENTS,
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index b73cf5b..42a7423 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -171,16 +171,15 @@
return;
}
- // Remove any existing intent and unregister for this package before adding a new one.
+ // Remove any existing PendingIntent for this package.
String callingPackage = pendingIntent.getCreatorPackage();
PendingIntent duplicatePendingIntent = findExistingRequestByPackage(callingPackage);
if (duplicatePendingIntent != null) {
- Slog.d(TAG, "Unregister duplicate request from " + callingPackage);
- onUnregisterObserver(callingPackage);
+ Slog.d(TAG, "Replace duplicate request from " + callingPackage);
mExistingPendingIntents.remove(duplicatePendingIntent);
}
- // Register new package and add request to mExistingRequests
+ // Register package and add pendingIntent to mExistingPendingIntents
startDetection(request, callingPackage, createDetectionResultRemoteCallback(),
getServerStatusCallback(clientStatusCallback));
mExistingPendingIntents.add(pendingIntent);
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index 010bf1b..e2b22dc 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -110,6 +110,8 @@
return runStopDetection();
case "get-last-status-code":
return getLastStatusCode();
+ case "get-last-package-name":
+ return getLastPackageName();
case "query-service-status":
return runQueryServiceStatus();
case "get-bound-package":
@@ -157,6 +159,13 @@
return lastResponse.getStatusCode();
}
+ private int getLastPackageName() {
+ AmbientContextDetectionServiceStatus lastResponse =
+ sTestableCallbackInternal.getLastStatus();
+ out.println(lastResponse == null ? "" : lastResponse.getPackageName());
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -167,6 +176,7 @@
pw.println(" start-detection USER_ID PACKAGE_NAME: Starts AmbientContextEvent detection.");
pw.println(" stop-detection USER_ID: Stops AmbientContextEvent detection.");
pw.println(" get-last-status-code: Prints the latest request status code.");
+ pw.println(" get-last-package-name: Prints the latest request package name.");
pw.println(" query-event-status USER_ID PACKAGE_NAME: Prints the event status code.");
pw.println(" get-bound-package USER_ID:"
+ " Print the bound package that implements the service.");
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index 193cc5f..5af73c9 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -275,6 +275,7 @@
*/
synchronized void reset(boolean featureEnabled) {
Log.i(TAG, "Resetting");
+ releaseSpat();
mState = STATE_UNINITIALIZED;
mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
@@ -831,10 +832,10 @@
try {
mSpat.registerHeadTrackingCallback(null);
mSpat.release();
- mSpat = null;
} catch (RemoteException e) {
Log.e(TAG, "Can't set release spatializer cleanly", e);
}
+ mSpat = null;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index 7765ab3..9ae6750 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -136,8 +136,8 @@
try {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA,
- getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index efedcf8..ded1810 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -96,7 +96,8 @@
protected void startHalOperation() {
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 8d76e9f..1935a5b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -109,7 +109,8 @@
if (mSensorPrivacyManager != null
&& mSensorPrivacyManager
- .isSensorPrivacyEnabled(SensorPrivacyManager.Sensors.CAMERA, getTargetUserId())) {
+ .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
+ SensorPrivacyManager.Sensors.CAMERA)) {
onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
mCallback.onClientFinished(this, false /* success */);
return;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index fadcce9..954b930 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -20,6 +20,7 @@
import android.Manifest;
import android.accounts.Account;
+import android.accounts.AccountManagerInternal;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -28,7 +29,10 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
import android.app.job.JobInfo;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -106,6 +110,13 @@
*/
private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS;
+ /**
+ * Enables checking for account access for the calling uid on all sync-related APIs.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
+ public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L;
+
public static class Lifecycle extends SystemService {
private ContentService mService;
@@ -157,6 +168,8 @@
private SyncManager mSyncManager = null;
private final Object mSyncManagerLock = new Object();
+ private final AccountManagerInternal mAccountManagerInternal;
+
private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
new BinderDeathDispatcher<>();
@@ -317,6 +330,8 @@
localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
localeFilter, null, null);
+
+ mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
}
void onBootPhase(int phase) {
@@ -593,6 +608,10 @@
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -642,11 +661,14 @@
@Override
public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, request.getAccount(), callingUid)) {
+ return;
+ }
final Bundle extras = request.getBundle();
-
validateExtras(callingUid, extras);
final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
@@ -853,6 +875,9 @@
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -882,8 +907,13 @@
"no permission to write the sync settings");
enforceCrossUserPermission(userId,
"no permission to modify the sync settings for user " + userId);
+
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+
final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
final long identityToken = clearCallingIdentity();
@@ -912,7 +942,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
+ final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
@@ -942,9 +976,11 @@
mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
"no permission to write the sync settings");
- validateExtras(Binder.getCallingUid(), extras);
-
final int callingUid = Binder.getCallingUid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
+ validateExtras(callingUid, extras);
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -969,6 +1005,9 @@
}
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return new ArrayList<>(); // return a new empty list for consistent behavior
+ }
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
@@ -995,6 +1034,9 @@
"no permission to read the sync settings for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1031,6 +1073,9 @@
syncable = normalizeSyncable(syncable);
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
+ if (!hasAccountAccess(true, account, callingUid)) {
+ return;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1103,6 +1148,10 @@
public boolean isSyncActive(Account account, String authority, ComponentName cname) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
int userId = UserHandle.getCallingUserId();
final long identityToken = clearCallingIdentity();
try {
@@ -1165,6 +1214,9 @@
"no permission to read the sync stats for user " + userId);
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return null;
+ }
final long identityToken = clearCallingIdentity();
try {
@@ -1196,6 +1248,10 @@
"no permission to read the sync stats");
enforceCrossUserPermission(userId,
"no permission to retrieve the sync settings for user " + userId);
+ if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
+ return false;
+ }
+
final long identityToken = clearCallingIdentity();
SyncManager syncManager = getSyncManager();
if (syncManager == null) return false;
@@ -1405,6 +1461,32 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
}
+ /**
+ * Checks to see if the given account is accessible by the provided uid.
+ *
+ * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled
+ * @param account the account trying to be accessed
+ * @param uid the uid trying to access the account
+ * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise
+ */
+ private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) {
+ if (account == null) {
+ // If the account is null, it means to check for all accounts hence skip the check here.
+ return true;
+ }
+ if (checkCompatFlag
+ && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) {
+ return true;
+ }
+
+ final long identityToken = clearCallingIdentity();
+ try {
+ return mAccountManagerInternal.hasAccountAccess(account, uid);
+ } finally {
+ restoreCallingIdentity(identityToken);
+ }
+ }
+
private static int normalizeSyncable(int syncable) {
if (syncable > 0) {
return SyncStorageEngine.AuthorityInfo.SYNCABLE;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 22d32a6..50f5536 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -467,7 +467,9 @@
}
mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
- mAtmInternal.notifyDreamStateChanged(false);
+ mHandler.post(() -> {
+ mAtmInternal.notifyDreamStateChanged(false);
+ });
}
private void checkPermission(String permission) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 52834cb..436cc69 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -252,8 +252,6 @@
private final RebootEscrowManager mRebootEscrowManager;
- private boolean mFirstCallToVold;
-
// Current password metric for all users on the device. Updated when user unlocks
// the device or changes password. Removed when user is stopped.
@GuardedBy("this")
@@ -597,8 +595,6 @@
mStrongAuth = injector.getStrongAuth();
mActivityManager = injector.getActivityManager();
- mFirstCallToVold = true;
-
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
@@ -2474,77 +2470,6 @@
});
}
- private LockscreenCredential createPattern(String patternString) {
- final byte[] patternBytes = patternString.getBytes();
- LockscreenCredential pattern = LockscreenCredential.createPattern(
- LockPatternUtils.byteArrayToPattern(patternBytes));
- Arrays.fill(patternBytes, (byte) 0);
- return pattern;
- }
-
- @Override
- public boolean checkVoldPassword(int userId) {
- if (!mFirstCallToVold) {
- return false;
- }
- mFirstCallToVold = false;
-
- checkPasswordReadPermission();
-
- // There's no guarantee that this will safely connect, but if it fails
- // we will simply show the lock screen when we shouldn't, so relatively
- // benign. There is an outside chance something nasty would happen if
- // this service restarted before vold stales out the password in this
- // case. The nastiness is limited to not showing the lock screen when
- // we should, within the first minute of decrypting the phone if this
- // service can't connect to vold, it restarts, and then the new instance
- // does successfully connect.
- final IStorageManager service = mInjector.getStorageManager();
- // TODO(b/120484642): Update vold to return a password as a byte array
- String password;
- final long identity = Binder.clearCallingIdentity();
- try {
- password = service.getPassword();
- service.clearPassword();
- } catch (RemoteException e) {
- Slog.w(TAG, "vold getPassword() failed", e);
- return false;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- if (TextUtils.isEmpty(password)) {
- return false;
- }
-
- try {
- final LockscreenCredential credential;
- switch (getCredentialTypeInternal(userId)) {
- case CREDENTIAL_TYPE_PATTERN:
- credential = createPattern(password);
- break;
- case CREDENTIAL_TYPE_PIN:
- credential = LockscreenCredential.createPin(password);
- break;
- case CREDENTIAL_TYPE_PASSWORD:
- credential = LockscreenCredential.createPassword(password);
- break;
- default:
- credential = null;
- Slog.e(TAG, "Unknown credential type");
- }
-
- if (credential != null
- && checkCredential(credential, userId, null /* progressCallback */)
- .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
- return true;
- }
- } catch (Exception e) {
- Slog.e(TAG, "checkVoldPassword failed: ", e);
- }
-
- return false;
- }
-
private void removeUser(int userId, boolean unknownUser) {
Slog.i(TAG, "RemoveUser: " + userId);
removeBiometricsForUser(userId);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 9f573c2..35f6a94 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4094,7 +4094,7 @@
"updateNetworkStats: " + uid + "/" + (uidForeground ? "F" : "B"));
}
try {
- mNetworkStats.setUidForeground(uid, uidForeground);
+ mNetworkStats.noteUidForeground(uid, uidForeground);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 93f1b47..9e0c975 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,6 +104,7 @@
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+ static final int RULE_LIMIT_PER_PACKAGE = 100;
// pkg|userId => uid
protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();
@@ -329,10 +330,10 @@
int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+ getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+ 1;
- if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
+ if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE
+ || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
-
}
ZenModeConfig newConfig;
diff --git a/services/core/java/com/android/server/pm/AppIdSettingMap.java b/services/core/java/com/android/server/pm/AppIdSettingMap.java
index bbef237..b41a0b8 100644
--- a/services/core/java/com/android/server/pm/AppIdSettingMap.java
+++ b/services/core/java/com/android/server/pm/AppIdSettingMap.java
@@ -17,46 +17,131 @@
package com.android.server.pm;
import android.os.Process;
+import android.util.Log;
+import com.android.server.utils.WatchedArrayList;
import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.Watcher;
/**
- * A wrapper over {@link WatchedSparseArray} that tracks the current maximum App ID.
+ * A wrapper over {@link WatchedArrayList} that tracks the current (app ID -> SettingBase) mapping
+ * for non-system apps. Also tracks system app settings in an {@link WatchedSparseArray}.
*/
-public class AppIdSettingMap extends WatchedSparseArray<SettingBase> {
- private int mCurrentMaxAppId;
+final class AppIdSettingMap {
+ /**
+ * We use an ArrayList instead of an SparseArray for non system apps because the number of apps
+ * might be big, and only ArrayList gives us a constant lookup time. For a given app ID, the
+ * index to the corresponding SettingBase object is (appId - FIRST_APPLICATION_ID). If an app ID
+ * doesn't exist (i.e., app is not installed), we fill the corresponding entry with null.
+ */
+ private WatchedArrayList<SettingBase> mNonSystemSettings = new WatchedArrayList<>();
+ private WatchedSparseArray<SettingBase> mSystemSettings = new WatchedSparseArray<>();
+ private int mFirstAvailableAppId = Process.FIRST_APPLICATION_UID;
- @Override
- public void put(int key, SettingBase value) {
- if (key > mCurrentMaxAppId) {
- mCurrentMaxAppId = key;
+ /** Returns true if the requested AppID was valid and not already registered. */
+ public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ // fill the array until our index becomes valid
+ while (index >= size) {
+ mNonSystemSettings.add(null);
+ size++;
+ }
+ if (mNonSystemSettings.get(index) != null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Adding duplicate app id: " + appId
+ + " name=" + name);
+ return false;
+ }
+ mNonSystemSettings.set(index, setting);
+ } else {
+ if (mSystemSettings.get(appId) != null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Adding duplicate shared id: " + appId
+ + " name=" + name);
+ return false;
+ }
+ mSystemSettings.put(appId, setting);
}
- super.put(key, value);
+ return true;
}
- @Override
+ public SettingBase getSetting(int appId) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ return index < size ? mNonSystemSettings.get(index) : null;
+ } else {
+ return mSystemSettings.get(appId);
+ }
+ }
+
+ public void removeSetting(int appId) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ if (index < size) {
+ mNonSystemSettings.set(index, null);
+ }
+ } else {
+ mSystemSettings.remove(appId);
+ }
+ setFirstAvailableAppId(appId + 1);
+ }
+
+ // This should be called (at least) whenever an application is removed
+ private void setFirstAvailableAppId(int uid) {
+ if (uid > mFirstAvailableAppId) {
+ mFirstAvailableAppId = uid;
+ }
+ }
+
+ public void replaceSetting(int appId, SettingBase setting) {
+ if (appId >= Process.FIRST_APPLICATION_UID) {
+ final int size = mNonSystemSettings.size();
+ final int index = appId - Process.FIRST_APPLICATION_UID;
+ if (index < size) {
+ mNonSystemSettings.set(index, setting);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings: calling replaceAppIdLpw to"
+ + " replace SettingBase at appId=" + appId
+ + " but nothing is replaced.");
+ }
+ } else {
+ mSystemSettings.put(appId, setting);
+ }
+ }
+
+ /** Returns a new AppID or -1 if we could not find an available AppID to assign */
+ public int acquireAndRegisterNewAppId(SettingBase obj) {
+ final int size = mNonSystemSettings.size();
+ for (int i = mFirstAvailableAppId - Process.FIRST_APPLICATION_UID; i < size; i++) {
+ if (mNonSystemSettings.get(i) == null) {
+ mNonSystemSettings.set(i, obj);
+ return Process.FIRST_APPLICATION_UID + i;
+ }
+ }
+
+ // None left?
+ if (size > (Process.LAST_APPLICATION_UID - Process.FIRST_APPLICATION_UID)) {
+ return -1;
+ }
+
+ mNonSystemSettings.add(obj);
+ return Process.FIRST_APPLICATION_UID + size;
+ }
+
public AppIdSettingMap snapshot() {
AppIdSettingMap l = new AppIdSettingMap();
- snapshot(l, this);
+ mNonSystemSettings.snapshot(l.mNonSystemSettings, mNonSystemSettings);
+ mSystemSettings.snapshot(l.mSystemSettings, mSystemSettings);
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;
- }
+ public void registerObserver(Watcher observer) {
+ mNonSystemSettings.registerObserver(observer);
+ mSystemSettings.registerObserver(observer);
}
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index b307984..89f8be2 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -112,7 +112,9 @@
String callingFeatureId,
ComponentName component,
@UserIdInt int userId,
- boolean launchMainActivity) throws RemoteException {
+ boolean launchMainActivity,
+ IBinder targetTask,
+ Bundle options) throws RemoteException {
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(component);
@@ -145,8 +147,12 @@
if (launchMainActivity) {
launchIntent.setAction(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ if (targetTask == null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ } else {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
// Only package name is set here, as opposed to component name, because intent action
// and category are ignored if component name is present while we are resolving intent.
launchIntent.setPackage(component.getPackageName());
@@ -170,15 +176,20 @@
}
verifyActivityCanHandleIntentAndExported(launchIntent, component, callingUid, userId);
+ // Always show the cross profile animation
+ if (options == null) {
+ options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ } else {
+ options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+ }
+
launchIntent.setPackage(null);
launchIntent.setComponent(component);
mInjector.getActivityTaskManagerInternal().startActivityAsUser(
caller, callingPackage, callingFeatureId, launchIntent,
- /* resultTo= */ null,
- Intent.FLAG_ACTIVITY_NEW_TASK,
- launchMainActivity
- ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
- : null,
+ targetTask,
+ /* startFlags= */ 0,
+ options,
userId);
}
@@ -225,6 +236,13 @@
verifyActivityCanHandleIntent(launchIntent, callingUid, userId);
+ // Always show the cross profile animation
+ if (options == null) {
+ options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ } else {
+ options.putAll(ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle());
+ }
+
mInjector.getActivityTaskManagerInternal()
.startActivityAsUser(
caller,
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 76b9830..5902f48 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -27,6 +27,7 @@
import android.os.CreateAppDataResult;
import android.os.IBinder;
import android.os.IInstalld;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.CrateMetadata;
@@ -215,6 +216,21 @@
return result;
}
+ static ReconcileSdkDataArgs buildReconcileSdkDataArgs(String uuid, String packageName,
+ List<String> subDirNames, int userId, int appId,
+ String seInfo, int flags) {
+ final ReconcileSdkDataArgs args = new ReconcileSdkDataArgs();
+ args.uuid = uuid;
+ args.packageName = packageName;
+ args.subDirNames = subDirNames;
+ args.userId = userId;
+ args.appId = appId;
+ args.previousAppId = 0;
+ args.seInfo = seInfo;
+ args.flags = flags;
+ return args;
+ }
+
public @NonNull CreateAppDataResult createAppData(@NonNull CreateAppDataArgs args)
throws InstallerException {
if (!checkBeforeRemote()) {
@@ -247,6 +263,18 @@
}
}
+ void reconcileSdkData(@NonNull ReconcileSdkDataArgs args)
+ throws InstallerException {
+ if (!checkBeforeRemote()) {
+ return;
+ }
+ try {
+ mInstalld.reconcileSdkData(args);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
/**
* Class that collects multiple {@code installd} operations together in an
* attempt to more efficiently execute them in bulk.
diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java
index 7b76567..39cc37e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerLocal.java
+++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java
@@ -16,8 +16,16 @@
package com.android.server.pm;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
/**
* In-process API for server side PackageManager related infrastructure.
*
@@ -28,4 +36,48 @@
*/
@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface PackageManagerLocal {
+
+ /**
+ * Indicates if operation should include device encrypted storage.
+ */
+ int FLAG_STORAGE_DE = Installer.FLAG_STORAGE_DE;
+ /**
+ * Indicates if operation should include credential encrypted storage.
+ */
+ int FLAG_STORAGE_CE = Installer.FLAG_STORAGE_CE;
+
+ /**
+ * Constants for use with {@link #reconcileSdkData} to specify which storage areas should be
+ * included for operation.
+ *
+ * @hide
+ */
+ @IntDef(prefix = "FLAG_STORAGE_", value = {
+ FLAG_STORAGE_DE,
+ FLAG_STORAGE_CE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StorageFlags {}
+
+ /**
+ * Reconcile sdk data sub-directories for the given {@code packagName}.
+ *
+ * Sub directories are created if they do not exist already. If there is an existing per-
+ * sdk directory that is missing from {@code subDirNames}, then it is removed.
+ *
+ * Sdk package path is created if it doesn't exist before creating per-sdk directories.
+ *
+ * @param volumeUuid the volume in which the sdk data should be prepared.
+ * @param packageName package name of the app for which sdk data directory will be prepared.
+ * @param subDirNames names of sub directories that should be reconciled against.
+ * @param userId id of the user to whom the package belongs to.
+ * @param appId id of the package.
+ * @param previousAppId previous id of the package if package is being updated.
+ * @param flags flags from StorageManager to indicate which storage areas should be included.
+ * @param seInfo seInfo tag to be used for selinux policy.
+ * @throws IOException If any error occurs during the operation.
+ */
+ void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, @StorageFlags int flags) throws IOException;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 67056ea..eaecb17 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -132,6 +132,7 @@
import android.os.ParcelableException;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.ReconcileSdkDataArgs;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -6032,6 +6033,22 @@
}
private class PackageManagerLocalImpl implements PackageManagerLocal {
+ @Override
+ public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName,
+ @NonNull List<String> subDirNames, int userId, int appId, int previousAppId,
+ @NonNull String seInfo, int flags) throws IOException {
+ synchronized (mInstallLock) {
+ ReconcileSdkDataArgs args = mInstaller.buildReconcileSdkDataArgs(volumeUuid,
+ packageName, subDirNames, userId, appId, seInfo,
+ flags);
+ args.previousAppId = previousAppId;
+ try {
+ mInstaller.reconcileSdkData(args);
+ } catch (InstallerException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternalBase {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 6ccaae1..698dbe9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -62,7 +62,6 @@
import android.os.Message;
import android.os.PatternMatcher;
import android.os.PersistableBundle;
-import android.os.Process;
import android.os.SELinux;
import android.os.SystemClock;
import android.os.Trace;
@@ -408,8 +407,6 @@
int[] excludedUserIds;
}
- private static int mFirstAvailableUid = Process.FIRST_APPLICATION_UID;
-
/** Map from volume UUID to {@link VersionInfo} */
@Watched
private final WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
@@ -472,10 +469,8 @@
@Watched
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
- @Watched
+ @Watched(manual = true)
private final AppIdSettingMap mAppIds;
- @Watched
- private final AppIdSettingMap mOtherAppIds;
// For reading/writing settings file.
@Watched
@@ -565,7 +560,6 @@
mCrossProfileIntentResolvers.registerObserver(mObserver);
mSharedUsers.registerObserver(mObserver);
mAppIds.registerObserver(mObserver);
- mOtherAppIds.registerObserver(mObserver);
mRenamedPackages.registerObserver(mObserver);
mNextAppLinkGeneration.registerObserver(mObserver);
mDefaultBrowserApp.registerObserver(mObserver);
@@ -592,7 +586,6 @@
mLock = new PackageManagerTracedLock();
mPackages.putAll(pkgSettings);
mAppIds = new AppIdSettingMap();
- mOtherAppIds = new AppIdSettingMap();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -629,7 +622,6 @@
mLock = lock;
mAppIds = new AppIdSettingMap();
- mOtherAppIds = new AppIdSettingMap();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence, new Consumer<Integer>() {
@@ -710,7 +702,6 @@
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot();
- mOtherAppIds = r.mOtherAppIds.snapshot();
WatchedArrayList.snapshot(
mPastSignatures, r.mPastSignatures);
WatchedArrayMap.snapshot(
@@ -782,7 +773,7 @@
SharedUserSetting s = mSharedUsers.get(name);
if (s == null && create) {
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
- s.mAppId = acquireAndRegisterNewAppIdLPw(s);
+ s.mAppId = mAppIds.acquireAndRegisterNewAppId(s);
if (s.mAppId < 0) {
// < 0 means we couldn't assign a userid; throw exception
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
@@ -890,7 +881,7 @@
pkgPrivateFlags, 0 /*userId*/, usesSdkLibraries, usesSdkLibrariesVersions,
usesStaticLibraries, usesStaticLibrariesVersions, mimeGroups, domainSetId);
p.setAppId(uid);
- if (registerExistingAppIdLPw(uid, p, name)) {
+ if (mAppIds.registerExistingAppId(uid, p, name)) {
mPackages.put(name, p);
return p;
}
@@ -909,7 +900,7 @@
}
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.mAppId = uid;
- if (registerExistingAppIdLPw(uid, s, name)) {
+ if (mAppIds.registerExistingAppId(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
@@ -1210,11 +1201,11 @@
final boolean createdNew;
if (p.getAppId() == 0 || forceNew) {
// Assign new user ID
- p.setAppId(acquireAndRegisterNewAppIdLPw(p));
+ p.setAppId(mAppIds.acquireAndRegisterNewAppId(p));
createdNew = true;
} else {
// Add new setting to list of user IDs
- createdNew = registerExistingAppIdLPw(p.getAppId(), p, p.getPackageName());
+ createdNew = mAppIds.registerExistingAppId(p.getAppId(), p, p.getPackageName());
}
if (p.getAppId() < 0) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -1304,11 +1295,11 @@
Object userIdPs = getSettingLPr(p.getAppId());
if (sharedUser == null) {
if (userIdPs != null && userIdPs != p) {
- replaceAppIdLPw(p.getAppId(), p);
+ mAppIds.replaceSetting(p.getAppId(), p);
}
} else {
if (userIdPs != null && userIdPs != sharedUser) {
- replaceAppIdLPw(p.getAppId(), sharedUser);
+ mAppIds.replaceSetting(p.getAppId(), sharedUser);
}
}
}
@@ -1357,73 +1348,22 @@
mInstallerPackages.remove(packageName);
}
- /** Returns true if the requested AppID was valid and not already registered. */
- private boolean registerExistingAppIdLPw(int appId, SettingBase obj, Object name) {
- if (appId > Process.LAST_APPLICATION_UID) {
- return false;
- }
-
- if (appId >= Process.FIRST_APPLICATION_UID) {
- if (mAppIds.get(appId) != null) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Adding duplicate app id: " + appId
- + " name=" + name);
- return false;
- }
- mAppIds.put(appId, obj);
- } else {
- if (mOtherAppIds.get(appId) != null) {
- PackageManagerService.reportSettingsProblem(Log.WARN,
- "Adding duplicate shared id: " + appId
- + " name=" + name);
- return false;
- }
- mOtherAppIds.put(appId, obj);
- }
- return true;
- }
-
/** Gets the setting associated with the provided App ID */
public SettingBase getSettingLPr(int appId) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- return mAppIds.get(appId);
- } else {
- return mOtherAppIds.get(appId);
- }
+ return mAppIds.getSetting(appId);
}
/** Unregisters the provided app ID. */
void removeAppIdLPw(int appId) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- mAppIds.remove(appId);
- } else {
- mOtherAppIds.remove(appId);
- }
- setFirstAvailableUid(appId + 1);
+ mAppIds.removeSetting(appId);
}
-
- private void replaceAppIdLPw(int appId, SettingBase obj) {
- if (appId >= Process.FIRST_APPLICATION_UID) {
- 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);
- }
- }
-
/**
* Transparently convert a SharedUserSetting into PackageSettings without changing appId.
* The sharedUser passed to this method has to be {@link SharedUserSetting#isSingleUser()}.
*/
void convertSharedUserSettingsLPw(SharedUserSetting sharedUser) {
final PackageSetting ps = sharedUser.getPackageSettings().valueAt(0);
- replaceAppIdLPw(sharedUser.getAppId(), ps);
+ mAppIds.replaceSetting(sharedUser.getAppId(), ps);
// Unlink the SharedUserSetting
ps.setSharedUserAppId(INVALID_UID);
@@ -4287,32 +4227,6 @@
}
}
- // This should be called (at least) whenever an application is removed
- private void setFirstAvailableUid(int uid) {
- if (uid > mFirstAvailableUid) {
- mFirstAvailableUid = uid;
- }
- }
-
- /** Returns a new AppID or -1 if we could not find an available AppID to assign */
- private int acquireAndRegisterNewAppIdLPw(SettingBase obj) {
- 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 (nextAvailableAppId > Process.LAST_APPLICATION_UID) {
- return -1;
- }
-
- mAppIds.put(nextAvailableAppId, obj);
- return nextAvailableAppId;
- }
-
public VerifierDeviceIdentity getVerifierDeviceIdentityLPw(@NonNull Computer computer) {
if (mVerifierDeviceIdentity == null) {
mVerifierDeviceIdentity = VerifierDeviceIdentity.generate();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1cf2dc5..25fe000 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -488,7 +488,8 @@
mShortcutBitmapSaver = new ShortcutBitmapSaver(this);
mShortcutDumpFiles = new ShortcutDumpFiles(this);
mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true);
+ SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, true)
+ && !injectIsLowRamDevice();
if (onlyForPackageManagerApis) {
return; // Don't do anything further. For unit tests only.
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 88a298a..9c74dd7 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -52,9 +52,6 @@
"options": [
{
"include-filter": "com.google.android.security.gts.PackageVerifierTest"
- },
- {
- "exclude-filter": "com.google.android.security.gts.PackageVerifierTest#testAdbInstall_timeout_allowed"
}
]
},
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index eae7658..34b7ad4 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4638,12 +4638,12 @@
final String restriction = getUserRemovalRestriction(userId);
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION;
}
}
if (userId == UserHandle.USER_SYSTEM) {
Slog.e(LOG_TAG, "System user cannot be removed.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER;
}
final long ident = Binder.clearCallingIdentity();
@@ -4655,7 +4655,7 @@
if (userData == null) {
Slog.e(LOG_TAG,
"Cannot remove user " + userId + ", invalid user id provided.");
- return UserManager.REMOVE_RESULT_ERROR;
+ return UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND;
}
if (mRemovingUserIds.get(userId)) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e79148d..dc5b325 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -792,7 +792,7 @@
public void onWakeUp() {
synchronized (mLock) {
if (shouldEnableWakeGestureLp()
- && mBatteryManagerInternal.getPlugType() != BATTERY_PLUGGED_WIRELESS) {
+ && getBatteryManagerInternal().getPlugType() != BATTERY_PLUGGED_WIRELESS) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
index 990b21c..1cc0539 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHalConcurrentCaptureHandler.java
@@ -20,6 +20,7 @@
import android.media.permission.SafeCloseable;
import android.media.soundtrigger.ModelParameterRange;
import android.media.soundtrigger.PhraseRecognitionEvent;
+import android.media.soundtrigger.PhraseRecognitionExtra;
import android.media.soundtrigger.PhraseSoundModel;
import android.media.soundtrigger.Properties;
import android.media.soundtrigger.RecognitionConfig;
@@ -392,7 +393,7 @@
private static void notifyAbort(int modelHandle, LoadedModel model) {
switch (model.type) {
case SoundModelType.GENERIC: {
- RecognitionEvent event = new RecognitionEvent();
+ RecognitionEvent event = newEmptyRecognitionEvent();
event.status = RecognitionStatus.ABORTED;
event.type = SoundModelType.GENERIC;
model.callback.recognitionCallback(modelHandle, event);
@@ -400,7 +401,7 @@
break;
case SoundModelType.KEYPHRASE: {
- PhraseRecognitionEvent event = new PhraseRecognitionEvent();
+ PhraseRecognitionEvent event = newEmptyPhraseRecognitionEvent();
event.common.status = RecognitionStatus.ABORTED;
event.common.type = SoundModelType.KEYPHRASE;
model.callback.phraseRecognitionCallback(modelHandle, event);
@@ -415,6 +416,19 @@
mNotifier.unregisterListener(this);
}
+ private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+ PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+ result.common = newEmptyRecognitionEvent();
+ result.phraseExtras = new PhraseRecognitionExtra[0];
+ return result;
+ }
+
+ private static RecognitionEvent newEmptyRecognitionEvent() {
+ RecognitionEvent result = new RecognitionEvent();
+ result.data = new byte[0];
+ return result;
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////
// All methods below do trivial delegation - no interesting logic.
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 543e44c..ffc4388 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -746,8 +746,9 @@
// if it is not already expanding to fullscreen. Otherwise, the arguments will
// be used the next time the activity enters PiP.
final Task rootTask = r.getRootTask();
- rootTask.setPictureInPictureAspectRatio(r.pictureInPictureArgs.getAspectRatio(),
- r.pictureInPictureArgs.getExpandedAspectRatio());
+ rootTask.setPictureInPictureAspectRatio(
+ r.pictureInPictureArgs.getAspectRatioFloat(),
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat());
rootTask.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
}
@@ -828,7 +829,7 @@
if (params.hasSetAspectRatio()
&& !mService.mWindowManager.isValidPictureInPictureAspectRatio(
- r.mDisplayContent, params.getAspectRatio())) {
+ r.mDisplayContent, params.getAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Aspect ratio is too extreme (must be between %f and %f).",
minAspectRatio, maxAspectRatio));
@@ -836,7 +837,7 @@
if (mService.mSupportsExpandedPictureInPicture && params.hasSetExpandedAspectRatio()
&& !mService.mWindowManager.isValidExpandedPictureInPictureAspectRatio(
- r.mDisplayContent, params.getExpandedAspectRatio())) {
+ r.mDisplayContent, params.getExpandedAspectRatioFloat())) {
throw new IllegalArgumentException(String.format(caller
+ ": Expanded aspect ratio is not extreme enough (must not be between"
+ " %f and %f).",
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a8dd856..c0cdec9 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -657,7 +657,7 @@
for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
final TransitionInfo prevInfo = mTransitionInfoList.get(i);
if (prevInfo.mIsDrawn || !prevInfo.mLastLaunchedActivity.mVisibleRequested) {
- abort(prevInfo, "nothing will be drawn");
+ scheduleCheckActivityToBeDrawn(prevInfo.mLastLaunchedActivity, 0 /* delay */);
}
}
}
@@ -757,6 +757,10 @@
/** Makes sure that the reference to the removed activity is cleared. */
void notifyActivityRemoved(@NonNull ActivityRecord r) {
mLastTransitionInfo.remove(r);
+ final TransitionInfo info = getActiveTransitionInfo(r);
+ if (info != null) {
+ abort(info, "removed");
+ }
final int packageUid = r.info.applicationInfo.uid;
final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b5312c4..988a7c6 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3523,8 +3523,9 @@
}
// Only update the saved args from the args that are set
r.setPictureInPictureParams(params);
- final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
- final float expandedAspectRatio = r.pictureInPictureArgs.getExpandedAspectRatio();
+ final float aspectRatio = r.pictureInPictureArgs.getAspectRatioFloat();
+ final float expandedAspectRatio =
+ r.pictureInPictureArgs.getExpandedAspectRatioFloat();
final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
mRootWindowContainer.moveActivityToPinnedRootTask(r,
null /* launchIntoPipHostActivity */, "enterPictureInPictureMode");
diff --git a/services/core/java/com/android/server/wm/BLASTSync.md b/services/core/java/com/android/server/wm/BLASTSync.md
new file mode 100644
index 0000000..2f39d6d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BLASTSync.md
@@ -0,0 +1,108 @@
+= What does it mean for BLAST Sync to work? =
+There are two BLAST sync primitives on the server side, BLASTSyncEngine and applyWithNextDraw.
+Both of them are used to solve subclasses of this category of problem:
+ 1. You have some server side changes, which will trigger both WM/SysUI initiated SurfaceControl.Transactions,
+ and also trigger a client redraw/update
+ 2. You want to synchronize the redraw of those clients with the application of those WM/SysUI side changes.
+
+Put simply, you would like to synchronize the graphical effects of some WM changes with the graphical output of various windows
+observing those changes.
+
+To talk about exactly what the primitives guarantee, we need to clarify what we mean by server side changes.
+In this document we will use a term syncable state to refer to any state mutated under the WindowManager lock
+which when observed by the client, produces a visible outcome in the produced frame.
+For example the current Configuration.
+
+The guarantee provided by Server-side BLAST Sync Primitives is thus:
+Guarantee 1: If you make a set of changes to syncable state, at the same time that you begin a sync,
+then the first frame drawn by the client after observing the syncable state will be sent in a transaction
+to the consumer of the sync which was begun, rather than directly sent to SurfaceFlinger.
+
+Here "at the same time" means in the same critical section (while holding the WM lock)
+For example this guarantee means that you can write code like:
+ window.performConfigurationChange(someConfiguration)
+ window.applyOnNextDraw(consumer)
+And the consumer will always be passed the first frame containing the configuration change. This can work with any
+syncable state not just Configuration.
+
+The following is the protocol and additional requirements for BLAST sync, and an analysis of why it is correct. Due to time
+constraints we analyze it for a single window only (as this is actually the hard part).
+
+Protocol requirements:
+ Server protocol, precondition, begin a syncSeqId integer per window at 0:
+ SA: Enter the critical section
+ SB: Change syncable state, any number of times, prepare any number of syncs (and
+ increment the seqId if a sync was prepared, assosciate it with the sync)
+ SC: Leave the critical section
+ SD: Send syncable state updates to the client, always paired with the current seqId
+ SE: When the client calls finishDrawing, execute the consumer for each sync with
+ seqId <= the seqId which the client passed to finishDrawing
+ Client protocol:
+ CA: Observe state and seqid changes up until a fixed frame deadline, then execute performTraversals
+ CB: If the seqId is incremeneted at the time of the frame deadline, configure the renderer to
+ redirect the next draw in to a transaction, record the seqId at the time
+ CC: When the draw is finished, send the transaction containing the draw to WM with the
+ previously recorded seqId
+ Additional requirements/assumptions:
+ 1. The server may only send changes to the syncable state paired with the seqId. The client may
+ only receive them together (e.g. not from other sources)
+ 2. In between changing and sending syncable state, the lock must be released and acquired again
+ 3. The client wont draw a frame reflecting syncable state changes without passing through "performTraversals"
+ 4. Drawing never fails
+ 5. There are no blocking calls between the client or the server
+
+Note that the server can begin the protocol at any time, so it may be possible for the client to proceed through
+phases SA, SB, SC, and SD multiple times before the client receives any messages.
+
+To show that the guarantee can't be violated, we use a notation of sequences, where we describe interleaving
+of protocol events. For duplicate events, we attach a number, e.g. SA_1, SA_2.
+
+We proceed by contradiction, imagine there was some sequence (..., SA_N, ...) for which the guarantee was
+not upheld. This means that either
+ 1. finishDrawing with the assosciate seqId was never sent to the server OR
+ 2. It was sent too late (after the first frame was sent to SF instead of WM) OR
+ 3. It was sent too early (not containing the state changes originating with SA_N)
+If it was sent neither too late, nor too early, and contained the assosciated seqId, then protocol step SE
+says that the frame will be passed to the consumer and we uphold our guarantee.
+
+The first case is impossible because step SD says that the server always sends the seqId if a sync was prepared.
+If we send it the client must receive it. Since we only increment the seqId, and the client only takes the
+seqId from us (requirement 1, protocol step SB), the received ID must be higher than the clients previous seqId.
+CA says that performTraversals will execute, and CB says that when it does, if the seqId is higher than before
+it will schedule the render to sync. Requirement 4 says drawing never fails, so CC must execute, and so we will always
+eventually send every seqId (or a seqId > than it) back to the server.
+
+It also can't be sent too late. By requirement 2 we must release and acquire the lock
+after after changing and before emitting syncable state changes. This means it's guaranteed
+that even in an ordering like AcquireLock, ChangeState, PrepareSync, Release lock we can't
+send the state changes before prepareSync, and so they can always include at least the seqId
+assosciated with changestate (or a later one).
+Since we only receive the SeqId with the State changes (requirement 1),
+and we wont draw state changes without passing through perform traversals (requirement 3) the first frame
+containing the state change must have been generated by a call to performTraversals which also observed
+the seqId change, and so it will appropriately configure the renderer.
+
+By the same argument it can't be sent too early! Since we only send seqIds we receive from the server,
+and we only send seqIds after completing a drawing pass of the assosciated state.
+
+So we can see that no matter at what time the server makes syncable state changes, the first frame will
+always be delivered to the draw handler. Assuming that the client and server uphold this protocol and these
+requirements.
+
+The trickiest part of the implementation at the moment is due to assosciating seqId. Currently we send one of the most
+most important pieces of syncable state (configuration) over multiple channels. Namely ClientTransaction
+and MSG_RESIZED. The ordering of these relative to sync preparation in server code is undefined, in fact we have cases like
+this all the time:
+ acquireLock()
+ changeConfiguration()
+ // time passes, but still in critical section
+ prepareSync()
+ releaseLock()
+This is exactly the kind of case Guarantee 1 mentions as an example. In previous incarnations of the code this worked
+because relayoutWindow needed to acquire the same lock and relayoutWindow was a necessary part of completing sync.
+
+Now that we have no barrier, that could create issues, because at the time we change configuration (and send the change
+to the client via ClientTransaction), we haven't even incremented the seqId yet, and so how can the client observe it
+at the same time as the state? We solve this by pushing all client communication through a handler thread that has to
+acquire the lock. This ensures we uphold requirement 2.
+
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 23f14a7..dbc0141 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -25,6 +25,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.Bundle;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -44,7 +45,11 @@
class BackNavigationController {
private static final String TAG = "BackNavigationController";
- private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
+ // By default, enable new back dispatching without any animations.
+ private static final int BACK_PREDICTABILITY_PROP =
+ SystemProperties.getInt("persist.debug.back_predictability", 1);
+ private static final int ANIMATIONS_MASK = 1 << 1;
+ private static final int SCREENSHOT_MASK = 1 << 2;
@Nullable
private TaskSnapshotController mTaskSnapshotController;
@@ -53,11 +58,15 @@
* Returns true if the back predictability feature is enabled
*/
static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ return BACK_PREDICTABILITY_PROP > 0;
}
static boolean isScreenshotEnabled() {
- return false;
+ return (BACK_PREDICTABILITY_PROP & SCREENSHOT_MASK) != 0;
+ }
+
+ private static boolean isAnimationEnabled() {
+ return (BACK_PREDICTABILITY_PROP & ANIMATIONS_MASK) != 0;
}
/**
@@ -93,14 +102,17 @@
ActivityRecord prev;
WindowContainer<?> removedWindowContainer;
ActivityRecord activityRecord;
+ ActivityRecord prevTaskTopActivity = null;
SurfaceControl animationLeashParent;
WindowConfiguration taskWindowConfiguration;
HardwareBuffer screenshotBuffer = null;
+ SurfaceControl screenshotSurface;
int prevTaskId;
int prevUserId;
RemoteAnimationTarget topAppTarget;
SurfaceControl animLeash;
- IOnBackInvokedCallback callback = null;
+ IOnBackInvokedCallback applicationCallback = null;
+ IOnBackInvokedCallback systemCallback = null;
synchronized (task.mWmService.mGlobalLock) {
@@ -116,15 +128,14 @@
removedWindowContainer = activityRecord;
taskWindowConfiguration = window.getWindowConfiguration();
}
- IOnBackInvokedCallback applicationCallback = null;
- IOnBackInvokedCallback systemCallback = null;
if (window != null) {
applicationCallback = window.getApplicationOnBackInvokedCallback();
- callback = applicationCallback;
- if (callback == null) {
- systemCallback = window.getSystemOnBackInvokedCallback();
- callback = systemCallback;
- }
+ systemCallback = window.getSystemOnBackInvokedCallback();
+ }
+ if (applicationCallback == null && systemCallback == null) {
+ // Return null when either there's no window, or apps have just initialized and
+ // have not finished registering callbacks.
+ return null;
}
ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
@@ -133,24 +144,24 @@
task, activityRecord, applicationCallback, systemCallback);
// TODO Temp workaround for Sysui until b/221071505 is fixed
- if (activityRecord == null && callback != null) {
+ if (activityRecord == null && applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
}
// For IME and Home, either a callback is registered, or we do nothing. In both cases,
// we don't need to pass the leashes below.
if (activityRecord == null || task.getDisplayContent().getImeContainer().isVisible()
|| activityRecord.isActivityTypeHome()) {
- if (callback != null) {
+ if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
} else {
return null;
}
@@ -159,12 +170,12 @@
prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
- if (callback != null) {
+ if (applicationCallback != null) {
return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
null /* topWindowLeash */, null /* screenshotSurface */,
null /* screenshotBuffer */, null /* taskWindowConfiguration */,
null /* onBackNavigationDone */,
- callback /* onBackInvokedCallback */);
+ applicationCallback /* onBackInvokedCallback */);
} else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) {
@@ -188,8 +199,8 @@
prevTaskId = prevTask != null ? prevTask.mTaskId : 0;
prevUserId = prevTask != null ? prevTask.mUserId : 0;
- ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s",
- prev != null ? prev.mActivityComponent : null);
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Previous Activity is %s. "
+ + "Back type is %s", prev != null ? prev.mActivityComponent : null, backType);
//TODO(207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented. For now we simply have the mBackScreenshots hash map that dumbly
@@ -204,6 +215,7 @@
return null;
}
// Prepare a leash to animate the current top window
+ // TODO(b/220934562): Use surface animator to better manage animation conflicts.
animLeash = removedWindowContainer.makeAnimationLeash()
.setName("BackPreview Leash for " + removedWindowContainer)
.setHidden(false)
@@ -231,12 +243,30 @@
activityRecord.windowType);
}
- SurfaceControl.Builder builder = new SurfaceControl.Builder()
+ screenshotSurface = new SurfaceControl.Builder()
.setName("BackPreview Screenshot for " + prev)
.setParent(animationLeashParent)
.setHidden(false)
- .setBLASTLayer();
- SurfaceControl screenshotSurface = builder.build();
+ .setBLASTLayer()
+ .build();
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+ task.mBackGestureStarted = true;
+ // Make launcher show from behind by marking its top activity as visible and
+ // launch-behind to bump its visibility for the duration of the back gesture.
+ prevTaskTopActivity = prevTask.getTopNonFinishingActivity();
+ if (prevTaskTopActivity != null) {
+ if (!prevTaskTopActivity.mVisibleRequested) {
+ prevTaskTopActivity.setVisibility(true);
+ }
+ prevTaskTopActivity.mLaunchTaskBehind = true;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+ "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+ prevTaskTopActivity);
+ prevTaskTopActivity.mRootWindowContainer.ensureActivitiesVisible(
+ null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */);
+ }
+ }
// Find a screenshot of the previous activity
@@ -253,17 +283,20 @@
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
try {
- activityRecord.token.linkToDeath(
- () -> resetSurfaces(finalRemovedWindowContainer), 0);
+ activityRecord.token.linkToDeath(() -> resetSurfaces(finalRemovedWindowContainer), 0);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death", e);
resetSurfaces(removedWindowContainer);
return null;
}
- RemoteCallback onBackNavigationDone = new RemoteCallback(
- result -> resetSurfaces(finalRemovedWindowContainer
- ));
+ int finalBackType = backType;
+ final IOnBackInvokedCallback callback =
+ applicationCallback != null ? applicationCallback : systemCallback;
+ ActivityRecord finalPrevTaskTopActivity = prevTaskTopActivity;
+ RemoteCallback onBackNavigationDone = new RemoteCallback(result -> onBackNavigationDone(
+ result, finalRemovedWindowContainer, finalBackType, task,
+ finalPrevTaskTopActivity));
return new BackNavigationInfo(backType,
topAppTarget,
screenshotSurface,
@@ -273,6 +306,39 @@
callback);
}
+ private void onBackNavigationDone(
+ Bundle result, WindowContainer windowContainer, int backType,
+ Task task, ActivityRecord prevTaskTopActivity) {
+ SurfaceControl surfaceControl = windowContainer.getSurfaceControl();
+ boolean triggerBack = result != null
+ ? result.getBoolean(BackNavigationInfo.KEY_TRIGGER_BACK)
+ : false;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "onBackNavigationDone backType=%s, "
+ + "task=%s, prevTaskTopActivity=%s", backType, task, prevTaskTopActivity);
+
+ if (backType == BackNavigationInfo.TYPE_RETURN_TO_HOME && isAnimationEnabled()) {
+ if (triggerBack) {
+ if (surfaceControl != null && surfaceControl.isValid()) {
+ // When going back to home, hide the task surface before it is re-parented to
+ // avoid flicker.
+ SurfaceControl.Transaction t = windowContainer.getSyncTransaction();
+ t.hide(surfaceControl);
+ t.apply();
+ }
+ }
+ if (prevTaskTopActivity != null && !triggerBack) {
+ // Restore the launch-behind state.
+ task.mTaskSupervisor.scheduleLaunchTaskBehindComplete(prevTaskTopActivity.token);
+ prevTaskTopActivity.mLaunchTaskBehind = false;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+ "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+ prevTaskTopActivity);
+ }
+ } else {
+ task.mBackGestureStarted = false;
+ }
+ resetSurfaces(windowContainer);
+ }
private HardwareBuffer getActivitySnapshot(@NonNull Task task,
ComponentName activityComponent) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 59ba4e7..73673202 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -145,7 +145,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE;
import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
-import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_ASSIGN_LAYERS;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
@@ -4504,56 +4503,38 @@
mTmpUpdateAllDrawn.clear();
- int repeats = 0;
- do {
- repeats++;
- if (repeats > 6) {
- Slog.w(TAG, "Animation repeat aborted after too many iterations");
- clearLayoutNeeded();
- break;
- }
+ if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
+ pendingLayoutChanges);
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
- pendingLayoutChanges);
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ mWallpaperController.adjustWallpaperWindows();
+ }
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
- mWallpaperController.adjustWallpaperWindows();
- }
-
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
- if (updateOrientation()) {
- setLayoutNeeded();
- sendNewConfiguration();
- }
- }
-
- if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+ if (updateOrientation()) {
setLayoutNeeded();
+ sendNewConfiguration();
}
+ }
- // FIRST LOOP: Perform a layout, if needed.
- if (repeats < LAYOUT_REPEAT_THRESHOLD) {
- performLayout(repeats == 1, false /* updateInputWindows */);
- } else {
- Slog.w(TAG, "Layout repeat skipped after too many iterations");
- }
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+ setLayoutNeeded();
+ }
- // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
- pendingLayoutChanges = 0;
+ // Perform a layout, if needed.
+ performLayout(true /* initial */, false /* updateInputWindows */);
+ pendingLayoutChanges = 0;
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
- try {
- mDisplayPolicy.beginPostLayoutPolicyLw();
- forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
- pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
- "after finishPostLayoutPolicyLw", pendingLayoutChanges);
- mInsetsStateController.onPostLayout();
- } while (pendingLayoutChanges != 0);
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
+ try {
+ mDisplayPolicy.beginPostLayoutPolicyLw();
+ forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+ mDisplayPolicy.finishPostLayoutPolicyLw();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+ mInsetsStateController.onPostLayout();
mTmpApplySurfaceChangesTransactionState.reset();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4148d8b..bb5dacc 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -42,11 +42,9 @@
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -79,7 +77,6 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
@@ -136,6 +133,7 @@
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants;
import android.view.accessibility.AccessibilityManager;
+import android.window.ClientWindowFrames;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -340,15 +338,12 @@
private static final Rect sTmpRect2 = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
private static final Rect sTmpDisplayCutoutSafe = new Rect();
- private static final Rect sTmpDisplayFrame = new Rect();
- private static final Rect sTmpParentFrame = new Rect();
- private static final Rect sTmpFrame = new Rect();
+ private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
private final WindowLayout mWindowLayout = new WindowLayout();
private WindowState mTopFullscreenOpaqueWindowState;
private boolean mTopIsFullscreen;
- private boolean mForceStatusBar;
private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
private boolean mForceShowSystemBars;
@@ -940,6 +935,26 @@
break;
}
+ if (LayoutParams.isSystemAlertWindowType(attrs.type)) {
+ float maxOpacity = mService.mMaximumObscuringOpacityForTouch;
+ if (attrs.alpha > maxOpacity
+ && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0
+ && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+ // The app is posting a SAW with the intent of letting touches pass through, but
+ // they are going to be deemed untrusted and will be blocked. Try to honor the
+ // intent of letting touches pass through at the cost of 0.2 opacity for app
+ // compatibility reasons. More details on b/218777508.
+ Slog.w(TAG, String.format(
+ "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and "
+ + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to "
+ + "let touches pass through (if this is isn't desirable, remove "
+ + "flag FLAG_NOT_TOUCHABLE).",
+ attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity));
+ attrs.alpha = maxOpacity;
+ win.mWinAnimator.mAlpha = maxOpacity;
+ }
+ }
+
// Check if alternate bars positions were updated.
if (mStatusBarAlt == win) {
mStatusBarAltPosition = getAltBarPosition(attrs);
@@ -1474,8 +1489,8 @@
displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
UNSPECIFIED_LENGTH, win.getRequestedVisibilities(),
null /* attachedWindowFrame */, win.mGlobalScale,
- sTmpDisplayFrame, sTmpParentFrame, sTmpFrame);
- controller.computeSimulatedState(win, displayFrames, sTmpFrame);
+ sTmpClientFrames);
+ controller.computeSimulatedState(win, displayFrames, sTmpClientFrames.frame);
}
}
@@ -1518,12 +1533,12 @@
sTmpLastParentFrame.set(pf);
- final boolean clippedByDisplayCutout = mWindowLayout.computeFrames(attrs,
- win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
+ mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
win.getRequestedVisibilities(), attachedWindowFrame, win.mGlobalScale,
- df, pf, f);
- windowFrames.setParentFrameWasClippedByDisplayCutout(clippedByDisplayCutout);
+ sTmpClientFrames);
+ windowFrames.setParentFrameWasClippedByDisplayCutout(
+ sTmpClientFrames.isParentFrameClippedByDisplayCutout);
if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+ ": sim=#" + Integer.toHexString(attrs.softInputMode)
@@ -1536,7 +1551,7 @@
windowFrames.setContentChanged(true);
}
- win.setFrame();
+ win.setFrames(sTmpClientFrames);
}
WindowState getTopFullscreenOpaqueWindow() {
@@ -1558,7 +1573,6 @@
mStatusBarBackgroundWindows.clear();
mStatusBarColorCheckedBounds.setEmpty();
mStatusBarBackgroundCheckedBounds.setEmpty();
- mForceStatusBar = false;
mAllowLockscreenWhenOn = false;
mShowingDream = false;
@@ -1599,9 +1613,6 @@
&& attrs.type < FIRST_SYSTEM_WINDOW;
if (mTopFullscreenOpaqueWindowState == null) {
final int fl = attrs.flags;
- if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
- }
if (win.isDreamWindow()) {
// If the lockscreen was showing when the dream started then wait
// for the dream to draw before hiding the lockscreen.
@@ -1710,21 +1721,9 @@
}
/**
- * Called following layout of all windows and after policy has been applied
- * to each window. If in this function you do
- * something that may have modified the animation state of another window,
- * be sure to return non-zero in order to perform another pass through layout.
- *
- * @return Return any bit set of
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
- * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
+ * Called following layout of all windows and after policy has been applied to each window.
*/
- public int finishPostLayoutPolicyLw() {
- int changes = 0;
- boolean topIsFullscreen = false;
-
+ public void finishPostLayoutPolicyLw() {
// If we are not currently showing a dream then remember the current
// lockscreen state. We will use this to determine whether the dream
// started while the lockscreen was showing and remember this state
@@ -1733,41 +1732,6 @@
mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
}
- if (getStatusBar() != null) {
- if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
- + " top=" + mTopFullscreenOpaqueWindowState);
- final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
- & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
-
- boolean topAppHidesStatusBar = topAppHidesStatusBar();
- if (mForceStatusBar || forceShowStatusBar) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
- // Maintain fullscreen layout until incoming animation is complete.
- topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
- } else if (mTopFullscreenOpaqueWindowState != null) {
- topIsFullscreen = topAppHidesStatusBar;
- // The subtle difference between the window for mTopFullscreenOpaqueWindowState
- // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
- // requests to hide the status bar. Not sure if there is another way that to be the
- // case though.
- if (!topIsFullscreen) {
- topAppHidesStatusBar = false;
- }
- }
- StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
- if (statusBar != null) {
- statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
- }
- }
-
- if (mTopIsFullscreen != topIsFullscreen) {
- if (!topIsFullscreen) {
- // Force another layout when status bar becomes fully shown.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- mTopIsFullscreen = topIsFullscreen;
- }
-
updateSystemBarAttributes();
if (mShowingDream != mLastShowingDream) {
@@ -1777,7 +1741,6 @@
}
mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
- return changes;
}
/**
@@ -2441,6 +2404,18 @@
mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
+ final boolean topAppHidesStatusBar = topAppHidesStatusBar();
+ if (getStatusBar() != null) {
+ final StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
+ }
+ }
+
+ // If the top app is not fullscreen, only the default rotation animation is allowed.
+ mTopIsFullscreen = topAppHidesStatusBar
+ && (mNotificationShade == null || !mNotificationShade.isVisible());
+
int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
appearance = configureStatusBarOpacity(appearance);
appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
@@ -2781,7 +2756,6 @@
}
}
pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
- pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
pw.print(prefix); pw.print("mForceShowNavigationBarEnabled=");
pw.print(mForceShowNavigationBarEnabled);
pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0c609191..9ad25ac8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -232,14 +232,14 @@
int requestedWidth, int requestedHeight, int viewFlags, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncSeqIdBundle) {
if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
+ Binder.getCallingPid());
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
int res = mService.relayoutWindow(this, window, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
- outActiveControls);
+ outActiveControls, outSyncSeqIdBundle);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
+ Binder.getCallingPid());
@@ -265,9 +265,9 @@
@Override
public void finishDrawing(IWindow window,
- @Nullable SurfaceControl.Transaction postDrawTransaction) {
+ @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (DEBUG) Slog.v(TAG_WM, "IWindow finishDrawing called for " + window);
- mService.finishDrawingWindow(this, window, postDrawTransaction);
+ mService.finishDrawingWindow(this, window, postDrawTransaction, seqId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cd7ebe3..f71bd72 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -72,6 +72,7 @@
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LOCKTASK;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
@@ -609,6 +610,12 @@
boolean mLastSurfaceShowing = true;
+ /**
+ * Tracks if a back gesture is in progress.
+ * Skips any system transition animations if this is set to {@code true}.
+ */
+ boolean mBackGestureStarted = false;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -1623,12 +1630,16 @@
}
ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
+ // The task should be preserved for putting new activity in case the last activity is
+ // finished if it is normal launch mode and not single top ("clear-task-top").
+ mReuseTask = true;
mTaskSupervisor.beginDeferResume();
final ActivityRecord result;
try {
result = clearTopActivities(newR, launchFlags);
} finally {
mTaskSupervisor.endDeferResume();
+ mReuseTask = false;
}
return result;
}
@@ -3322,6 +3333,14 @@
}
});
}
+ } else if (mBackGestureStarted) {
+ // Cancel playing transitions if a back navigation animation is in progress.
+ // This bit is set by {@link BackNavigationController} when a back gesture is started.
+ // It is used as a one-off transition overwrite that is cleared when the back gesture
+ // is committed and triggers a transition, or when the gesture is cancelled.
+ mBackGestureStarted = false;
+ mDisplayContent.mSkipAppTransitionAnimation = true;
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Skipping app transition animation. task=%s", this);
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, sources);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 597d29f..d187bd6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -63,8 +63,6 @@
import static com.android.server.wm.TaskFragmentProto.MIN_HEIGHT;
import static com.android.server.wm.TaskFragmentProto.MIN_WIDTH;
import static com.android.server.wm.TaskFragmentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.TASK_FRAGMENT;
import android.annotation.IntDef;
@@ -2370,8 +2368,7 @@
if (!hasChild()) {
return false;
}
- return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES)
- || inTransition();
+ return isExitAnimationRunningSelfOrChild() || inTransition();
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index dab02de..e7b4e83 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1196,6 +1196,23 @@
return false;
}
+ boolean isExitAnimationRunningSelfOrChild() {
+ if (!mTransitionController.isShellTransitionsEnabled()) {
+ return isAnimating(TRANSITION | CHILDREN, WindowState.EXIT_ANIMATING_TYPES);
+ }
+ if (mTransitionController.isCollecting(this)) {
+ return true;
+ }
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ WindowContainer child = mChildren.get(i);
+ if (child.isExitAnimationRunningSelfOrChild()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6718235..c50888b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -119,7 +119,6 @@
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -745,6 +744,9 @@
private final DisplayHashController mDisplayHashController;
+ volatile float mMaximumObscuringOpacityForTouch =
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH;
+
@VisibleForTesting
final WindowContextListenerController mWindowContextListenerController =
new WindowContextListenerController();
@@ -782,6 +784,8 @@
DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR);
private final Uri mDisplaySettingsPathUri = Settings.Global.getUriFor(
DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH);
+ private final Uri mMaximumObscuringOpacityForTouchUri = Settings.Global.getUriFor(
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
public SettingsObserver() {
super(new Handler());
@@ -806,6 +810,8 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mMaximumObscuringOpacityForTouchUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -849,6 +855,11 @@
return;
}
+ if (mMaximumObscuringOpacityForTouchUri.equals(uri)) {
+ updateMaximumObscuringOpacityForTouch();
+ return;
+ }
+
@UpdateAnimationScaleMode
final int mode;
if (mWindowAnimationScaleUri.equals(uri)) {
@@ -868,6 +879,14 @@
void loadSettings() {
updateSystemUiSettings(false /* handleChange */);
updatePointerLocation();
+ updateMaximumObscuringOpacityForTouch();
+ }
+
+ void updateMaximumObscuringOpacityForTouch() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mMaximumObscuringOpacityForTouch = Settings.Global.getFloat(resolver,
+ Settings.Global.MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH,
+ InputManager.DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH);
}
void updateSystemUiSettings(boolean handleChange) {
@@ -2192,7 +2211,7 @@
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
ClientWindowFrames outFrames, MergedConfiguration mergedConfiguration,
SurfaceControl outSurfaceControl, InsetsState outInsetsState,
- InsetsSourceControl[] outActiveControls) {
+ InsetsSourceControl[] outActiveControls, Bundle outSyncIdBundle) {
Arrays.fill(outActiveControls, null);
int result = 0;
boolean configChanged;
@@ -2483,8 +2502,6 @@
ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
win, focusMayChange);
- result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
-
if (DEBUG_LAYOUT) {
Slog.v(TAG_WM, "Relayout complete " + win + ": outFrames=" + outFrames);
}
@@ -2543,8 +2560,7 @@
if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
focusMayChange = true;
win.mAnimatingExit = true;
- } else if (win.mDisplayContent.okToAnimate() && win.isAnimating(TRANSITION | PARENTS,
- WindowState.EXIT_ANIMATING_TYPES)) {
+ } else if (win.mDisplayContent.okToAnimate() && win.isExitAnimationRunningSelfOrParent()) {
// Currently in a hide animation... turn this into
// an exit.
win.mAnimatingExit = true;
@@ -2617,7 +2633,7 @@
}
void finishDrawingWindow(Session session, IWindow client,
- @Nullable SurfaceControl.Transaction postDrawTransaction) {
+ @Nullable SurfaceControl.Transaction postDrawTransaction, int seqId) {
if (postDrawTransaction != null) {
postDrawTransaction.sanitize();
}
@@ -2628,7 +2644,7 @@
WindowState win = windowForClientLocked(session, client, false);
ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
- if (win != null && win.finishDrawing(postDrawTransaction)) {
+ if (win != null && win.finishDrawing(postDrawTransaction, seqId)) {
if (win.hasWallpaper()) {
win.getDisplayContent().pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index db687f6..60e196c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -134,6 +134,7 @@
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_STARTING_REVEAL;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowContainerChildProto.WINDOW;
@@ -1393,13 +1394,13 @@
}
// TODO(b/161810301): Make the frame be passed from the client side.
- void setFrame() {
- // TODO(b/161810301): Set the window frame here. We don't have to do it now because
- // DisplayPolicy has already done it for the window.
-
+ void setFrames(ClientWindowFrames clientWindowFrames) {
mHaveFrame = true;
final WindowFrames windowFrames = mWindowFrames;
+ windowFrames.mDisplayFrame.set(clientWindowFrames.displayFrame);
+ windowFrames.mParentFrame.set(clientWindowFrames.parentFrame);
+ windowFrames.mFrame.set(clientWindowFrames.frame);
if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
mLastRequestedWidth = mRequestedWidth;
@@ -2610,8 +2611,7 @@
mWmService.mAccessibilityController.onWindowTransition(this, transit);
}
}
- final boolean isAnimating = mAnimatingExit
- || isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES);
+ final boolean isAnimating = mAnimatingExit || isExitAnimationRunningSelfOrParent();
final boolean lastWindowIsStartingWindow = startingWindow && mActivityRecord != null
&& mActivityRecord.isLastWindow(this);
// We delay the removal of a window if it has a showing surface that can be used to run
@@ -3946,7 +3946,7 @@
try {
mClient.resized(mClientWindowFrames, reportDraw, mLastReportedConfiguration,
- forceRelayout, alwaysConsumeSystemBars, displayId);
+ forceRelayout, alwaysConsumeSystemBars, displayId, Integer.MAX_VALUE);
if (drawPending && reportOrientation && mOrientationChanging) {
mOrientationChangeRedrawRequestTime = SystemClock.elapsedRealtime();
ProtoLog.v(WM_DEBUG_ORIENTATION,
@@ -4977,6 +4977,15 @@
return false;
}
+ boolean isExitAnimationRunningSelfOrParent() {
+ return inAppOrRecentsTransition()
+ || isAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
+ boolean isExitAnimationRunningSelfOrChild() {
+ return isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION);
+ }
+
private boolean shouldFinishAnimatingExit() {
// Exit animation might be applied soon.
if (inTransition()) {
@@ -4988,7 +4997,7 @@
return true;
}
// Exit animation is running.
- if (isAnimating(TRANSITION | PARENTS, EXIT_ANIMATING_TYPES)) {
+ if (isExitAnimationRunningSelfOrParent()) {
ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "shouldWaitAnimatingExit: isAnimating: %s",
this);
return false;
@@ -5081,7 +5090,7 @@
@Override
boolean handleCompleteDeferredRemoval() {
- if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, EXIT_ANIMATING_TYPES)) {
+ if (mRemoveOnExit && !isSelfAnimating(0 /* flags */, ANIMATION_TYPE_WINDOW_ANIMATION)) {
mRemoveOnExit = false;
removeImmediately();
}
@@ -5938,7 +5947,7 @@
super.finishSync(outMergedTransaction, cancel);
}
- boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction) {
+ boolean finishDrawing(SurfaceControl.Transaction postDrawTransaction, int syncSeqId) {
if (mOrientationChangeRedrawRequestTime > 0) {
final long duration =
SystemClock.elapsedRealtime() - mOrientationChangeRedrawRequestTime;
@@ -5985,7 +5994,7 @@
void immediatelyNotifyBlastSync() {
prepareDrawHandlers();
- finishDrawing(null);
+ finishDrawing(null, Integer.MAX_VALUE);
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!useBLASTSync()) return;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 200b120..ba00bee 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -189,4 +189,9 @@
public ParcelableResource getString(String stringId) {
return null;
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ return false;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3d40f48..3a98e4e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -18790,4 +18790,18 @@
mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
}
+
+ @Override
+ public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ROLE_HOLDERS));
+ return mInjector.binderWithCleanCallingIdentity(() -> {
+ if (mUserManager.getUserCount() > 1) {
+ return false;
+ }
+ AccountManager am = AccountManager.get(mContext);
+ Account[] accounts = am.getAccounts();
+ return accounts.length == 0;
+ });
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index f05658b..e096687 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -494,9 +494,9 @@
final ArgumentCaptor<AlarmManagerService.UninstallReceiver> packageReceiverCaptor =
ArgumentCaptor.forClass(AlarmManagerService.UninstallReceiver.class);
- verify(mMockContext).registerReceiver(packageReceiverCaptor.capture(),
+ verify(mMockContext).registerReceiverForAllUsers(packageReceiverCaptor.capture(),
argThat((filter) -> filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
- && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)));
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)), isNull(), isNull());
mPackageChangesReceiver = packageReceiverCaptor.getValue();
assertEquals(mService.mExactAlarmCandidates, Collections.emptySet());
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
index 41d46f2..534d0a1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.content.Context;
@@ -71,10 +70,10 @@
.strictness(Strictness.LENIENT)
.mockStatic(LocalServices.class)
.startMocking();
- when(mIrs.getContext()).thenReturn(mContext);
- when(mIrs.getCompleteEconomicPolicyLocked()).thenReturn(mEconomicPolicy);
- when(mIrs.getLock()).thenReturn(mIrs);
- when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mock(AlarmManager.class));
+ doReturn(mContext).when(mIrs).getContext();
+ doReturn(mEconomicPolicy).when(mIrs).getCompleteEconomicPolicyLocked();
+ doReturn(mIrs).when(mIrs).getLock();
+ doReturn(mock(AlarmManager.class)).when(mContext).getSystemService(Context.ALARM_SERVICE);
mScribe = new MockScribe(mIrs);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index ab29e59..c2cf2ff 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -109,6 +109,7 @@
long lastReclamationTime = System.currentTimeMillis();
long remainingConsumableNarcs = 2000L;
long consumptionLimit = 500_000L;
+ when(mIrs.getConsumptionLimitLocked()).thenReturn(consumptionLimit);
Ledger ledger = mScribeUnderTest.getLedgerLocked(TEST_USER_ID, TEST_PACKAGE);
ledger.recordTransaction(new Ledger.Transaction(0, 1000L, 1, null, 2000, 0));
@@ -119,8 +120,13 @@
mScribeUnderTest.setConsumptionLimitLocked(consumptionLimit);
mScribeUnderTest.adjustRemainingConsumableNarcsLocked(
remainingConsumableNarcs - consumptionLimit);
- mScribeUnderTest.writeImmediatelyForTesting();
+ assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
+ assertEquals(remainingConsumableNarcs,
+ mScribeUnderTest.getRemainingConsumableNarcsLocked());
+ assertEquals(consumptionLimit, mScribeUnderTest.getSatiatedConsumptionLimitLocked());
+
+ mScribeUnderTest.writeImmediatelyForTesting();
mScribeUnderTest.loadFromDiskLocked();
assertEquals(lastReclamationTime, mScribeUnderTest.getLastReclamationTimeLocked());
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 152f3b3..e3be3a7 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -64,6 +64,7 @@
"testng",
"junit",
"platform-compat-test-rules",
+ "ActivityContext",
],
aidl: {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 1f016fb..56c5150 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -28,6 +28,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -61,10 +63,12 @@
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.TestUtils;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService.AccessibilityDisplayListener;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.MagnificationController;
+import com.android.server.accessibility.magnification.MagnificationProcessor;
import com.android.server.accessibility.magnification.WindowMagnificationManager;
import com.android.server.accessibility.test.MessageCapturingHandler;
import com.android.server.pm.UserManagerInternal;
@@ -185,7 +189,7 @@
mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
}
- private void setupAccessibilityServiceConnection() {
+ private void setupAccessibilityServiceConnection(int serviceInfoFlag) {
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
@@ -193,7 +197,12 @@
mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
when(mMockBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
+ when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mock(KeyEventDispatcher.class));
+ when(mMockSystemSupport.getMagnificationProcessor()).thenReturn(
+ mock(MagnificationProcessor.class));
mTestableContext.addMockService(COMPONENT_NAME, mMockBinder);
+
+ mMockServiceInfo.flags = serviceInfoFlag;
mAccessibilityServiceConnection = new AccessibilityServiceConnection(
userState,
mTestableContext,
@@ -256,7 +265,7 @@
@SmallTest
@Test
public void testOnSystemActionsChanged() throws Exception {
- setupAccessibilityServiceConnection();
+ setupAccessibilityServiceConnection(0);
final AccessibilityUserState userState = mA11yms.mUserStates.get(
mA11yms.getCurrentUserIdLocked());
@@ -376,7 +385,7 @@
@SmallTest
@Test
public void testOnClientChange_boundServiceCanControlMagnification_requestConnection() {
- setupAccessibilityServiceConnection();
+ setupAccessibilityServiceConnection(0);
when(mMockSecurityPolicy.canControlMagnification(any())).thenReturn(true);
// Invokes client change to trigger onUserStateChanged.
@@ -385,6 +394,29 @@
verify(mMockWindowMagnificationMgr).requestConnection(true);
}
+ @Test
+ public void testUnbindIme_whenServiceUnbinds() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ mAccessibilityServiceConnection.unbindLocked();
+ verify(mMockSystemSupport, atLeastOnce()).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
+ @Test
+ public void testUnbindIme_whenServiceCrashed() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ mAccessibilityServiceConnection.binderDied();
+ verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
+ @Test
+ public void testUnbindIme_whenServiceStopsRequestingIme() {
+ setupAccessibilityServiceConnection(AccessibilityServiceInfo.FLAG_INPUT_METHOD_EDITOR);
+ doCallRealMethod().when(mMockServiceInfo).updateDynamicallyConfigurableProperties(
+ any(IPlatformCompat.class), any(AccessibilityServiceInfo.class));
+ mAccessibilityServiceConnection.setServiceInfo(new AccessibilityServiceInfo());
+ verify(mMockSystemSupport).unbindImeLocked(mAccessibilityServiceConnection);
+ }
+
public static class FakeInputFilter extends AccessibilityInputFilter {
FakeInputFilter(Context context,
AccessibilityManagerService service) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
index 3cb5d5f..ce322f7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java
@@ -20,6 +20,7 @@
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.IApplicationThread;
import android.app.admin.DevicePolicyManagerInternal;
@@ -46,6 +47,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
+import com.android.activitycontext.ActivityContext;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.server.LocalServices;
@@ -240,7 +242,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -265,7 +269,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -292,7 +298,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -319,7 +327,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -344,7 +354,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -369,7 +381,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -396,7 +410,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -440,7 +456,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -465,7 +483,9 @@
FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -490,7 +510,9 @@
FEATURE_ID,
new ComponentName(PACKAGE_TWO, "test"),
UserHandle.of(PROFILE_OF_PRIMARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -515,7 +537,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
- true));
+ true,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -540,7 +564,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(SECONDARY_USER).getIdentifier(),
- false));
+ false,
+ /* targetTask */ null,
+ /* options */ null));
verify(mActivityTaskManagerInternal, never())
.startActivityAsUser(
@@ -564,7 +590,9 @@
FEATURE_ID,
ACTIVITY_COMPONENT,
UserHandle.of(PRIMARY_USER).getIdentifier(),
- true);
+ true,
+ /* targetTask */ null,
+ /* options */ null);
verify(mActivityTaskManagerInternal)
.startActivityAsUser(
@@ -578,6 +606,44 @@
eq(PRIMARY_USER));
}
+ @Test
+ public void startActivityAsUser_sameTask_fromProfile_success() throws Exception {
+ mTestInjector.setCallingUserId(PROFILE_OF_PRIMARY_USER);
+
+ Bundle options = ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle();
+ IBinder result = ActivityContext.getWithContext(activity -> {
+ try {
+ IBinder targetTask = activity.getActivityToken();
+ mCrossProfileAppsServiceImpl.startActivityAsUser(
+ mIApplicationThread,
+ PACKAGE_ONE,
+ FEATURE_ID,
+ ACTIVITY_COMPONENT,
+ UserHandle.of(PRIMARY_USER).getIdentifier(),
+ true,
+ targetTask,
+ options);
+ return targetTask;
+ } catch (Exception re) {
+ return null;
+ }
+ });
+ if (result == null) {
+ throw new Exception();
+ }
+
+ verify(mActivityTaskManagerInternal)
+ .startActivityAsUser(
+ nullable(IApplicationThread.class),
+ eq(PACKAGE_ONE),
+ eq(FEATURE_ID),
+ any(Intent.class),
+ eq(result),
+ anyInt(),
+ eq(options),
+ eq(PRIMARY_USER));
+ }
+
private void mockAppsInstalled(String packageName, int user, boolean installed) {
when(mPackageManagerInternal.getPackageInfo(
eq(packageName),
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index c7b5547..06b7112 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -316,7 +316,8 @@
asHandle(currentUser));
try {
assertThat(mUserManager.removeUserWhenPossible(user1.getUserHandle(),
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_RESTRICTION);
} finally {
mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_USER, /* value= */ false,
asHandle(currentUser));
@@ -353,7 +354,8 @@
@Test
public void testRemoveUserWhenPossible_systemUserReturnsError() throws Exception {
assertThat(mUserManager.removeUserWhenPossible(UserHandle.SYSTEM,
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_SYSTEM_USER);
assertThat(hasUser(UserHandle.USER_SYSTEM)).isTrue();
}
@@ -363,7 +365,8 @@
public void testRemoveUserWhenPossible_invalidUserReturnsError() throws Exception {
assertThat(hasUser(Integer.MAX_VALUE)).isFalse();
assertThat(mUserManager.removeUserWhenPossible(UserHandle.of(Integer.MAX_VALUE),
- /* overrideDevicePolicy= */ false)).isEqualTo(UserManager.REMOVE_RESULT_ERROR);
+ /* overrideDevicePolicy= */ false))
+ .isEqualTo(UserManager.REMOVE_RESULT_ERROR_USER_NOT_FOUND);
}
@MediumTest
diff --git a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
index d76a1de..83139b0 100644
--- a/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/statusbar/StatusBarManagerServiceTest.java
@@ -692,23 +692,12 @@
public void testSetNavBarMode_invalidInputThrowsError() throws RemoteException {
int navBarModeInvalid = -1;
- assertThrows(UnsupportedOperationException.class,
+ assertThrows(IllegalArgumentException.class,
() -> mStatusBarManagerService.setNavBarMode(navBarModeInvalid));
verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
}
@Test
- public void testSetNavBarMode_noOverlayManagerDoesNotEnable() throws RemoteException {
- mOverlayManager = null;
- int navBarModeKids = StatusBarManager.NAV_BAR_MODE_KIDS;
-
- mStatusBarManagerService.setNavBarMode(navBarModeKids);
-
- assertEquals(navBarModeKids, mStatusBarManagerService.getNavBarMode());
- verify(mOverlayManager, never()).setEnabledExclusiveInCategory(anyString(), anyInt());
- }
-
- @Test
public void testSetNavBarMode_noPackageDoesNotEnable() throws Exception {
mContext.setMockPackageManager(mPackageManager);
when(mPackageManager.getPackageInfo(anyString(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 31be33e..fd1536c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,6 +43,7 @@
import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER;
import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER;
+import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -1611,6 +1612,35 @@
}
@Test
+ public void testAddAutomaticZenRule_beyondSystemLimit() {
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+
+ }
+
+ @Test
public void testAddAutomaticZenRule_CA() {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index d4d8b868..7689e08 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -256,6 +256,14 @@
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
+
+ // If an activity is removed immediately before visibility update, it should cancel too.
+ final ActivityRecord removedImm = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ clearInvocations(mLaunchObserver);
+ onActivityLaunched(removedImm);
+ removedImm.removeImmediately();
+ // Verify any() instead of proto because the field of record may be changed.
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(any());
}
@Test
@@ -299,15 +307,16 @@
@Test
public void testOnReportFullyDrawn() {
// Create an invisible event that should be cancelled after the next event starts.
- onActivityLaunched(mTrampolineActivity);
- mTrampolineActivity.mVisibleRequested = false;
+ final ActivityRecord prev = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ onActivityLaunched(prev);
+ prev.mVisibleRequested = false;
mActivityOptions = ActivityOptions.makeBasic();
mActivityOptions.setSourceInfo(SourceInfo.TYPE_LAUNCHER, SystemClock.uptimeMillis() - 10);
onIntentStarted(mTopActivity.intent);
notifyActivityLaunched(START_SUCCESS, mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
- verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTrampolineActivity));
+ verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(prev));
// The activity reports fully drawn before windows drawn, then the fully drawn event will
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index c21a5b6..92550a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -30,7 +30,10 @@
import android.annotation.NonNull;
import android.hardware.HardwareBuffer;
import android.platform.test.annotations.Presubmit;
+import android.window.BackEvent;
import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
import android.window.TaskSnapshot;
import org.junit.Before;
@@ -42,15 +45,19 @@
public class BackNavigationControllerTests extends WindowTestsBase {
private BackNavigationController mBackNavigationController;
+ private IOnBackInvokedCallback mOnBackInvokedCallback;
@Before
public void setUp() throws Exception {
mBackNavigationController = new BackNavigationController();
+ mOnBackInvokedCallback = createBackCallback();
}
@Test
public void backTypeHomeWhenBackToLauncher() {
Task task = createTopTaskWithActivity();
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -63,6 +70,8 @@
Task taskA = createTask(mDefaultDisplay);
createActivityRecord(taskA);
Task task = createTopTaskWithActivity();
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -75,6 +84,8 @@
Task task = createTopTaskWithActivity();
mAtm.setFocusedTask(task.mTaskId,
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
+ registerSystemOnBackInvokedCallback();
+
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -89,6 +100,7 @@
public void backNavInfoFullyPopulated() {
Task task = createTopTaskWithActivity();
createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
+ registerSystemOnBackInvokedCallback();
// We need a mock screenshot so
TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -104,6 +116,30 @@
assertThat(backNavigationInfo.getTaskWindowConfiguration()).isNotNull();
}
+ @Test
+ public void preparesForBackToHome() {
+ Task task = createTopTaskWithActivity();
+ ActivityRecord activity = task.getTopActivity(false, false);
+ registerSystemOnBackInvokedCallback();
+
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+ }
+
+ @Test
+ public void backTypeCallback() {
+ Task task = createTopTaskWithActivity();
+ ActivityRecord activity = task.getTopActivity(false, false);
+ registerApplicationOnBackInvokedCallback();
+
+ BackNavigationInfo backNavigationInfo =
+ mBackNavigationController.startBackNavigation(task, new StubTransaction());
+ assertThat(typeToString(backNavigationInfo.getType()))
+ .isEqualTo(typeToString(BackNavigationInfo.TYPE_CALLBACK));
+ }
+
@NonNull
private TaskSnapshotController createMockTaskSnapshotController() {
TaskSnapshotController taskSnapshotController = mock(TaskSnapshotController.class);
@@ -126,4 +162,30 @@
mAtm.setFocusedTask(task.mTaskId, record);
return task;
}
+
+ private void registerSystemOnBackInvokedCallback() {
+ mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+ mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_SYSTEM);
+ }
+
+ private void registerApplicationOnBackInvokedCallback() {
+ mWm.getFocusedWindowLocked().setOnBackInvokedCallback(
+ mOnBackInvokedCallback, OnBackInvokedDispatcher.PRIORITY_DEFAULT);
+ }
+
+ private IOnBackInvokedCallback createBackCallback() {
+ return new IOnBackInvokedCallback.Stub() {
+ @Override
+ public void onBackStarted() { }
+
+ @Override
+ public void onBackProgressed(BackEvent backEvent) { }
+
+ @Override
+ public void onBackCancelled() { }
+
+ @Override
+ public void onBackInvoked() { }
+ };
+ }
}
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 636c6bc..9304761 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -259,6 +259,20 @@
}
@Test
+ public void testPerformClearTop() {
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build();
+ // Detach from process so the activities can be removed from hierarchy when finishing.
+ activity1.detachFromProcess();
+ activity2.detachFromProcess();
+ assertNull(task.performClearTop(activity1, 0 /* launchFlags */));
+ assertFalse(task.hasChild());
+ // In real case, the task should be preserved for adding new activity.
+ assertTrue(task.isAttached());
+ }
+
+ @Test
public void testRemoveChildForOverlayTask() {
final Task task = createTask(mDisplayContent);
final int taskId = task.mTaskId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index 7dfb5ae..4f35d55 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -44,7 +44,7 @@
@Override
public void resized(ClientWindowFrames frames, boolean reportDraw,
MergedConfiguration mergedConfig, boolean forceLayout, boolean alwaysConsumeSystemBars,
- int displayId) throws RemoteException {
+ int displayId, int seqId) throws RemoteException {
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index c4547f6..7e5d017 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -692,7 +692,8 @@
statusBar.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
final SurfaceControl.Transaction postDrawTransaction =
mock(SurfaceControl.Transaction.class);
- final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction);
+ final boolean layoutNeeded = statusBar.finishDrawing(postDrawTransaction,
+ Integer.MAX_VALUE);
assertFalse(layoutNeeded);
transactionCommittedListener.onTransactionCommitted();
@@ -742,7 +743,7 @@
player.finish();
// The controller should be cleared if the target windows are drawn.
- statusBar.finishDrawing(mWm.mTransactionFactory.get());
+ statusBar.finishDrawing(mWm.mTransactionFactory.get(), Integer.MAX_VALUE);
statusBar.setOrientationChanging(false);
assertNull(mDisplayContent.getAsyncRotationController());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
index 7d2e9bf..ea18e58 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowLayoutTests.java
@@ -45,6 +45,7 @@
import android.view.WindowInsets;
import android.view.WindowLayout;
import android.view.WindowManager;
+import android.window.ClientWindowFrames;
import androidx.test.filters.SmallTest;
@@ -71,9 +72,7 @@
private static final Insets WATERFALL_INSETS = Insets.of(6, 0, 12, 0);
private final WindowLayout mWindowLayout = new WindowLayout();
- private final Rect mDisplayFrame = new Rect();
- private final Rect mParentFrame = new Rect();
- private final Rect mFrame = new Rect();
+ private final ClientWindowFrames mOutFrames = new ClientWindowFrames();
private WindowManager.LayoutParams mAttrs;
private InsetsState mState;
@@ -108,7 +107,7 @@
private void computeFrames() {
mWindowLayout.computeFrames(mAttrs, mState, mDisplayCutoutSafe, mWindowBounds,
mWindowingMode, mRequestedWidth, mRequestedHeight, mRequestedVisibilities,
- mAttachedWindowFrame, mCompatScale, mDisplayFrame, mParentFrame, mFrame);
+ mAttachedWindowFrame, mCompatScale, mOutFrames);
}
private void addDisplayCutout() {
@@ -146,9 +145,9 @@
public void defaultParams() {
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -157,9 +156,9 @@
mRequestedHeight = UNSPECIFIED_LENGTH;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -173,9 +172,9 @@
mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertRect(0, STATUS_BAR_HEIGHT, width, STATUS_BAR_HEIGHT + height, mOutFrames.frame);
}
@Test
@@ -186,9 +185,12 @@
mRequestedHeight = UNSPECIFIED_LENGTH;
computeFrames();
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT, mFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.displayFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.parentFrame);
+ assertRect(0, top, DISPLAY_WIDTH, DISPLAY_HEIGHT - NAVIGATION_BAR_HEIGHT,
+ mOutFrames.frame);
}
@Test
@@ -196,9 +198,9 @@
mAttrs.setFitInsetsTypes(WindowInsets.Type.statusBars());
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
}
@Test
@@ -206,9 +208,9 @@
mAttrs.setFitInsetsTypes(WindowInsets.Type.navigationBars());
computeFrames();
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -216,9 +218,9 @@
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -226,9 +228,9 @@
mAttrs.setFitInsetsSides(WindowInsets.Side.all());
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -236,9 +238,9 @@
mAttrs.setFitInsetsSides(WindowInsets.Side.TOP);
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, 0, mOutFrames.frame);
}
@Test
@@ -246,9 +248,9 @@
mAttrs.setFitInsetsSides(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -257,9 +259,9 @@
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
@Test
@@ -269,9 +271,9 @@
mAttrs.setFitInsetsIgnoringVisibility(true);
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.frame);
}
@Test
@@ -282,9 +284,9 @@
mAttrs.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
computeFrames();
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mDisplayFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mParentFrame);
- assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, NAVIGATION_BAR_HEIGHT, mOutFrames.displayFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.parentFrame);
+ assertInsetByTopBottom(STATUS_BAR_HEIGHT, IME_HEIGHT, mOutFrames.frame);
}
@Test
@@ -295,11 +297,11 @@
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, DISPLAY_CUTOUT_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -310,11 +312,11 @@
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -325,9 +327,9 @@
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
}
@Test
@@ -342,9 +344,9 @@
mAttrs.privateFlags |= PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
computeFrames();
- assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayFrame);
- assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mParentFrame);
- assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.displayFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, mOutFrames.parentFrame);
+ assertRect(0, 0, DISPLAY_WIDTH, height + DISPLAY_CUTOUT_HEIGHT, mOutFrames.frame);
}
@Test
@@ -357,11 +359,11 @@
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -371,9 +373,9 @@
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mDisplayFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mParentFrame);
- assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.displayFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.parentFrame);
+ assertInsetBy(WATERFALL_INSETS.left, 0, WATERFALL_INSETS.right, 0, mOutFrames.frame);
}
@Test
@@ -384,11 +386,11 @@
computeFrames();
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mDisplayFrame);
+ mOutFrames.displayFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mParentFrame);
+ mOutFrames.parentFrame);
assertInsetBy(WATERFALL_INSETS.left, STATUS_BAR_HEIGHT, WATERFALL_INSETS.right, 0,
- mFrame);
+ mOutFrames.frame);
}
@Test
@@ -398,8 +400,8 @@
mAttrs.setFitInsetsTypes(0);
computeFrames();
- assertInsetByTopBottom(0, 0, mDisplayFrame);
- assertInsetByTopBottom(0, 0, mParentFrame);
- assertInsetByTopBottom(0, 0, mFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.displayFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.parentFrame);
+ assertInsetByTopBottom(0, 0, mOutFrames.frame);
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 25d7334..b4d305b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -932,7 +932,7 @@
mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
assertNotNull(o.mChangedInfo);
assertNotNull(o.mChangedInfo.pictureInPictureParams);
- final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
+ final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatio();
assertEquals(3, ratio.getNumerator());
assertEquals(4, ratio.getDenominator());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 6d7895f..6a3aa78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -504,7 +504,7 @@
assertTrue(win.useBLASTSync());
final SurfaceControl.Transaction drawT = new StubTransaction();
win.prepareDrawHandlers();
- assertTrue(win.finishDrawing(drawT));
+ assertTrue(win.finishDrawing(drawT, Integer.MAX_VALUE));
assertEquals(drawT, handledT[0]);
assertFalse(win.useBLASTSync());
@@ -693,7 +693,7 @@
doThrow(new RemoteException("test")).when(win.mClient).resized(any() /* frames */,
anyBoolean() /* reportDraw */, any() /* mergedConfig */,
anyBoolean() /* forceLayout */, anyBoolean() /* alwaysConsumeSystemBars */,
- anyInt() /* displayId */);
+ anyInt() /* displayId */, anyInt() /* seqId */);
} catch (RemoteException ignored) {
}
win.reportResized();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 5a95210..3988892 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -67,6 +67,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SharedMemory;
+import android.provider.DeviceConfig;
import android.service.voice.HotwordDetectedResult;
import android.service.voice.HotwordDetectionService;
import android.service.voice.HotwordDetector;
@@ -110,12 +111,20 @@
private static final String TAG = "HotwordDetectionConnection";
static final boolean DEBUG = false;
+ private static final String KEY_RESTART_PERIOD_IN_SECONDS = "restart_period_in_seconds";
// TODO: These constants need to be refined.
private static final long VALIDATION_TIMEOUT_MILLIS = 4000;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
private static final long RESET_DEBUG_HOTWORD_LOGGING_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour
+ /**
+ * Time after which each HotwordDetectionService process is stopped and replaced by a new one.
+ * 0 indicates no restarts.
+ */
+ private static final int RESTART_PERIOD_SECONDS =
+ DeviceConfig.getInt(DeviceConfig.NAMESPACE_VOICE_INTERACTION,
+ KEY_RESTART_PERIOD_IN_SECONDS, 0);
private static final int MAX_ISOLATED_PROCESS_NUMBER = 10;
// Hotword metrics
@@ -134,6 +143,7 @@
// TODO: This may need to be a Handler(looper)
private final ScheduledExecutorService mScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
+ @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
@@ -150,7 +160,6 @@
private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
private Instant mLastRestartInstant;
- private ScheduledFuture<?> mCancellationTaskFuture;
private ScheduledFuture<?> mCancellationKeyPhraseDetectionFuture;
private ScheduledFuture<?> mDebugHotwordLoggingTimeoutFuture = null;
@@ -196,16 +205,20 @@
mLastRestartInstant = Instant.now();
updateStateAfterProcessStart(options, sharedMemory);
- // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
- // until the current session is closed.
- mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
- Slog.v(TAG, "Time to restart the process, TTL has passed");
- synchronized (mLock) {
- restartProcessLocked();
- HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
- HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
- }
- }, 30, 30, TimeUnit.MINUTES);
+ if (RESTART_PERIOD_SECONDS <= 0) {
+ mCancellationTaskFuture = null;
+ } else {
+ // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
+ // until the current session is closed.
+ mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
+ Slog.v(TAG, "Time to restart the process, TTL has passed");
+ synchronized (mLock) {
+ restartProcessLocked();
+ HotwordMetricsLogger.writeServiceRestartEvent(mDetectorType,
+ HOTWORD_DETECTION_SERVICE_RESTARTED__REASON__SCHEDULE);
+ }
+ }, RESTART_PERIOD_SECONDS, RESTART_PERIOD_SECONDS, TimeUnit.SECONDS);
+ }
}
private void initAudioFlingerLocked() {
@@ -346,7 +359,9 @@
removeServiceUidForAudioPolicy(mIdentity.getIsolatedUid());
}
mIdentity = null;
- mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ if (mCancellationTaskFuture != null) {
+ mCancellationTaskFuture.cancel(/* may interrupt */ true);
+ }
if (mAudioFlinger != null) {
mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0);
}
@@ -764,6 +779,7 @@
}
public void dump(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("RESTART_PERIOD_SECONDS="); pw.println(RESTART_PERIOD_SECONDS);
pw.print(prefix);
pw.print("mBound=" + mRemoteHotwordDetectionService.isBound());
pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 837cf8b..cff90bb 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -504,7 +504,12 @@
/** Control whether users can choose a network operator. */
public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
- /** Used in Cellular Network Settings for preferred network type. */
+ /**
+ * Used in the Preferred Network Types menu to determine if the 2G option is displayed.
+ * Value defaults to false as of Android T to discourage the use of insecure 2G protocols.
+ *
+ * @see #KEY_HIDE_ENABLE_2G
+ */
public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
/**
@@ -8594,7 +8599,7 @@
sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
sDefaults.putBoolean(KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
- sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
+ sDefaults.putBoolean(KEY_PREFER_2G_BOOL, false);
sDefaults.putBoolean(KEY_4G_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_APN_SETTING_CDMA_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 5ef22de..3f430ab 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8352,24 +8352,6 @@
}
/**
- * Get P-CSCF address from PCO after data connection is established or modified.
- * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
- * @return array of P-CSCF address
- * @hide
- */
- public String[] getPcscfAddress(String apnType) {
- try {
- ITelephony telephony = getITelephony();
- if (telephony == null)
- return new String[0];
- return telephony.getPcscfAddress(apnType, getOpPackageName(), getAttributionTag());
- } catch (RemoteException e) {
- return new String[0];
- }
- }
-
-
- /**
* Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot.
* Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to
* recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index fc94ebf..8143da5 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -549,7 +549,6 @@
* Returns the profile id to which the APN saved in modem.
*
* @return the profile id of the APN
- * @hide
*/
public int getProfileId() {
return mProfileId;
@@ -558,8 +557,7 @@
/**
* Returns if the APN setting is persistent on the modem.
*
- * @return is the APN setting to be set in modem
- * @hide
+ * @return {@code true} if the APN setting is persistent on the modem.
*/
public boolean isPersistent() {
return mPersistent;
@@ -1103,8 +1101,10 @@
sb.append(", ").append(MVNO_TYPE_INT_MAP.get(mMvnoType));
sb.append(", ").append(mMvnoMatchData);
sb.append(", ").append(mPermanentFailed);
- sb.append(", ").append(mNetworkTypeBitmask);
- sb.append(", ").append(mLingeringNetworkTypeBitmask);
+ sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+ mNetworkTypeBitmask));
+ sb.append(", ").append(TelephonyManager.convertNetworkTypeBitmaskToString(
+ mLingeringNetworkTypeBitmask));
sb.append(", ").append(mApnSetId);
sb.append(", ").append(mCarrierId);
sb.append(", ").append(mSkip464Xlat);
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 892eb29..bd346d5 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -31,6 +31,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
import android.util.Log;
import android.util.SparseArray;
@@ -166,7 +167,8 @@
* link properties of the existing data connection, otherwise null.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason, @Nullable LinkProperties linkProperties,
@NonNull DataServiceCallback callback) {
@@ -214,7 +216,8 @@
* for example, a zero-rating slice.
* @param callback The result callback for this request.
*/
- public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
+ public void setupDataCall(
+ @RadioAccessNetworkType int accessNetworkType, @NonNull DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming,
@SetupDataReason int reason,
@Nullable LinkProperties linkProperties,
@@ -294,6 +297,9 @@
* with reason {@link DataService.REQUEST_REASON_HANDOVER}. The target transport now owns
* the transferred resources and is responsible for releasing them.
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
@@ -322,6 +328,9 @@
* </li>
* </ul>
*
+ * <p/>
+ * Note that the callback will be executed on binder thread.
+ *
* @param cid The identifier of the data call which is provided in {@link DataCallResponse}
* @param callback The result callback for this request.
*
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index fe44530..5ffee56 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -32,7 +32,12 @@
import java.util.Objects;
/**
- * Provides Qos attributes of an EPS bearer.
+ * Provides QOS attributes of an EPS bearer.
+ *
+ * <p> The dedicated EPS bearer along with QOS is allocated by the LTE network and notified to the
+ * device. The Telephony framework creates the {@link EpsBearerQosSessionAttributes} object which
+ * represents the QOS of the dedicated bearer and notifies the same to applications via
+ * {@link QosCallback}.
*
* {@hide}
*/
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dc96b35..a5e2c1f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -978,14 +978,6 @@
boolean isManualNetworkSelectionAllowed(int subId);
/**
- * Get P-CSCF address from PCO after data connection is established or modified.
- * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
- * @param callingPackage The package making the call.
- * @param callingFeatureId The feature in the package.
- */
- String[] getPcscfAddress(String apnType, String callingPackage, String callingFeatureId);
-
- /**
* Set IMS registration state
*/
void setImsRegistrationState(boolean registered);
diff --git a/tools/traceinjection/Android.bp b/tools/traceinjection/Android.bp
new file mode 100644
index 0000000..1395c5f
--- /dev/null
+++ b/tools/traceinjection/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_binary_host {
+ name: "traceinjection",
+ manifest: "manifest.txt",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "asm-7.0",
+ "asm-commons-7.0",
+ "asm-tree-7.0",
+ "asm-analysis-7.0",
+ "guava-21.0",
+ ],
+}
+
+java_library_host {
+ name: "TraceInjectionTests-Uninjected",
+ srcs: ["test/**/*.java"],
+ static_libs: [
+ "junit",
+ ],
+}
+
+java_genrule_host {
+ name: "TraceInjectionTests-Injected",
+ srcs: [":TraceInjectionTests-Uninjected"],
+ tools: ["traceinjection"],
+ cmd: "$(location traceinjection) " +
+ " --annotation \"com/android/traceinjection/Trace\"" +
+ " --start \"com/android/traceinjection/InjectionTests.traceStart\"" +
+ " --end \"com/android/traceinjection/InjectionTests.traceEnd\"" +
+ " -o $(out) " +
+ " -i $(in)",
+ out: ["TraceInjectionTests-Injected.jar"],
+}
+
+java_test_host {
+ name: "TraceInjectionTests",
+ static_libs: [
+ "TraceInjectionTests-Injected",
+ ],
+}
diff --git a/tools/traceinjection/manifest.txt b/tools/traceinjection/manifest.txt
new file mode 100644
index 0000000..7f4ee1d
--- /dev/null
+++ b/tools/traceinjection/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.traceinjection.Main
diff --git a/tools/traceinjection/src/com/android/traceinjection/Main.java b/tools/traceinjection/src/com/android/traceinjection/Main.java
new file mode 100644
index 0000000..190df81
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/Main.java
@@ -0,0 +1,121 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ String inJar = null;
+ String outJar = null;
+ String annotation = null;
+ String traceStart = null;
+ String traceEnd = null;
+
+ // All arguments require a value currently, so just make sure we have an even number and
+ // then process them all two at a time.
+ if (args.length % 2 != 0) {
+ throw new IllegalArgumentException("Argument is missing corresponding value");
+ }
+ for (int i = 0; i < args.length - 1; i += 2) {
+ final String arg = args[i].trim();
+ final String argValue = args[i + 1].trim();
+ if ("-i".equals(arg)) {
+ inJar = argValue;
+ } else if ("-o".equals(arg)) {
+ outJar = argValue;
+ } else if ("--annotation".equals(arg)) {
+ annotation = argValue;
+ } else if ("--start".equals(arg)) {
+ traceStart = argValue;
+ } else if ("--end".equals(arg)) {
+ traceEnd = argValue;
+ } else {
+ throw new IllegalArgumentException("Unknown argument: " + arg);
+ }
+ }
+
+ if (inJar == null) {
+ throw new IllegalArgumentException("input jar is required");
+ }
+
+ if (outJar == null) {
+ throw new IllegalArgumentException("output jar is required");
+ }
+
+ if (annotation == null) {
+ throw new IllegalArgumentException("trace annotation is required");
+ }
+
+ if (traceStart == null) {
+ throw new IllegalArgumentException("start trace method is required");
+ }
+
+ if (traceEnd == null) {
+ throw new IllegalArgumentException("end trace method is required");
+ }
+
+ TraceInjectionConfiguration params =
+ new TraceInjectionConfiguration(annotation, traceStart, traceEnd);
+
+ try (
+ ZipFile zipSrc = new ZipFile(inJar);
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outJar));
+ ) {
+ Enumeration<? extends ZipEntry> srcEntries = zipSrc.entries();
+ while (srcEntries.hasMoreElements()) {
+ ZipEntry entry = srcEntries.nextElement();
+ ZipEntry newEntry = new ZipEntry(entry.getName());
+ newEntry.setTime(entry.getTime());
+ zos.putNextEntry(newEntry);
+ BufferedInputStream bis = new BufferedInputStream(zipSrc.getInputStream(entry));
+
+ if (entry.getName().endsWith(".class")) {
+ convert(bis, zos, params);
+ } else {
+ while (bis.available() > 0) {
+ zos.write(bis.read());
+ }
+ zos.closeEntry();
+ bis.close();
+ }
+ }
+ zos.finish();
+ }
+ }
+
+ private static void convert(InputStream in, OutputStream out,
+ TraceInjectionConfiguration params) throws IOException {
+ ClassReader cr = new ClassReader(in);
+ ClassWriter cw = new ClassWriter(0);
+ TraceInjectionClassVisitor cv = new TraceInjectionClassVisitor(cw, params);
+ cr.accept(cv, ClassReader.EXPAND_FRAMES);
+ byte[] data = cw.toByteArray();
+ out.write(data);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
new file mode 100644
index 0000000..863f976
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionClassVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * {@link ClassVisitor} that injects tracing code to methods annotated with the configured
+ * annotation.
+ */
+public class TraceInjectionClassVisitor extends ClassVisitor {
+ private final TraceInjectionConfiguration mParams;
+ public TraceInjectionClassVisitor(ClassVisitor classVisitor,
+ TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, classVisitor);
+ mParams = params;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
+ MethodVisitor chain = super.visitMethod(access, name, desc, signature, exceptions);
+ return new TraceInjectionMethodAdapter(chain, access, name, desc, mParams);
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
new file mode 100644
index 0000000..f9595bd
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.traceinjection;
+
+/**
+ * Configuration data for trace method injection.
+ */
+public class TraceInjectionConfiguration {
+ public final String annotation;
+ public final String startMethodClass;
+ public final String startMethodName;
+ public final String endMethodClass;
+ public final String endMethodName;
+
+ public TraceInjectionConfiguration(String annotation, String startMethod, String endMethod) {
+ this.annotation = annotation;
+ String[] startMethodComponents = parseMethod(startMethod);
+ String[] endMethodComponents = parseMethod(endMethod);
+ startMethodClass = startMethodComponents[0];
+ startMethodName = startMethodComponents[1];
+ endMethodClass = endMethodComponents[0];
+ endMethodName = endMethodComponents[1];
+ }
+
+ public String toString() {
+ return "TraceInjectionParams{annotation=" + annotation
+ + ", startMethod=" + startMethodClass + "." + startMethodName
+ + ", endMethod=" + endMethodClass + "." + endMethodName + "}";
+ }
+
+ private static String[] parseMethod(String method) {
+ String[] methodComponents = method.split("\\.");
+ if (methodComponents.length != 2) {
+ throw new IllegalArgumentException("Invalid method descriptor: " + method);
+ }
+ return methodComponents;
+ }
+}
diff --git a/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
new file mode 100644
index 0000000..c2bbddc
--- /dev/null
+++ b/tools/traceinjection/src/com/android/traceinjection/TraceInjectionMethodAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.traceinjection;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.AdviceAdapter;
+import org.objectweb.asm.commons.Method;
+
+/**
+ * Adapter that injects tracing code to methods annotated with the configured annotation.
+ *
+ * Assuming the configured annotation is {@code @Trace} and the configured methods are
+ * {@code Tracing.begin()} and {@code Tracing.end()}, it effectively transforms:
+ *
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * doStuff();
+ * }
+ * }</pre>
+ *
+ * into:
+ * <pre>{@code
+ * @Trace
+ * void method() {
+ * Tracing.begin();
+ * try {
+ * doStuff();
+ * } finally {
+ * Tracing.end();
+ * }
+ * }
+ * }</pre>
+ */
+public class TraceInjectionMethodAdapter extends AdviceAdapter {
+ private final TraceInjectionConfiguration mParams;
+ private final Label mStartFinally = newLabel();
+ private final boolean mIsConstructor;
+
+ private boolean mShouldTrace;
+ private long mTraceId;
+ private String mTraceLabel;
+
+ public TraceInjectionMethodAdapter(MethodVisitor methodVisitor, int access,
+ String name, String descriptor, TraceInjectionConfiguration params) {
+ super(Opcodes.ASM7, methodVisitor, access, name, descriptor);
+ mParams = params;
+ mIsConstructor = "<init>".equals(name);
+ }
+
+ @Override
+ public void visitCode() {
+ super.visitCode();
+ if (mShouldTrace) {
+ visitLabel(mStartFinally);
+ }
+ }
+
+ @Override
+ protected void onMethodEnter() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.startMethodClass));
+ Method trace = Method.getMethod("void " + mParams.startMethodName + " (long, String)");
+ push(mTraceId);
+ push(getTraceLabel());
+ invokeStatic(type, trace);
+ }
+
+ private String getTraceLabel() {
+ return !isEmpty(mTraceLabel) ? mTraceLabel : getName();
+ }
+
+ @Override
+ protected void onMethodExit(int opCode) {
+ // Any ATHROW exits will be caught as part of our exception-handling block, so putting it
+ // here would cause us to call the end trace method multiple times.
+ if (opCode != ATHROW) {
+ onFinally();
+ }
+ }
+
+ private void onFinally() {
+ if (!mShouldTrace) {
+ return;
+ }
+ Type type = Type.getType(toJavaSpecifier(mParams.endMethodClass));
+ Method trace = Method.getMethod("void " + mParams.endMethodName + " (long)");
+ push(mTraceId);
+ invokeStatic(type, trace);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ final int minStackSize;
+ if (mShouldTrace) {
+ Label endFinally = newLabel();
+ visitLabel(endFinally);
+ catchException(mStartFinally, endFinally, null);
+ // The stack will always contain exactly one element: the exception we caught
+ final Object[] stack = new Object[]{ "java/lang/Throwable"};
+ // Because we use EXPAND_FRAMES, the frame type must always be F_NEW.
+ visitFrame(F_NEW, /* numLocal= */ 0, /* local= */ null, stack.length, stack);
+ onFinally();
+ // Rethrow the exception that we caught in the finally block.
+ throwException();
+
+ // Make sure we have at least enough stack space to push the trace arguments
+ // (long, String)
+ minStackSize = Type.LONG_TYPE.getSize() + Type.getType(String.class).getSize();
+ } else {
+ // We didn't inject anything, so no need for additional stack space.
+ minStackSize = 0;
+ }
+
+ super.visitMaxs(Math.max(minStackSize, maxStack), maxLocals);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+ AnnotationVisitor av = super.visitAnnotation(descriptor, visible);
+ if (descriptor.equals(toJavaSpecifier(mParams.annotation))) {
+ if (mIsConstructor) {
+ // TODO: Support constructor tracing. At the moment, constructors aren't supported
+ // because you can't put an exception handler around a super() call within the
+ // constructor itself.
+ throw new IllegalStateException("Cannot trace constructors");
+ }
+ av = new TracingAnnotationVisitor(av);
+ }
+ return av;
+ }
+
+ /**
+ * An AnnotationVisitor that pulls the trace ID and label information from the configured
+ * annotation.
+ */
+ class TracingAnnotationVisitor extends AnnotationVisitor {
+
+ TracingAnnotationVisitor(AnnotationVisitor annotationVisitor) {
+ super(Opcodes.ASM7, annotationVisitor);
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ if ("tag".equals(name)) {
+ mTraceId = (long) value;
+ // If we have a trace annotation and ID, then we have everything we need to trace
+ mShouldTrace = true;
+ } else if ("label".equals(name)) {
+ mTraceLabel = (String) value;
+ }
+ super.visit(name, value);
+ }
+ }
+
+ private static String toJavaSpecifier(String klass) {
+ return "L" + klass + ";";
+ }
+
+ private static boolean isEmpty(String str) {
+ return str == null || "".equals(str);
+ }
+}
diff --git a/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
new file mode 100644
index 0000000..81bf235
--- /dev/null
+++ b/tools/traceinjection/test/com/android/traceinjection/InjectionTests.java
@@ -0,0 +1,246 @@
+/*
+ * 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.traceinjection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class InjectionTests {
+ public static final int TRACE_TAG = 42;
+ public static final String CUSTOM_TRACE_NAME = "Custom";
+
+ public static final TraceTracker TRACKER = new TraceTracker();
+
+ @After
+ public void tearDown() {
+ TRACKER.reset();
+ }
+
+ @Test
+ public void testDefaultLabel() {
+ assertTraces(this::tracedMethod, "tracedMethod");
+ tracedMethodThrowsAndCatches();
+ }
+
+ @Test
+ public void testCustomLabel() {
+ assertTraces(this::tracedMethodHasCustomName, CUSTOM_TRACE_NAME);
+ }
+
+ @Test
+ public void testTracedMethodsStillThrow() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class, this::tracedMethodThrows),
+ "tracedMethodThrows");
+ // Also test that we rethrow exceptions from method calls. This is slightly different from
+ // the previous case because the ATHROW instruction is not actually present at all in the
+ // bytecode of the instrumented method.
+ TRACKER.reset();
+ assertTraces(() -> assertThrows(NullPointerException.class,
+ this::tracedMethodCallsThrowingMethod),
+ "tracedMethodCallsThrowingMethod");
+ }
+
+ @Test
+ public void testNestedTracedMethods() {
+ assertTraces(this::outerTracedMethod, "outerTracedMethod", "innerTracedMethod");
+ }
+
+ @Test
+ public void testTracedMethodWithCatchBlock() {
+ assertTraces(this::tracedMethodThrowsAndCatches, "tracedMethodThrowsAndCatches");
+ }
+
+ @Test
+ public void testTracedMethodWithFinallyBlock() {
+ assertTraces(() -> assertThrows(IllegalArgumentException.class,
+ this::tracedMethodThrowWithFinally), "tracedMethodThrowWithFinally");
+ }
+
+ @Test
+ public void testNonVoidMethod() {
+ assertTraces(this::tracedNonVoidMethod, "tracedNonVoidMethod");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinCatches() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinCatches,
+ "tracedNonVoidMethodReturnsWithinCatches");
+ }
+
+ @Test
+ public void testNonVoidMethodReturnsWithinFinally() {
+ assertTraces(this::tracedNonVoidMethodReturnsWithinFinally,
+ "tracedNonVoidMethodReturnsWithinFinally");
+ }
+
+ @Test
+ public void testTracedStaticMethod() {
+ assertTraces(InjectionTests::tracedStaticMethod, "tracedStaticMethod");
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrows() {
+ throw new IllegalArgumentException();
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodCallsThrowingMethod() {
+ throwingMethod();
+ }
+
+ private void throwingMethod() {
+ throw new NullPointerException();
+ }
+
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowsAndCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void tracedMethodThrowWithFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+ }
+
+ @Trace(tag = TRACE_TAG, label = CUSTOM_TRACE_NAME)
+ public void tracedMethodHasCustomName() {
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void outerTracedMethod() {
+ innerTracedMethod();
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public void innerTracedMethod() {
+ assertEquals(2, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinCatches() {
+ try {
+ throw new IllegalArgumentException();
+ } catch (IllegalArgumentException ignored) {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public int tracedNonVoidMethodReturnsWithinFinally() {
+ try {
+ throw new IllegalArgumentException();
+ } finally {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ return 0;
+ }
+ }
+
+ @Trace(tag = TRACE_TAG)
+ public static void tracedStaticMethod() {
+ assertEquals(1, TRACKER.getTraceCount(TRACE_TAG));
+ }
+
+ public void assertTraces(Runnable r, String... traceLabels) {
+ r.run();
+ assertEquals(Arrays.asList(traceLabels), TRACKER.getTraceLabels(TRACE_TAG));
+ TRACKER.assertAllTracesClosed();
+ }
+
+ public static void traceStart(long tag, String name) {
+ TRACKER.onTraceStart(tag, name);
+ }
+
+ public static void traceEnd(long tag) {
+ TRACKER.onTraceEnd(tag);
+ }
+
+ static class TraceTracker {
+ private final Map<Long, List<String>> mTraceLabelsByTag = new HashMap<>();
+ private final Map<Long, Integer> mTraceCountsByTag = new HashMap<>();
+
+ public void onTraceStart(long tag, String name) {
+ getTraceLabels(tag).add(name);
+ mTraceCountsByTag.put(tag, mTraceCountsByTag.getOrDefault(tag, 0) + 1);
+ }
+
+ public void onTraceEnd(long tag) {
+ final int newCount = getTraceCount(tag) - 1;
+ if (newCount < 0) {
+ throw new IllegalStateException("Trace count has gone negative for tag " + tag);
+ }
+ mTraceCountsByTag.put(tag, newCount);
+ }
+
+ public void reset() {
+ mTraceLabelsByTag.clear();
+ mTraceCountsByTag.clear();
+ }
+
+ public List<String> getTraceLabels(long tag) {
+ if (!mTraceLabelsByTag.containsKey(tag)) {
+ mTraceLabelsByTag.put(tag, new ArrayList<>());
+ }
+ return mTraceLabelsByTag.get(tag);
+ }
+
+ public int getTraceCount(long tag) {
+ return mTraceCountsByTag.getOrDefault(tag, 0);
+ }
+
+ public void assertAllTracesClosed() {
+ for (Map.Entry<Long, Integer> count: mTraceCountsByTag.entrySet()) {
+ final String errorMsg = "Tag " + count.getKey() + " is not fully closed (count="
+ + count.getValue() + ")";
+ assertEquals(errorMsg, 0, (int) count.getValue());
+ }
+ }
+ }
+}
diff --git a/tools/traceinjection/test/com/android/traceinjection/Trace.java b/tools/traceinjection/test/com/android/traceinjection/Trace.java
new file mode 100644
index 0000000..9e1c545
--- /dev/null
+++ b/tools/traceinjection/test/com/android/traceinjection/Trace.java
@@ -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.
+ */
+
+package com.android.traceinjection;
+
+public @interface Trace {
+ long tag();
+ String label() default "";
+}
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 0423b7a..ff24d16 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -32,7 +32,7 @@
"libui-types",
],
target: {
- linux_glibc: {
+ host_linux: {
static_libs: [
// libbinder is only available for linux
"libbinder",