Merge "Update permissions for ServiceState broadcast"
diff --git a/Android.bp b/Android.bp
index ee5db70..1c4f10e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,7 +110,7 @@
// AIDL sources from external directories
":android.hardware.graphics.common-V3-java-source",
- ":android.hardware.security.keymint-V1-java-source",
+ ":android.hardware.security.keymint-V2-java-source",
":android.hardware.security.secureclock-V1-java-source",
":android.hardware.tv.tuner-V1-java-source",
":android.security.apc-java-source",
diff --git a/Android.mk b/Android.mk
index 46529eb..d9e202c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,6 +15,14 @@
#
LOCAL_PATH := $(call my-dir)
+$(eval $(call declare-1p-copy-files,frameworks/base,.ogg))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kl))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kcm))
+$(eval $(call declare-1p-copy-files,frameworks/base,.idc))
+$(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects))
+$(eval $(call declare-1p-copy-files,frameworks/base/config,))
+$(eval $(call declare-1p-copy-files,frameworks/native/data,))
+
# Load framework-specific path mappings used later in the build.
include $(LOCAL_PATH)/pathmap.mk
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 a5c2bcc..90ec700 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -149,6 +149,8 @@
import com.android.server.usage.AppStandbyInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
+import dalvik.annotation.optimization.NeverCompile;
+
import libcore.util.EmptyArray;
import java.io.FileDescriptor;
@@ -2869,6 +2871,7 @@
packageName, UserHandle.of(userId));
}
+ @NeverCompile // Avoid size overhead of debugging code.
void dumpImpl(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.println("Current Alarm Manager state:");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index bdfdd55..4e73b02 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -127,6 +127,8 @@
import com.android.server.utils.quota.Category;
import com.android.server.utils.quota.CountQuotaTracker;
+import dalvik.annotation.optimization.NeverCompile;
+
import libcore.util.EmptyArray;
import java.io.FileDescriptor;
@@ -3821,6 +3823,7 @@
});
}
+ @NeverCompile // Avoid size overhead of debugging code.
void dumpInternal(final IndentingPrintWriter pw, int filterUid) {
final int filterAppId = UserHandle.getAppId(filterUid);
final long now = sSystemClock.millis();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index 649aa39..efcf14f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -56,6 +56,8 @@
import com.android.server.job.JobStatusDumpProto;
import com.android.server.job.JobStatusShortInfoProto;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1971,6 +1973,7 @@
}
// Dumpsys infrastructure
+ @NeverCompile // Avoid size overhead of debugging code.
public void dump(IndentingPrintWriter pw, boolean full, long nowElapsed) {
UserHandle.formatUid(pw, callingUid);
pw.print(" tag="); pw.println(tag);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index b96055f..48f8581 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -76,6 +76,8 @@
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
import com.android.server.utils.AlarmQueue;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -4358,6 +4360,7 @@
//////////////////////////// DATA DUMP //////////////////////////////
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
public void dumpControllerStateLocked(final IndentingPrintWriter pw,
final Predicate<JobStatus> predicate) {
diff --git a/apex/media/Android.bp b/apex/media/Android.bp
index 1a710a98b..96e88dd 100644
--- a/apex/media/Android.bp
+++ b/apex/media/Android.bp
@@ -18,11 +18,7 @@
"//frameworks/av/apex/testing",
],
// 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"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
sdk {
diff --git a/apex/media/aidl/Android.bp b/apex/media/aidl/Android.bp
index 545a0cd..4ba0d9b 100644
--- a/apex/media/aidl/Android.bp
+++ b/apex/media/aidl/Android.bp
@@ -16,11 +16,7 @@
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"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
filegroup {
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 2c2af28..e38488d 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -14,11 +14,7 @@
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"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
java_library {
@@ -68,6 +64,7 @@
"//frameworks/av/apex:__subpackages__",
"//frameworks/base/apex/media/service",
"//frameworks/base/api", // For framework-all
+ "//packages/modules/Media/apex/service",
],
}
diff --git a/apex/media/service/Android.bp b/apex/media/service/Android.bp
index 834e5cb..0e300bb 100644
--- a/apex/media/service/Android.bp
+++ b/apex/media/service/Android.bp
@@ -13,11 +13,7 @@
// limitations under the License.
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"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
filegroup {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 1c82597..e1b7829 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -134,19 +134,19 @@
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
- R::overlay::integer::int1)),
+ R::overlay::integer::int1)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
- R::overlay::string::str1)),
+ R::overlay::string::str1)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
- R::overlay::string::str3)),
+ R::overlay::string::str3)),
std::string::npos)
<< result->stdout_str;
ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
- R::overlay::string::str4)),
+ R::overlay::string::str4)),
std::string::npos)
<< result->stdout_str;
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d1e280..bf49838 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -631,6 +631,7 @@
field public static final int elevation = 16843840; // 0x1010440
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
+ field public static final int enableOnBackInvokedCallback;
field public static final int enableVrMode = 16844069; // 0x1010525
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
@@ -1452,6 +1453,7 @@
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsBatteryGameMode;
field public static final int supportsInlineSuggestions = 16844301; // 0x101060d
+ field public static final int supportsInlineSuggestionsWithTouchExploration;
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsMultipleDisplays = 16844182; // 0x1010596
@@ -4274,6 +4276,7 @@
method public void setLocusContext(@Nullable android.content.LocusId, @Nullable android.os.Bundle);
method public final void setMediaController(android.media.session.MediaController);
method public void setPictureInPictureParams(@NonNull android.app.PictureInPictureParams);
+ method public void setPreferDockBigOverlays(boolean);
method @Deprecated public final void setProgress(int);
method @Deprecated public final void setProgressBarIndeterminate(boolean);
method @Deprecated public final void setProgressBarIndeterminateVisibility(boolean);
@@ -6636,9 +6639,12 @@
method public android.app.PictureInPictureParams.Builder setActions(java.util.List<android.app.RemoteAction>);
method public android.app.PictureInPictureParams.Builder setAspectRatio(android.util.Rational);
method @NonNull public android.app.PictureInPictureParams.Builder setAutoEnterEnabled(boolean);
+ method @NonNull public android.app.PictureInPictureParams.Builder setCloseAction(@Nullable android.app.RemoteAction);
method @NonNull public android.app.PictureInPictureParams.Builder setExpandedAspectRatio(@Nullable android.util.Rational);
method @NonNull public android.app.PictureInPictureParams.Builder setSeamlessResizeEnabled(boolean);
method public android.app.PictureInPictureParams.Builder setSourceRectHint(android.graphics.Rect);
+ method @NonNull public android.app.PictureInPictureParams.Builder setSubtitle(@Nullable CharSequence);
+ method @NonNull public android.app.PictureInPictureParams.Builder setTitle(@Nullable CharSequence);
}
public final class PictureInPictureUiState implements android.os.Parcelable {
@@ -16445,6 +16451,7 @@
public class MeasuredText {
method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
method @FloatRange(from=0.0f) @Px public float getCharWidthAt(@IntRange(from=0) int);
+ method public void getFontMetricsInt(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Paint.FontMetricsInt);
method @FloatRange(from=0.0) @Px public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
}
@@ -39604,7 +39611,7 @@
public class SpeechRecognizer {
method @MainThread public void cancel();
- method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionSupportCallback);
+ method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.RecognitionSupportCallback);
method @MainThread @NonNull public static android.speech.SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context);
method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context, android.content.ComponentName);
@@ -45007,6 +45014,7 @@
method public char charAt(int);
method public static android.text.PrecomputedText create(@NonNull CharSequence, @NonNull android.text.PrecomputedText.Params);
method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
+ method public void getFontMetricsInt(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Paint.FontMetricsInt);
method @IntRange(from=0) public int getParagraphCount();
method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
@@ -47676,15 +47684,11 @@
public final class Choreographer {
method public static android.view.Choreographer getInstance();
- method public void postExtendedFrameCallback(@NonNull android.view.Choreographer.ExtendedFrameCallback);
method public void postFrameCallback(android.view.Choreographer.FrameCallback);
method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
- method public void removeExtendedFrameCallback(@Nullable android.view.Choreographer.ExtendedFrameCallback);
+ method public void postVsyncCallback(@NonNull android.view.Choreographer.VsyncCallback);
method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
- }
-
- public static interface Choreographer.ExtendedFrameCallback {
- method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ method public void removeVsyncCallback(@Nullable android.view.Choreographer.VsyncCallback);
}
public static interface Choreographer.FrameCallback {
@@ -47699,10 +47703,14 @@
public static class Choreographer.FrameTimeline {
method public long getDeadlineNanos();
- method public long getExpectedPresentTimeNanos();
+ method public long getExpectedPresentationTimeNanos();
method public long getVsyncId();
}
+ public static interface Choreographer.VsyncCallback {
+ method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ }
+
public interface CollapsibleActionView {
method public void onActionViewCollapsed();
method public void onActionViewExpanded();
@@ -49254,6 +49262,7 @@
method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
+ method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b1f0b54..5d76b08 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1656,8 +1656,8 @@
method @NonNull public android.os.Bundle getSearchConstraints();
method @NonNull public String getSource();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
- field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
+ field public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
+ field public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchRequest> CREATOR;
}
@@ -1699,23 +1699,23 @@
method @NonNull public String getTitle();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.cloudsearch.SearchResult> CREATOR;
- field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE";
- field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "ACTION_BUTTON_TEXT";
- field public static final String EXTRAINFO_APP_BADGES = "APP_BADGES";
- field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "APP_CONTAINS_ADS_DISCLAIMER";
- field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "APP_CONTAINS_IAP_DISCLAIMER";
- field public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME";
- field public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL";
- field public static final String EXTRAINFO_APP_IARC = "APP_IARC";
- field public static final String EXTRAINFO_APP_ICON = "APP_ICON";
- field public static final String EXTRAINFO_APP_REVIEW_COUNT = "APP_REVIEW_COUNT";
- field public static final String EXTRAINFO_APP_SIZE_BYTES = "APP_SIZE_BYTES";
- field public static final String EXTRAINFO_APP_STAR_RATING = "APP_STAR_RATING";
- field public static final String EXTRAINFO_LONG_DESCRIPTION = "LONG_DESCRIPTION";
- field public static final String EXTRAINFO_SCREENSHOTS = "SCREENSHOTS";
- field public static final String EXTRAINFO_SHORT_DESCRIPTION = "SHORT_DESCRIPTION";
- field public static final String EXTRAINFO_WEB_ICON = "WEB_ICON";
- field public static final String EXTRAINFO_WEB_URL = "WEB_URL";
+ field public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
+ field public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "android.app.cloudsearch.ACTION_BUTTON_TEXT";
+ field public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
+ field public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
+ field public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER = "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
+ field public static final String EXTRAINFO_APP_DEVELOPER_NAME = "android.app.cloudsearch.APP_DEVELOPER_NAME";
+ field public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
+ field public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
+ field public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
+ field public static final String EXTRAINFO_APP_REVIEW_COUNT = "android.app.cloudsearch.APP_REVIEW_COUNT";
+ field public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
+ field public static final String EXTRAINFO_APP_STAR_RATING = "android.app.cloudsearch.APP_STAR_RATING";
+ field public static final String EXTRAINFO_LONG_DESCRIPTION = "android.app.cloudsearch.LONG_DESCRIPTION";
+ field public static final String EXTRAINFO_SCREENSHOTS = "android.app.cloudsearch.SCREENSHOTS";
+ field public static final String EXTRAINFO_SHORT_DESCRIPTION = "android.app.cloudsearch.SHORT_DESCRIPTION";
+ field public static final String EXTRAINFO_WEB_ICON = "android.app.cloudsearch.WEB_ICON";
+ field public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
}
public static final class SearchResult.Builder {
@@ -2507,9 +2507,10 @@
package android.app.usage {
public final class BroadcastResponseStats implements android.os.Parcelable {
- ctor public BroadcastResponseStats(@NonNull String);
+ ctor public BroadcastResponseStats(@NonNull String, @IntRange(from=1) long);
method public int describeContents();
method @IntRange(from=0) public int getBroadcastsDispatchedCount();
+ method @IntRange(from=1) public long getId();
method @IntRange(from=0) public int getNotificationsCancelledCount();
method @IntRange(from=0) public int getNotificationsPostedCount();
method @IntRange(from=0) public int getNotificationsUpdatedCount();
@@ -2566,13 +2567,13 @@
}
public final class UsageStatsManager {
- method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void clearBroadcastResponseStats(@NonNull String, @IntRange(from=1) long);
+ method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void clearBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
method @RequiresPermission(allOf={android.Manifest.permission.INTERACT_ACROSS_USERS, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long getLastTimeAnyComponentUsed(@NonNull String);
method public int getUsageSource();
method @RequiresPermission(android.Manifest.permission.BIND_CARRIER_SERVICES) public void onCarrierPrivilegedAppsChanged();
- method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public android.app.usage.BroadcastResponseStats queryBroadcastResponseStats(@NonNull String, @IntRange(from=1) long);
+ method @NonNull @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.List<android.app.usage.BroadcastResponseStats> queryBroadcastResponseStats(@Nullable String, @IntRange(from=0) long);
method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
@@ -5318,9 +5319,9 @@
method public int getCurrentDataRole();
method public int getCurrentMode();
method public int getCurrentPowerRole();
- method public int getPowerBrickStatus();
+ method public int getPowerBrickConnectionStatus();
method public int getSupportedRoleCombinations();
- method @Nullable public int[] getUsbDataStatus();
+ method public int getUsbDataStatus();
method public boolean isConnected();
method public boolean isPowerTransferLimited();
method public boolean isRoleCombinationSupported(int, int);
@@ -5329,6 +5330,13 @@
field public static final int DATA_ROLE_DEVICE = 2; // 0x2
field public static final int DATA_ROLE_HOST = 1; // 0x1
field public static final int DATA_ROLE_NONE = 0; // 0x0
+ field public static final int DATA_STATUS_DISABLED_CONTAMINANT = 4; // 0x4
+ field public static final int DATA_STATUS_DISABLED_DEBUG = 32; // 0x20
+ field public static final int DATA_STATUS_DISABLED_DOCK = 8; // 0x8
+ field public static final int DATA_STATUS_DISABLED_FORCE = 16; // 0x10
+ field public static final int DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
+ field public static final int DATA_STATUS_ENABLED = 1; // 0x1
+ field public static final int DATA_STATUS_UNKNOWN = 0; // 0x0
field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4
field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8
field public static final int MODE_DFP = 2; // 0x2
@@ -5340,13 +5348,6 @@
field public static final int POWER_ROLE_NONE = 0; // 0x0
field public static final int POWER_ROLE_SINK = 2; // 0x2
field public static final int POWER_ROLE_SOURCE = 1; // 0x1
- field public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3; // 0x3
- field public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6; // 0x6
- field public static final int USB_DATA_STATUS_DISABLED_DOCK = 4; // 0x4
- field public static final int USB_DATA_STATUS_DISABLED_FORCE = 5; // 0x5
- field public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
- field public static final int USB_DATA_STATUS_ENABLED = 1; // 0x1
- field public static final int USB_DATA_STATUS_UNKNOWN = 0; // 0x0
}
}
@@ -6075,7 +6076,7 @@
method public boolean isAudioServerRunning();
method public boolean isHdmiSystemAudioSupported();
method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable();
- method public static boolean isUltrasoundSupported();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND) public boolean isUltrasoundSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void muteAwaitConnection(@NonNull int[], @NonNull android.media.AudioDeviceAttributes, long, @NonNull java.util.concurrent.TimeUnit) throws java.lang.IllegalStateException;
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void registerMuteAwaitConnectionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.MuteAwaitConnectionCallback);
@@ -15621,7 +15622,7 @@
public interface WindowManager extends android.view.ViewManager {
method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
- method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull android.window.TaskFpsCallback);
+ method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback);
method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
}
@@ -16213,12 +16214,9 @@
package android.window {
- public final class TaskFpsCallback {
- ctor public TaskFpsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback.OnFpsCallbackListener);
- }
-
- public static interface TaskFpsCallback.OnFpsCallbackListener {
- method public void onFpsReported(float);
+ public abstract class TaskFpsCallback {
+ ctor public TaskFpsCallback();
+ method public abstract void onFpsReported(float);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 5c5321c..e5165449 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -107,6 +107,8 @@
method public final boolean addDumpable(@NonNull android.util.Dumpable);
method public void dumpInternal(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
method public void onMovedToDisplay(int, android.content.res.Configuration);
+ field public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+ field public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
}
public class ActivityManager {
@@ -270,9 +272,12 @@
}
public class DreamManager {
+ method public boolean areDreamsSupported();
method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isDreaming();
+ method public boolean isScreensaverEnabled();
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setActiveDream(@Nullable android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setDreamOverlay(@Nullable android.content.ComponentName);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setScreensaverEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
}
@@ -352,8 +357,11 @@
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();
}
@@ -411,6 +419,7 @@
method @NonNull public android.content.res.Configuration getConfiguration();
method public int getParentTaskId();
method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams();
+ method public boolean getPreferDockBigOverlays();
method @NonNull public android.window.WindowContainerToken getToken();
method public boolean hasParentTask();
}
@@ -2982,6 +2991,7 @@
field public static final String DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE = "max_buffer_size";
field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
field public static final String DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY = "text_change_flush_frequency";
+ field public static final String DUMPABLE_NAME = "ContentCaptureManager";
field public static final int LOGGING_LEVEL_DEBUG = 1; // 0x1
field public static final int LOGGING_LEVEL_OFF = 0; // 0x0
field public static final int LOGGING_LEVEL_VERBOSE = 2; // 0x2
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index eaf79b4..11663a5 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -814,6 +814,13 @@
Dialog mDialog;
Bundle mArgs;
}
+
+ /** @hide */ public static final String DUMP_ARG_AUTOFILL = "--autofill";
+ /** @hide */ public static final String DUMP_ARG_CONTENT_CAPTURE = "--contentcapture";
+ /** @hide */ public static final String DUMP_ARG_TRANSLATION = "--translation";
+ /** @hide */ @TestApi public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
+ /** @hide */ @TestApi public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+
private SparseArray<ManagedDialog> mManagedDialogs;
// set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
@@ -1649,7 +1656,10 @@
}
mRestoredFromBundle = savedInstanceState != null;
mCalled = true;
- if (!WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+
+ boolean aheadOfTimeBack = WindowOnBackInvokedDispatcher
+ .isOnBackInvokedCallbackEnabled(this);
+ if (aheadOfTimeBack) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = new OnBackInvokedCallback() {
@Override
@@ -2955,6 +2965,27 @@
return false;
}
+ /**
+ * Specifies a preference to dock big overlays like the expanded picture-in-picture on TV
+ * (see {@link PictureInPictureParams.Builder#setExpandedAspectRatio}). Docking puts the
+ * big overlay side-by-side next to this activity, so that both windows are fully visible to
+ * the user.
+ *
+ * <p> If unspecified, whether the overlay window will be docked or not, will be defined
+ * by the system.
+ *
+ * <p> If specified, the system will try to respect the preference, but it may be
+ * overridden by a user preference.
+ *
+ * @param preferDockBigOverlays indicates that the activity prefers big overlays to be
+ * docked next to it instead of overlaying its content
+ *
+ * @see PictureInPictureParams.Builder#setExpandedAspectRatio
+ */
+ public void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
+ ActivityClient.getInstance().setPreferDockBigOverlays(mToken, preferDockBigOverlays);
+ }
+
void dispatchMovedToDisplay(int displayId, Configuration config) {
updateDisplay(displayId);
onMovedToDisplay(displayId, config);
@@ -7367,25 +7398,30 @@
boolean isSpecialCase = true;
// Handle special cases
switch (arg) {
- case "--autofill":
- dumpAutofillManager(prefix, writer, args);
- break;
- case "--contentcapture":
- dumpContentCaptureManager(prefix, writer);
- break;
- case "--translation":
- dumpUiTranslation(prefix, writer);
- break;
- case "--list-dumpables":
+ case DUMP_ARG_AUTOFILL:
+ dumpLegacyDumpable(prefix, writer, arg,
+ AutofillClientController.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_CONTENT_CAPTURE:
+ dumpLegacyDumpable(prefix, writer, arg,
+ ContentCaptureManager.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_TRANSLATION:
+ dumpLegacyDumpable(prefix, writer, arg,
+ UiTranslationController.DUMPABLE_NAME);
+ return;
+ case DUMP_ARG_LIST_DUMPABLES:
if (mDumpableContainer == null) {
writer.print(prefix); writer.println("No dumpables");
} else {
mDumpableContainer.listDumpables(prefix, writer);
}
- break;
- case "--dump-dumpable":
+ mDumpableContainer.listDumpables(prefix, writer);
+ return;
+ case DUMP_ARG_DUMP_DUMPABLE:
if (args.length == 1) {
- writer.println("--dump-dumpable requires the dumpable name");
+ writer.print(DUMP_ARG_DUMP_DUMPABLE);
+ writer.println(" requires the dumpable name");
} else if (mDumpableContainer == null) {
writer.println("no dumpables");
} else {
@@ -7452,25 +7488,10 @@
}
}
- private void dumpContentCaptureManager(String prefix, PrintWriter writer) {
- dumpLegacyDumpable(prefix, writer, ContentCaptureManager.DUMPABLE_NAME, /* args= */ null);
- }
-
- private void dumpUiTranslation(String prefix, PrintWriter writer) {
- dumpLegacyDumpable(prefix, writer, UiTranslationController.DUMPABLE_NAME, /* args= */ null);
- }
-
- private void dumpAutofillManager(String prefix, PrintWriter writer, String[] args) {
- dumpLegacyDumpable(prefix, writer, AutofillClientController.DUMPABLE_NAME, args);
- }
-
- private void dumpLegacyDumpable(@NonNull String prefix, @NonNull PrintWriter writer,
- @NonNull String dumpableName, @Nullable String[] args) {
- if (mDumpableContainer == null) {
- writer.print(prefix); writer.print("no "); writer.println(dumpableName);
- return;
- }
- mDumpableContainer.dumpOneDumpable(prefix, writer, dumpableName, args);
+ private void dumpLegacyDumpable(String prefix, PrintWriter writer, String legacyOption,
+ String dumpableName) {
+ writer.printf("%s%s option deprecated. Use %s %s instead\n", prefix, legacyOption,
+ DUMP_ARG_DUMP_DUMPABLE, dumpableName);
}
/**
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 4715e0f..cf8480c 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -324,6 +324,14 @@
}
}
+ void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ try {
+ getActivityClientController().setPreferDockBigOverlays(token, preferDockBigOverlays);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
void toggleFreeformWindowingMode(IBinder token) {
try {
getActivityClientController().toggleFreeformWindowingMode(token);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d29d3d4..9fe8e79 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -831,4 +831,9 @@
* Restart android.
*/
public abstract void restart();
+
+ /**
+ * Returns some summary statistics of the current PendingIntent queue - sizes and counts.
+ */
+ public abstract List<PendingIntentStats> getPendingIntentStats();
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index aa6c184..569fda9 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -456,7 +456,8 @@
*/
protected void onStart() {
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
- if (mContext != null && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ if (mContext != null
+ && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Add onBackPressed as default back behavior.
mDefaultBackCallback = new OnBackInvokedCallback() {
@Override
@@ -703,7 +704,7 @@
if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
&& event.isTracking()
&& !event.isCanceled()
- && WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ && !WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
onBackPressed();
return true;
}
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index 34ae08fd..00af1c02 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -26,6 +28,8 @@
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@@ -48,6 +52,40 @@
}
/**
+ * Returns whether Settings.Secure.SCREENSAVER_ENABLED is enabled.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean isScreensaverEnabled() {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ /**
+ * Sets whether Settings.Secure.SCREENSAVER_ENABLED is enabled.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(WRITE_SECURE_SETTINGS)
+ public void setScreensaverEnabled(boolean enabled) {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_ENABLED, enabled ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ /**
+ * Returns whether dreams are supported.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean areDreamsSupported() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_dreamsSupported);
+ }
+
+ /**
* Starts dream service with name "name".
*
* <p>This is only used for testing the dream service APIs.
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index f9439cb..caf1c41b7 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -88,6 +88,7 @@
boolean enterPictureInPictureMode(in IBinder token, in PictureInPictureParams params);
void setPictureInPictureParams(in IBinder token, in PictureInPictureParams params);
+ oneway void setPreferDockBigOverlays(in IBinder token, in boolean preferDockBigOverlays);
void toggleFreeformWindowingMode(in IBinder token);
oneway void startLockTaskModeByToken(in IBinder token);
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 55afed2..2242224b 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -73,6 +73,7 @@
* @param nightModeCustomType
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
void setNightModeCustomType(int nightModeCustomType);
/**
@@ -82,6 +83,7 @@
* {@link #MODE_NIGHT_CUSTOM_TYPE_UNKNOWN}.
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
int getNightModeCustomType();
/**
@@ -113,6 +115,7 @@
* {@code nightModeCustomType}.
* @hide
*/
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
boolean setNightModeActivatedForCustomMode(int nightModeCustom, boolean active);
/**
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/app/PendingIntentStats.java
similarity index 63%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to core/java/android/app/PendingIntentStats.java
index 3091df3..111db3c 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/app/PendingIntentStats.java
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package android.window;
+package android.app;
/**
+ * Data about pending intents - size and count, per UID that sent the intent.
* @hide
*/
-oneway interface IOnFpsCallbackListener {
+public class PendingIntentStats {
+ public final int uid;
+ public final int count;
+ public final int sizeKb;
- /**
- * Reports the fps from the registered task
- * @param fps The frame rate per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(in float fps);
+ public PendingIntentStats(int uid, int count, int sizeKb) {
+ this.uid = uid;
+ this.count = count;
+ this.sizeKb = sizeKb;
+ }
}
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 18343fd..5ecddfd 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -51,19 +51,25 @@
private List<RemoteAction> mUserActions;
@Nullable
+ private RemoteAction mCloseAction;
+
+ @Nullable
private Rect mSourceRectHint;
private Boolean mAutoEnterEnabled;
private Boolean mSeamlessResizeEnabled;
+ private CharSequence mTitle;
+
+ private CharSequence mSubtitle;
+
/**
* Sets the aspect ratio. This aspect ratio is defined as the desired width / height, and
* does not change upon device rotation.
*
* @param aspectRatio the new aspect ratio for the activity in picture-in-picture, must be
- * between 2.39:1 and 1:2.39 (inclusive).
- *
+ * between 2.39:1 and 1:2.39 (inclusive).
* @return this builder instance.
*/
public Builder setAspectRatio(Rational aspectRatio) {
@@ -111,6 +117,25 @@
}
/**
+ * Sets a close action that should be invoked before the default close PiP action. The
+ * custom action must close the activity quickly using {@link Activity#finish()}.
+ * Otherwise, the system will forcibly close the PiP as if no custom close action was
+ * provided.
+ *
+ * If the action matches one set via {@link PictureInPictureParams.Builder#setActions(List)}
+ * it may be shown in place of that custom action in the menu.
+ *
+ * @param action to replace the system close action
+ * @return this builder instance.
+ * @see RemoteAction
+ */
+ @NonNull
+ public Builder setCloseAction(@Nullable RemoteAction action) {
+ mCloseAction = action;
+ return this;
+ }
+
+ /**
* Sets the source bounds hint. These bounds are only used when an activity first enters
* picture-in-picture, and describe the bounds in window coordinates of activity entering
* picture-in-picture that will be visible following the transition. For the best effect,
@@ -168,6 +193,36 @@
}
/**
+ * Sets a title for the picture-in-picture window, which may be displayed by the system to
+ * give the user information about what this PIP is generally being used for.
+ *
+ * @param title General information about the PIP content
+ * @return this builder instance.
+ */
+ @NonNull
+ public Builder setTitle(@Nullable CharSequence title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets a subtitle for the picture-in-picture window, which may be displayed by the system
+ * to give the user more detailed information about what this PIP is displaying.<br/>
+ *
+ * Setting a title via {@link PictureInPictureParams.Builder#setTitle(CharSequence)} should
+ * be prioritized.
+ *
+ * @param subtitle Details about the PIP content.
+ * @return this builder instance
+ */
+ @NonNull
+ public Builder setSubtitle(@Nullable CharSequence subtitle) {
+ mSubtitle = subtitle;
+ return this;
+ }
+
+
+ /**
* @return an immutable {@link PictureInPictureParams} to be used when entering or updating
* the activity in picture-in-picture.
*
@@ -176,8 +231,8 @@
*/
public PictureInPictureParams build() {
PictureInPictureParams params = new PictureInPictureParams(mAspectRatio,
- mExpandedAspectRatio, mUserActions,
- mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled);
+ mExpandedAspectRatio, mUserActions, mCloseAction, mSourceRectHint,
+ mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle);
return params;
}
}
@@ -201,6 +256,12 @@
private List<RemoteAction> mUserActions;
/**
+ * Action to replace the system close action.
+ */
+ @Nullable
+ private RemoteAction mCloseAction;
+
+ /**
* The source bounds hint used when entering picture-in-picture, relative to the window bounds.
* We can use this internally for the transition into picture-in-picture to ensure that a
* particular source rect is visible throughout the whole transition.
@@ -221,6 +282,18 @@
*/
private Boolean mSeamlessResizeEnabled;
+ /**
+ * Title of the picture-in-picture window to be displayed to the user.
+ */
+ @Nullable
+ private CharSequence mTitle;
+
+ /**
+ * Subtitle for the picture-in-picture window to be displayed to the user.
+ */
+ @Nullable
+ private CharSequence mSubtitle;
+
/** {@hide} */
PictureInPictureParams() {
}
@@ -233,6 +306,7 @@
mUserActions = new ArrayList<>();
in.readTypedList(mUserActions, RemoteAction.CREATOR);
}
+ mCloseAction = in.readTypedObject(RemoteAction.CREATOR);
if (in.readInt() != 0) {
mSourceRectHint = Rect.CREATOR.createFromParcel(in);
}
@@ -242,18 +316,28 @@
if (in.readInt() != 0) {
mSeamlessResizeEnabled = in.readBoolean();
}
+ if (in.readInt() != 0) {
+ mTitle = in.readCharSequence();
+ }
+ if (in.readInt() != 0) {
+ mSubtitle = in.readCharSequence();
+ }
}
/** {@hide} */
PictureInPictureParams(Rational aspectRatio, Rational expandedAspectRatio,
- List<RemoteAction> actions, Rect sourceRectHint, Boolean autoEnterEnabled,
- Boolean seamlessResizeEnabled) {
+ List<RemoteAction> actions, RemoteAction closeAction, Rect sourceRectHint,
+ Boolean autoEnterEnabled, Boolean seamlessResizeEnabled, CharSequence title,
+ CharSequence subtitle) {
mAspectRatio = aspectRatio;
mExpandedAspectRatio = expandedAspectRatio;
mUserActions = actions;
+ mCloseAction = closeAction;
mSourceRectHint = sourceRectHint;
mAutoEnterEnabled = autoEnterEnabled;
mSeamlessResizeEnabled = seamlessResizeEnabled;
+ mTitle = title;
+ mSubtitle = subtitle;
}
/**
@@ -261,9 +345,10 @@
* @hide
*/
public PictureInPictureParams(PictureInPictureParams other) {
- this(other.mAspectRatio, other.mExpandedAspectRatio, other.mUserActions,
+ this(other.mAspectRatio, other.mExpandedAspectRatio, other.mUserActions, other.mCloseAction,
other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null,
- other.mAutoEnterEnabled, other.mSeamlessResizeEnabled);
+ other.mAutoEnterEnabled, other.mSeamlessResizeEnabled, other.mTitle,
+ other.mSubtitle);
}
/**
@@ -281,6 +366,9 @@
if (otherArgs.hasSetActions()) {
mUserActions = otherArgs.mUserActions;
}
+ if (otherArgs.hasSetCloseAction()) {
+ mCloseAction = otherArgs.mCloseAction;
+ }
if (otherArgs.hasSourceBoundsHint()) {
mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
}
@@ -290,6 +378,12 @@
if (otherArgs.mSeamlessResizeEnabled != null) {
mSeamlessResizeEnabled = otherArgs.mSeamlessResizeEnabled;
}
+ if (otherArgs.hasSetTitle()) {
+ mTitle = otherArgs.mTitle;
+ }
+ if (otherArgs.hasSetSubtitle()) {
+ mSubtitle = otherArgs.mSubtitle;
+ }
}
/**
@@ -355,7 +449,26 @@
}
/**
+ * @return the close action.
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public RemoteAction getCloseAction() {
+ return mCloseAction;
+ }
+
+ /**
+ * @return whether the close action was set.
+ * @hide
+ */
+ public boolean hasSetCloseAction() {
+ return mCloseAction != null;
+ }
+
+ /**
* Truncates the set of actions to the given {@param size}.
+ *
* @hide
*/
public void truncateActions(int size) {
@@ -399,13 +512,50 @@
}
/**
+ * @return whether a title was set.
+ * @hide
+ */
+ public boolean hasSetTitle() {
+ return mTitle != null;
+ }
+
+ /**
+ * @return title of the pip.
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * @return whether a subtitle was set.
+ * @hide
+ */
+ public boolean hasSetSubtitle() {
+ return mSubtitle != null;
+ }
+
+ /**
+ * @return subtitle of the pip.
+ * @hide
+ */
+ @TestApi
+ @Nullable
+ public CharSequence getSubtitle() {
+ return mSubtitle;
+ }
+
+ /**
* @return True if no parameters are set
* @hide
*/
public boolean empty() {
- return !hasSourceBoundsHint() && !hasSetActions() && !hasSetAspectRatio()
- && !hasSetExpandedAspectRatio() && mAutoEnterEnabled != null
- && mSeamlessResizeEnabled != null;
+ return !hasSourceBoundsHint() && !hasSetActions() && !hasSetCloseAction()
+ && !hasSetAspectRatio() && !hasSetExpandedAspectRatio() && mAutoEnterEnabled != null
+ && mSeamlessResizeEnabled != null && !hasSetTitle()
+ && !hasSetSubtitle();
}
@Override
@@ -418,13 +568,16 @@
&& Objects.equals(mAspectRatio, that.mAspectRatio)
&& Objects.equals(mExpandedAspectRatio, that.mExpandedAspectRatio)
&& Objects.equals(mUserActions, that.mUserActions)
- && Objects.equals(mSourceRectHint, that.mSourceRectHint);
+ && Objects.equals(mCloseAction, that.mCloseAction)
+ && Objects.equals(mSourceRectHint, that.mSourceRectHint)
+ && Objects.equals(mTitle, that.mTitle)
+ && Objects.equals(mSubtitle, that.mSubtitle);
}
@Override
public int hashCode() {
- return Objects.hash(mAspectRatio, mExpandedAspectRatio, mUserActions, mSourceRectHint,
- mAutoEnterEnabled, mSeamlessResizeEnabled);
+ return Objects.hash(mAspectRatio, mExpandedAspectRatio, mUserActions, mCloseAction,
+ mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled, mTitle, mSubtitle);
}
@Override
@@ -442,6 +595,9 @@
} else {
out.writeInt(0);
}
+
+ out.writeTypedObject(mCloseAction, 0);
+
if (mSourceRectHint != null) {
out.writeInt(1);
mSourceRectHint.writeToParcel(out, 0);
@@ -460,6 +616,18 @@
} else {
out.writeInt(0);
}
+ if (mTitle != null) {
+ out.writeInt(1);
+ out.writeCharSequence(mTitle);
+ } else {
+ out.writeInt(0);
+ }
+ if (mSubtitle != null) {
+ out.writeInt(1);
+ out.writeCharSequence(mSubtitle);
+ } else {
+ out.writeInt(0);
+ }
}
private void writeRationalToParcel(Rational rational, Parcel out) {
@@ -486,8 +654,11 @@
+ " expandedAspectRatio=" + mExpandedAspectRatio
+ " sourceRectHint=" + getSourceRectHint()
+ " hasSetActions=" + hasSetActions()
+ + " hasSetCloseAction=" + hasSetCloseAction()
+ " isAutoPipEnabled=" + isAutoEnterEnabled()
+ " isSeamlessResizeEnabled=" + isSeamlessResizeEnabled()
+ + " title=" + getTitle()
+ + " subtitle=" + getSubtitle()
+ ")";
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 3d2c03d..eca4170 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -186,6 +186,11 @@
public PictureInPictureParams pictureInPictureParams;
/**
+ * @hide
+ */
+ public boolean preferDockBigOverlays;
+
+ /**
* The {@link Rect} copied from {@link DisplayCutout#getSafeInsets()} if the cutout is not of
* (LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES, LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS),
* {@code null} otherwise.
@@ -379,6 +384,12 @@
}
/** @hide */
+ @TestApi
+ public boolean getPreferDockBigOverlays() {
+ return preferDockBigOverlays;
+ }
+
+ /** @hide */
@WindowConfiguration.WindowingMode
public int getWindowingMode() {
return configuration.windowConfiguration.getWindowingMode();
@@ -447,6 +458,7 @@
&& displayAreaFeatureId == that.displayAreaFeatureId
&& Objects.equals(positionInParent, that.positionInParent)
&& Objects.equals(pictureInPictureParams, that.pictureInPictureParams)
+ && Objects.equals(preferDockBigOverlays, that.preferDockBigOverlays)
&& Objects.equals(displayCutoutInsets, that.displayCutoutInsets)
&& getWindowingMode() == that.getWindowingMode()
&& Objects.equals(taskDescription, that.taskDescription)
@@ -503,6 +515,7 @@
token = WindowContainerToken.CREATOR.createFromParcel(source);
topActivityType = source.readInt();
pictureInPictureParams = source.readTypedObject(PictureInPictureParams.CREATOR);
+ preferDockBigOverlays = source.readBoolean();
displayCutoutInsets = source.readTypedObject(Rect.CREATOR);
topActivityInfo = source.readTypedObject(ActivityInfo.CREATOR);
isResizeable = source.readBoolean();
@@ -548,6 +561,7 @@
token.writeToParcel(dest, flags);
dest.writeInt(topActivityType);
dest.writeTypedObject(pictureInPictureParams, flags);
+ dest.writeBoolean(preferDockBigOverlays);
dest.writeTypedObject(displayCutoutInsets, flags);
dest.writeTypedObject(topActivityInfo, flags);
dest.writeBoolean(isResizeable);
@@ -587,6 +601,7 @@
+ " token=" + token
+ " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams
+ + " preferDockBigOverlays=" + preferDockBigOverlays
+ " displayCutoutSafeInsets=" + displayCutoutInsets
+ " topActivityInfo=" + topActivityInfo
+ " launchCookies=" + launchCookies
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index cfaffb1..ecab37d 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -244,7 +244,18 @@
public static final int MODE_NIGHT_YES = 2;
/**
- * Granular types for {@link MODE_NIGHT_CUSTOM_TYPE_BEDTIME}
+ * Granular types for {@link #setNightModeCustomType(int)}
+ * @hide
+ */
+ @IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
+ MODE_NIGHT_CUSTOM_TYPE_SCHEDULE,
+ MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NightModeCustomType {}
+
+ /**
+ * Granular types for {@link #getNightModeCustomType()}
* @hide
*/
@IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
@@ -253,7 +264,7 @@
MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface NightModeCustomType {}
+ public @interface NightModeCustomReturnType {}
/**
* A granular type for {@link #MODE_NIGHT_CUSTOM} which is unknown.
@@ -539,6 +550,8 @@
* {@code nightModeCustomType}.
*
* @param nightModeCustomType
+ * @throws IllegalArgumentException if passed an unsupported type to
+ * {@code nightModeCustomType}.
* @hide
*/
@SystemApi
@@ -562,7 +575,7 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
- public int getNightModeCustomType() {
+ public @NightModeCustomReturnType int getNightModeCustomType() {
if (mService != null) {
try {
return mService.getNightModeCustomType();
diff --git a/core/java/android/app/assist/OWNERS b/core/java/android/app/assist/OWNERS
index 46b5ea0..e857c72 100644
--- a/core/java/android/app/assist/OWNERS
+++ b/core/java/android/app/assist/OWNERS
@@ -1,7 +1,5 @@
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+joannechung@google.com
+markpun@google.com
+lpeter@google.com
+tymtsai@google.com
diff --git a/core/java/android/app/cloudsearch/SearchRequest.java b/core/java/android/app/cloudsearch/SearchRequest.java
index ef66c0c..4d6507a 100644
--- a/core/java/android/app/cloudsearch/SearchRequest.java
+++ b/core/java/android/app/cloudsearch/SearchRequest.java
@@ -83,11 +83,13 @@
* presubmit is the input before the user finishes the entire query, i.e. push "ENTER" or
* "SEARCH" button. After the user finishes the entire query, the behavior is postsubmit.
*/
- public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION = "IS_PRESUBMIT_SUGGESTION";
+ public static final String CONSTRAINT_IS_PRESUBMIT_SUGGESTION =
+ "android.app.cloudsearch.IS_PRESUBMIT_SUGGESTION";
/** The target search provider list of package names(separated by ;), String value expected.
* If this is not provided or its value is empty, then no filter will be applied.
*/
- public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER = "SEARCH_PROVIDER_FILTER";
+ public static final String CONSTRAINT_SEARCH_PROVIDER_FILTER =
+ "android.app.cloudsearch.SEARCH_PROVIDER_FILTER";
@NonNull
private Bundle mSearchConstraints;
diff --git a/core/java/android/app/cloudsearch/SearchResult.java b/core/java/android/app/cloudsearch/SearchResult.java
index 3403ab0..af8adac 100644
--- a/core/java/android/app/cloudsearch/SearchResult.java
+++ b/core/java/android/app/cloudsearch/SearchResult.java
@@ -75,47 +75,54 @@
EXTRAINFO_WEB_ICON})
public @interface SearchResultExtraInfoKey {}
/** This App developer website's domain URL, String value expected. */
- public static final String EXTRAINFO_APP_DOMAIN_URL = "APP_DOMAIN_URL";
+ public static final String EXTRAINFO_APP_DOMAIN_URL = "android.app.cloudsearch.APP_DOMAIN_URL";
/** This App icon, android.graphics.drawable.Icon expected. */
- public static final String EXTRAINFO_APP_ICON = "APP_ICON";
+ public static final String EXTRAINFO_APP_ICON = "android.app.cloudsearch.APP_ICON";
/** This App developer's name, String value expected. */
- public static final String EXTRAINFO_APP_DEVELOPER_NAME = "APP_DEVELOPER_NAME";
+ public static final String EXTRAINFO_APP_DEVELOPER_NAME =
+ "android.app.cloudsearch.APP_DEVELOPER_NAME";
/** This App's pkg size in bytes, Double value expected. */
- public static final String EXTRAINFO_APP_SIZE_BYTES = "APP_SIZE_BYTES";
+ public static final String EXTRAINFO_APP_SIZE_BYTES = "android.app.cloudsearch.APP_SIZE_BYTES";
/** This App developer's name, Double value expected. */
- public static final String EXTRAINFO_APP_STAR_RATING = "APP_STAR_RATING";
+ public static final String EXTRAINFO_APP_STAR_RATING =
+ "android.app.cloudsearch.APP_STAR_RATING";
/** This App's IARC rating, String value expected.
* IARC (International Age Rating Coalition) is partnered globally with major
* content rating organizations to provide a centralized and one-stop-shop for
* rating content on a global scale.
*/
- public static final String EXTRAINFO_APP_IARC = "APP_IARC";
+ public static final String EXTRAINFO_APP_IARC = "android.app.cloudsearch.APP_IARC";
/** This App's review count, Double value expected. */
- public static final String EXTRAINFO_APP_REVIEW_COUNT = "APP_REVIEW_COUNT";
+ public static final String EXTRAINFO_APP_REVIEW_COUNT =
+ "android.app.cloudsearch.APP_REVIEW_COUNT";
/** If this App contains the Ads Disclaimer, Boolean value expected. */
public static final String EXTRAINFO_APP_CONTAINS_ADS_DISCLAIMER =
- "APP_CONTAINS_ADS_DISCLAIMER";
+ "android.app.cloudsearch.APP_CONTAINS_ADS_DISCLAIMER";
/** If this App contains the IAP Disclaimer, Boolean value expected. */
public static final String EXTRAINFO_APP_CONTAINS_IAP_DISCLAIMER =
- "APP_CONTAINS_IAP_DISCLAIMER";
+ "android.app.cloudsearch.APP_CONTAINS_IAP_DISCLAIMER";
/** This App's short description, String value expected. */
- public static final String EXTRAINFO_SHORT_DESCRIPTION = "SHORT_DESCRIPTION";
+ public static final String EXTRAINFO_SHORT_DESCRIPTION =
+ "android.app.cloudsearch.SHORT_DESCRIPTION";
/** This App's long description, String value expected. */
- public static final String EXTRAINFO_LONG_DESCRIPTION = "LONG_DESCRIPTION";
- /** This App's screenshots, List<ImageLoadingBundle> value expected. */
- public static final String EXTRAINFO_SCREENSHOTS = "SCREENSHOTS";
- /** Editor's choices for this App, ArrayList<String> value expected. */
- public static final String EXTRAINFO_APP_BADGES = "APP_BADGES";
+ public static final String EXTRAINFO_LONG_DESCRIPTION =
+ "android.app.cloudsearch.LONG_DESCRIPTION";
+ /** This App's screenshots, {@code List<ImageLoadingBundle>} value expected. */
+ public static final String EXTRAINFO_SCREENSHOTS = "android.app.cloudsearch.SCREENSHOTS";
+ /** Editor's choices for this App, {@code ArrayList<String>} value expected. */
+ public static final String EXTRAINFO_APP_BADGES = "android.app.cloudsearch.APP_BADGES";
/** Pre-registration game's action button text, String value expected. */
@SuppressLint("IntentName")
- public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING = "ACTION_BUTTON_TEXT";
+ public static final String EXTRAINFO_ACTION_BUTTON_TEXT_PREREGISTERING =
+ "android.app.cloudsearch.ACTION_BUTTON_TEXT";
/** Pre-registration game's action button image, ImageLoadingBundle value expected. */
@SuppressLint("IntentName")
- public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING = "ACTION_BUTTON_IMAGE";
+ public static final String EXTRAINFO_ACTION_BUTTON_IMAGE_PREREGISTERING =
+ "android.app.cloudsearch.ACTION_BUTTON_IMAGE";
/** Web content's URL, String value expected. */
- public static final String EXTRAINFO_WEB_URL = "WEB_URL";
+ public static final String EXTRAINFO_WEB_URL = "android.app.cloudsearch.WEB_URL";
/** Web content's domain icon, android.graphics.drawable.Icon expected. */
- public static final String EXTRAINFO_WEB_ICON = "WEB_ICON";
+ public static final String EXTRAINFO_WEB_ICON = "android.app.cloudsearch.WEB_ICON";
@NonNull
private Bundle mExtraInfos;
diff --git a/core/java/android/app/contentsuggestions/OWNERS b/core/java/android/app/contentsuggestions/OWNERS
index 482abb2..cf54c2a 100644
--- a/core/java/android/app/contentsuggestions/OWNERS
+++ b/core/java/android/app/contentsuggestions/OWNERS
@@ -1,9 +1,7 @@
# Bug component: 643919
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+joannechung@google.com
+markpun@google.com
+lpeter@google.com
+tymtsai@google.com
diff --git a/core/java/android/app/usage/BroadcastResponseStats.java b/core/java/android/app/usage/BroadcastResponseStats.java
index 5acc3dda..e1d37e1 100644
--- a/core/java/android/app/usage/BroadcastResponseStats.java
+++ b/core/java/android/app/usage/BroadcastResponseStats.java
@@ -23,6 +23,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Class containing a collection of stats related to response events started from an app
* after receiving a broadcast.
@@ -32,17 +34,30 @@
@SystemApi
public final class BroadcastResponseStats implements Parcelable {
private final String mPackageName;
+ private final long mId;
private int mBroadcastsDispatchedCount;
private int mNotificationsPostedCount;
private int mNotificationsUpdatedCount;
private int mNotificationsCancelledCount;
- public BroadcastResponseStats(@NonNull String packageName) {
+ /**
+ * Creates a new {@link BroadcastResponseStats} object that contain the stats for broadcasts
+ * with {@code id} (specified using
+ * {@link BroadcastOptions#recordResponseEventWhileInBackground(long)} by the sender) that
+ * were sent to {@code packageName}.
+ *
+ * @param packageName the name of the package that broadcasts were sent to.
+ * @param id the ID specified by the sender using
+ * {@link BroadcastOptions#recordResponseEventWhileInBackground(long)}.
+ */
+ public BroadcastResponseStats(@NonNull String packageName, @IntRange(from = 1) long id) {
mPackageName = packageName;
+ mId = id;
}
private BroadcastResponseStats(@NonNull Parcel in) {
mPackageName = in.readString8();
+ mId = in.readLong();
mBroadcastsDispatchedCount = in.readInt();
mNotificationsPostedCount = in.readInt();
mNotificationsUpdatedCount = in.readInt();
@@ -58,6 +73,14 @@
}
/**
+ * @return the ID of the broadcasts that the stats in this object correspond to.
+ */
+ @IntRange(from = 1)
+ public long getId() {
+ return mId;
+ }
+
+ /**
* Returns the total number of broadcasts that were dispatched to the app by the caller.
*
* <b> Note that the returned count will only include the broadcasts that the caller explicitly
@@ -148,9 +171,35 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || !(obj instanceof BroadcastResponseStats)) {
+ return false;
+ }
+ final BroadcastResponseStats other = (BroadcastResponseStats) obj;
+ return this.mBroadcastsDispatchedCount == other.mBroadcastsDispatchedCount
+ && this.mNotificationsPostedCount == other.mNotificationsPostedCount
+ && this.mNotificationsUpdatedCount == other.mNotificationsUpdatedCount
+ && this.mNotificationsCancelledCount == other.mNotificationsCancelledCount
+ && this.mId == other.mId
+ && this.mPackageName.equals(other.mPackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackageName, mId, mBroadcastsDispatchedCount,
+ mNotificationsPostedCount, mNotificationsUpdatedCount,
+ mNotificationsCancelledCount);
+ }
+
+ @Override
public @NonNull String toString() {
return "stats {"
- + "broadcastsSent=" + mBroadcastsDispatchedCount
+ + "package=" + mPackageName
+ + ",id=" + mId
+ + ",broadcastsSent=" + mBroadcastsDispatchedCount
+ ",notificationsPosted=" + mNotificationsPostedCount
+ ",notificationsUpdated=" + mNotificationsUpdatedCount
+ ",notificationsCancelled=" + mNotificationsCancelledCount
@@ -165,6 +214,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
dest.writeString8(mPackageName);
+ dest.writeLong(mId);
dest.writeInt(mBroadcastsDispatchedCount);
dest.writeInt(mNotificationsPostedCount);
dest.writeInt(mNotificationsUpdatedCount);
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/app/usage/BroadcastResponseStatsList.aidl
similarity index 66%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to core/java/android/app/usage/BroadcastResponseStatsList.aidl
index 3091df3..7380359 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/app/usage/BroadcastResponseStatsList.aidl
@@ -14,17 +14,7 @@
* limitations under the License.
*/
-package android.window;
+package android.app.usage;
-/**
- * @hide
- */
-oneway interface IOnFpsCallbackListener {
-
- /**
- * Reports the fps from the registered task
- * @param fps The frame rate per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(in float fps);
-}
+/** {@hide} */
+parcelable BroadcastResponseStatsList;
\ No newline at end of file
diff --git a/core/java/android/app/usage/BroadcastResponseStatsList.java b/core/java/android/app/usage/BroadcastResponseStatsList.java
new file mode 100644
index 0000000..4d2ff286
--- /dev/null
+++ b/core/java/android/app/usage/BroadcastResponseStatsList.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.app.usage;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** @hide */
+public final class BroadcastResponseStatsList implements Parcelable {
+ private List<BroadcastResponseStats> mBroadcastResponseStats;
+
+ public BroadcastResponseStatsList(
+ @NonNull List<BroadcastResponseStats> broadcastResponseStats) {
+ mBroadcastResponseStats = broadcastResponseStats;
+ }
+
+ private BroadcastResponseStatsList(@NonNull Parcel in) {
+ mBroadcastResponseStats = new ArrayList<>();
+ final byte[] bytes = in.readBlob();
+ final Parcel data = Parcel.obtain();
+ try {
+ data.unmarshall(bytes, 0, bytes.length);
+ data.setDataPosition(0);
+ data.readTypedList(mBroadcastResponseStats, BroadcastResponseStats.CREATOR);
+ } finally {
+ data.recycle();
+ }
+ }
+
+ @NonNull
+ public List<BroadcastResponseStats> getList() {
+ return mBroadcastResponseStats == null ? Collections.emptyList() : mBroadcastResponseStats;
+ }
+
+ @Override
+ public @ContentsFlags int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
+ final Parcel data = Parcel.obtain();
+ try {
+ data.writeTypedList(mBroadcastResponseStats);
+ dest.writeBlob(data.marshall());
+ } finally {
+ data.recycle();
+ }
+ }
+
+ public static final @NonNull Creator<BroadcastResponseStatsList> CREATOR =
+ new Creator<BroadcastResponseStatsList>() {
+ @Override
+ public @NonNull BroadcastResponseStatsList createFromParcel(
+ @NonNull Parcel source) {
+ return new BroadcastResponseStatsList(source);
+ }
+
+ @Override
+ public @NonNull BroadcastResponseStatsList[] newArray(int size) {
+ return new BroadcastResponseStatsList[size];
+ }
+ };
+}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 6f8fea1..a430714 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.app.usage.BroadcastResponseStats;
+import android.app.usage.BroadcastResponseStatsList;
import android.app.usage.UsageEvents;
import android.content.pm.ParceledListSlice;
@@ -73,9 +74,11 @@
void forceUsageSourceSettingRead();
long getLastTimeAnyComponentUsed(String packageName, String callingPackage);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
- BroadcastResponseStats queryBroadcastResponseStats(
+ BroadcastResponseStatsList queryBroadcastResponseStats(
String packageName, long id, String callingPackage, int userId);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
void clearBroadcastResponseStats(String packageName, long id, String callingPackage,
int userId);
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)")
+ void clearBroadcastEvents(String callingPackage, int userId);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index b81c62d..d7152b3 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1397,29 +1397,46 @@
* Returns the broadcast response stats since the last boot corresponding to
* {@code packageName} and {@code id}.
*
- * <p>Broadcast response stats will include the aggregated data of what actions an app took upon
- * receiving a broadcast. This data will consider the broadcasts that the caller sent to
+ * <p> Broadcast response stats will include the aggregated data of what actions an app took
+ * upon receiving a broadcast. This data will consider the broadcasts that the caller sent to
* {@code packageName} and explicitly requested to record the response events using
* {@link BroadcastOptions#recordResponseEventWhileInBackground(long)}.
*
- * @param packageName The name of the package that the caller wants to query for.
- * @param id The ID corresponding to the broadcasts that the caller wants to query for. This is
- * the ID the caller specifies when requesting a broadcast response event to be
- * recorded using {@link BroadcastOptions#recordResponseEventWhileInBackground(long)}.
+ * <p> The returned list could one or more {@link BroadcastResponseStats} objects or be empty
+ * depending on the {@code packageName} and {@code id} and whether there is any data
+ * corresponding to these. If the {@code packageName} is not {@code null} and {@code id} is
+ * {@code > 0}, then the returned list would contain at most one {@link BroadcastResponseStats}
+ * object. Otherwise, the returned list could contain more than one
+ * {@link BroadcastResponseStats} object in no particular order.
*
- * @return the broadcast response stats corresponding to {@code packageName} and {@code id}.
+ * <p> Note: It is possible that same {@code id} was used for broadcasts sent to different
+ * packages. So, callers can query the data corresponding to
+ * all broadcasts with a particular {@code id} by passing {@code packageName} as {@code null}.
*
+ * @param packageName The name of the package that the caller wants to query for
+ * or {@code null} to indicate that data corresponding to all packages
+ * should be returned.
+ * @param id The ID corresponding to the broadcasts that the caller wants to query for, or
+ * {@code 0} to indicate that data corresponding to all IDs should be returned.
+ * This is the ID the caller specifies when requesting a broadcast response event
+ * to be recorded using
+ * {@link BroadcastOptions#recordResponseEventWhileInBackground(long)}.
+ *
+ * @return the list of broadcast response stats corresponding to {@code packageName}
+ * and {@code id}.
+ *
+ * @see #clearBroadcastResponseStats(String, long)
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
@UserHandleAware
@NonNull
- public BroadcastResponseStats queryBroadcastResponseStats(
- @NonNull String packageName, @IntRange(from = 1) long id) {
+ public List<BroadcastResponseStats> queryBroadcastResponseStats(
+ @Nullable String packageName, @IntRange(from = 0) long id) {
try {
return mService.queryBroadcastResponseStats(packageName, id,
- mContext.getOpPackageName(), mContext.getUserId());
+ mContext.getOpPackageName(), mContext.getUserId()).getList();
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1428,12 +1445,15 @@
/**
* Clears the broadcast response stats corresponding to {@code packageName} and {@code id}.
*
- * When a caller uses this API, stats related to the events occurring till that point will be
- * cleared and subsequent calls to {@link #queryBroadcastResponseStats(String, long)} will
+ * <p> When a caller uses this API, stats related to the events occurring till that point will
+ * be cleared and subsequent calls to {@link #queryBroadcastResponseStats(String, long)} will
* return stats related to events occurring after this.
*
- * @param packageName The name of the package that the caller wants to clear the data for.
- * @param id The ID corresponding to the broadcasts that the caller wants to clear the data for.
+ * @param packageName The name of the package that the caller wants to clear the data for or
+ * {@code null} to indicate that data corresponding to all packages should
+ * be cleared.
+ * @param id The ID corresponding to the broadcasts that the caller wants to clear the data
+ * for, or {code 0} to indicate that data corresponding to all IDs should be deleted.
* This is the ID the caller specifies when requesting a broadcast response event
* to be recorded using
* {@link BroadcastOptions#recordResponseEventWhileInBackground(long)}.
@@ -1444,8 +1464,8 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
@UserHandleAware
- public void clearBroadcastResponseStats(@NonNull String packageName,
- @IntRange(from = 1) long id) {
+ public void clearBroadcastResponseStats(@Nullable String packageName,
+ @IntRange(from = 0) long id) {
try {
mService.clearBroadcastResponseStats(packageName, id,
mContext.getOpPackageName(), mContext.getUserId());
@@ -1453,4 +1473,19 @@
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Clears the broadcast events that were sent by the caller uid.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ @UserHandleAware
+ public void clearBroadcastEvents() {
+ try {
+ mService.clearBroadcastEvents(mContext.getOpPackageName(), mContext.getUserId());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0fed733..8f82a0a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3525,7 +3525,7 @@
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
/**
- * Connect to an application service, creating it if needed. This defines
+ * Connects to an application service, creating it if needed. This defines
* a dependency between your application and the service. The given
* <var>conn</var> will receive the service object when it is created and be
* told if it dies and restarts. The service will be considered required
@@ -3540,11 +3540,8 @@
* will be invoked instead of
* {@link ServiceConnection#onServiceConnected(ComponentName, IBinder) onServiceConnected()}.
*
- * <p>This method will throw {@link SecurityException} if the calling app does not
- * have permission to bind to the given service.
- *
- * <p class="note">Note: this method <em>cannot be called from a
- * {@link BroadcastReceiver} component</em>. A pattern you can use to
+ * <p class="note"><b>Note:</b> This method <em>cannot</em> be called from a
+ * {@link BroadcastReceiver} component. A pattern you can use to
* communicate from a BroadcastReceiver to a Service is to call
* {@link #startService} with the arguments containing the command to be
* sent, with the service calling its
@@ -3559,33 +3556,34 @@
* specify an explicit component name.
* @param conn Receives information as the service is started and stopped.
* This must be a valid ServiceConnection object; it must not be null.
- * @param flags Operation options for the binding. May be 0,
- * {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND},
- * {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT},
- * {@link #BIND_ALLOW_OOM_MANAGEMENT}, {@link #BIND_WAIVE_PRIORITY}.
- * {@link #BIND_IMPORTANT}, {@link #BIND_ADJUST_WITH_ACTIVITY},
- * {@link #BIND_NOT_PERCEPTIBLE}, or {@link #BIND_INCLUDE_CAPABILITIES}.
- * @return {@code true} if the system is in the process of bringing up a
+ * @param flags Operation options for the binding. Can be:
+ * <ul>
+ * <li>0
+ * <li>{@link #BIND_AUTO_CREATE}
+ * <li>{@link #BIND_DEBUG_UNBIND}
+ * <li>{@link #BIND_NOT_FOREGROUND}
+ * <li>{@link #BIND_ABOVE_CLIENT}
+ * <li>{@link #BIND_ALLOW_OOM_MANAGEMENT}
+ * <li>{@link #BIND_WAIVE_PRIORITY}
+ * <li>{@link #BIND_IMPORTANT}
+ * <li>{@link #BIND_ADJUST_WITH_ACTIVITY}
+ * <li>{@link #BIND_NOT_PERCEPTIBLE}
+ * <li>{@link #BIND_INCLUDE_CAPABILITIES}
+ * </ul>
+ *
+ * @return {@code true} if the system is in the process of bringing up a
* service that your client has permission to bind to; {@code false}
* if the system couldn't find the service or if your client doesn't
* have permission to bind to it. You should call {@link #unbindService}
* to release the connection even if this method returned {@code false}.
*
- * @throws SecurityException If the caller does not have permission to access the service
- * or the service can not be found.
+ * @throws SecurityException If the caller does not have permission to
+ * access the service or the service cannot be found. Call
+ * {@link #unbindService} to release the connection when this exception
+ * is thrown.
*
* @see #unbindService
* @see #startService
- * @see #BIND_AUTO_CREATE
- * @see #BIND_DEBUG_UNBIND
- * @see #BIND_NOT_FOREGROUND
- * @see #BIND_ABOVE_CLIENT
- * @see #BIND_ALLOW_OOM_MANAGEMENT
- * @see #BIND_WAIVE_PRIORITY
- * @see #BIND_IMPORTANT
- * @see #BIND_ADJUST_WITH_ACTIVITY
- * @see #BIND_NOT_PERCEPTIBLE
- * @see #BIND_INCLUDE_CAPABILITIES
*/
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e5cffb1..0aa25ef 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9209,6 +9209,16 @@
}
/**
+ * Returns the total size of the extras in bytes, or 0 if no extras are present.
+ * @hide
+ */
+ public int getExtrasTotalSize() {
+ return (mExtras != null)
+ ? mExtras.getSize()
+ : 0;
+ }
+
+ /**
* @return Whether {@link #maybeStripForHistory} will return an lightened intent or
* return itself as-is.
* @hide
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index 21398f6..660a7f0 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -63,8 +63,12 @@
* happen, for example, if the application hosting the service it is bound to
* has been updated.
*
- * @param name The concrete component name of the service whose
- * connection is dead.
+ * <p class="note"><b>Note:</b> The app that requested the binding must call
+ * {@link Context#unbindService(ServiceConnection)} to release the tracking
+ * resources associated with this ServiceConnection even if this callback was
+ * invoked following {@link Context#bindService Context.bindService() bindService()}.
+ *
+ * @param name The concrete component name of the service whose connection is dead.
*/
default void onBindingDied(ComponentName name) {
}
@@ -72,10 +76,10 @@
/**
* Called when the service being bound has returned {@code null} from its
* {@link android.app.Service#onBind(Intent) onBind()} method. This indicates
- * that the attempting service binding represented by this ServiceConnection
+ * that the attempted service binding represented by this ServiceConnection
* will never become usable.
*
- * <p class="note">The app which requested the binding must still call
+ * <p class="note"><b>Note:</b> The app that requested the binding must still call
* {@link Context#unbindService(ServiceConnection)} to release the tracking
* resources associated with this ServiceConnection even if this callback was
* invoked following {@link Context#bindService Context.bindService() bindService()}.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2528e16..be58ba7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -39,6 +39,7 @@
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
+import android.view.OnBackInvokedCallback;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Parcelling;
@@ -801,11 +802,24 @@
*/
public static final int PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE = 1 << 2;
+
+ /**
+ * If false, {@link android.view.KeyEvent#KEYCODE_BACK} related events will be forwarded to
+ * the Activities, Dialogs and Views and {@link android.app.Activity#onBackPressed()},
+ * {@link android.app.Dialog#onBackPressed} will be called. Otherwise, those events will be
+ * replaced by a call to {@link OnBackInvokedCallback#onBackInvoked()} on the focused window.
+ *
+ * @hide
+ * @see android.R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+ */
+ public static final int PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK = 1 << 3;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
PRIVATE_FLAG_EXT_PROFILEABLE,
PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE,
+ PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlagsExt {}
@@ -1683,6 +1697,7 @@
pw.println(prefix + "localeConfigRes=0x"
+ Integer.toHexString(localeConfigRes));
}
+ pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
}
pw.println(prefix + "createTimestamp=" + createTimestamp);
if (mKnownActivityEmbeddingCerts != null) {
@@ -2566,6 +2581,17 @@
}
/**
+ * Returns whether the application will use the {@link android.view.OnBackInvokedCallback}
+ * navigation system instead of the {@link android.view.KeyEvent#KEYCODE_BACK} and related
+ * callbacks.
+ *
+ * @hide
+ */
+ public boolean isOnBackInvokedCallbackEnabled() {
+ return ((privateFlagsExt & PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)) != 0;
+ }
+
+ /**
* @hide
*/
@Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dc79ee6..a162c41 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8035,6 +8035,7 @@
return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
FrameworkPackageUserState.DEFAULT);
} catch (PackageParser.PackageParserException e) {
+ Log.w(TAG, "Failure to parse package archive", e);
return null;
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 98cc8f6..e914432 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -59,6 +59,7 @@
import android.content.pm.overlay.OverlayPaths;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
@@ -2417,9 +2418,28 @@
Slog.i(TAG, newPermsMsg.toString());
}
- final List<PermissionManager.SplitPermissionInfo> splitPermissions =
- ActivityThread.currentApplication().getSystemService(PermissionManager.class)
- .getSplitPermissions();
+ // Must build permission info manually for legacy code, which can be called before
+ // Appication is available through the app process, so the normal API doesn't work.
+ List<SplitPermissionInfoParcelable> splitPermissionParcelables;
+ try {
+ splitPermissionParcelables = ActivityThread.getPermissionManager()
+ .getSplitPermissions();
+ } catch (RemoteException e) {
+ splitPermissionParcelables = Collections.emptyList();
+ }
+
+ int splitPermissionsSize = splitPermissionParcelables.size();
+ List<PermissionManager.SplitPermissionInfo> splitPermissions =
+ new ArrayList<>(splitPermissionsSize);
+ for (int index = 0; index < splitPermissionsSize; index++) {
+ SplitPermissionInfoParcelable splitPermissionParcelable =
+ splitPermissionParcelables.get(index);
+ splitPermissions.add(new PermissionManager.SplitPermissionInfo(
+ splitPermissionParcelable.getSplitPermission(),
+ splitPermissionParcelable.getNewPermissions(),
+ splitPermissionParcelable.getTargetSdk()
+ ));
+ }
final int listSize = splitPermissions.size();
for (int is = 0; is < listSize; is++) {
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index ecd240d..24ae31e 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -199,6 +199,7 @@
certs.add(certsList);
}
}
+ typedArray.recycle();
}
return new ProviderResourceEntry(
authority,
diff --git a/core/java/android/hardware/ISensorPrivacyListener.aidl b/core/java/android/hardware/ISensorPrivacyListener.aidl
index 5d40265..2ac21d2 100644
--- a/core/java/android/hardware/ISensorPrivacyListener.aidl
+++ b/core/java/android/hardware/ISensorPrivacyListener.aidl
@@ -24,6 +24,6 @@
// the ones in
// frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
// =============== Beginning of transactions used on native side as well ======================
- void onSensorPrivacyChanged(boolean enabled);
+ void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
// =============== End of transactions used on native side as well ============================
}
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index 5571165..a392afd 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -24,34 +24,31 @@
// the ones in
// frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
// =============== Beginning of transactions used on native side as well ======================
- boolean supportsSensorToggle(int sensor);
+ boolean supportsSensorToggle(int toggleType, int sensor);
void addSensorPrivacyListener(in ISensorPrivacyListener listener);
- void addIndividualSensorPrivacyListener(int userId, int sensor,
- in ISensorPrivacyListener listener);
+ void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
- void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+ void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
boolean isSensorPrivacyEnabled();
- boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+ boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+ boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
void setSensorPrivacy(boolean enable);
- void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
- void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+ void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
// =============== End of transactions used on native side as well ============================
- void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
+ void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token,
boolean suppress);
- void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
- void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
void showSensorUseDialog(int sensor);
}
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 47659a9..dec424c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -639,7 +639,7 @@
/**
* Unregisters a listener for the sensors with which it is registered.
*
- * <p class="note"></p>
+ * <p class="note">
* Note: Don't use this method with a one shot trigger sensor such as
* {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
* Use {@link #cancelTriggerSensor(TriggerEventListener, Sensor)} instead.
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 79153d7..4399af9 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -36,7 +36,6 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
-import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -73,8 +72,6 @@
public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName()
+ ".extra.all_sensors";
- private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>();
-
/**
* Sensor constants which are used in {@link SensorPrivacyManager}
*/
@@ -241,8 +238,55 @@
void onSensorPrivacyChanged(int sensor, boolean enabled);
}
+ /**
+ * A class implementing this interface can register with the {@link
+ * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy
+ * state changes.
+ *
+ * @hide
+ */
+ public interface OnToggleSensorPrivacyChangedListener {
+
+ /**
+ * A class containing information about what the sensor privacy state has changed to.
+ */
+ class SensorPrivacyChangedParams {
+
+ private int mToggleType;
+ private int mSensor;
+ private boolean mEnabled;
+
+ private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) {
+ mToggleType = toggleType;
+ mSensor = sensor;
+ mEnabled = enabled;
+ }
+
+ public @ToggleTypes.ToggleType int getToggleType() {
+ return mToggleType;
+ }
+
+ public @Sensors.Sensor int getSensor() {
+ return mSensor;
+ }
+
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+ }
+
+ /**
+ * Callback invoked when the sensor privacy state changes.
+ *
+ * @param params Parameters describing the new state
+ */
+ void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params);
+ }
+
private static final Object sInstanceLock = new Object();
+ private final Object mLock = new Object();
+
@GuardedBy("sInstanceLock")
private static SensorPrivacyManager sInstance;
@@ -252,12 +296,46 @@
@NonNull
private final ISensorPrivacyManager mService;
+ @GuardedBy("mLock")
+ private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>();
+
@NonNull
private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners;
+ /** Registered listeners */
+ @GuardedBy("mLock")
@NonNull
- private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener>
- mIndividualListeners;
+ private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners =
+ new ArrayMap<>();
+
+ /** Listeners registered using the deprecated APIs and which
+ * OnToggleSensorPrivacyChangedListener they're using. */
+ @GuardedBy("mLock")
+ @NonNull
+ private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>,
+ OnToggleSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>();
+
+ /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local
+ * listeners */
+ @NonNull
+ private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() {
+ @Override
+ public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) {
+ synchronized (mLock) {
+ for (int i = 0; i < mToggleListeners.size(); i++) {
+ OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i);
+ mToggleListeners.valueAt(i).execute(() -> listener
+ .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener
+ .SensorPrivacyChangedParams(toggleType, sensor, enabled)));
+ }
+ }
+ }
+ };
+
+ /** Whether the singleton ISensorPrivacyListener has been registered */
+ @GuardedBy("mLock")
+ @NonNull
+ private boolean mToggleListenerRegistered = false;
/**
* Private constructor to ensure only a single instance is created.
@@ -266,7 +344,6 @@
mContext = context;
mService = service;
mListeners = new ArrayMap<>();
- mIndividualListeners = new ArrayMap<>();
}
/**
@@ -295,25 +372,43 @@
* @return whether the toggle for the sensor is supported on this device.
*/
public boolean supportsSensorToggle(@Sensors.Sensor int sensor) {
+ return supportsSensorToggle(ToggleTypes.SOFTWARE, sensor);
+ }
+
+ /**
+ * Checks if the given toggle is supported on this device
+ * @param sensor The sensor to check
+ * @return whether the toggle for the sensor is supported on this device.
+ *
+ * @hide
+ */
+ public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType,
+ @Sensors.Sensor int sensor) {
try {
- Boolean val = mToggleSupportCache.get(sensor);
- if (val == null) {
- val = mService.supportsSensorToggle(sensor);
- mToggleSupportCache.put(sensor, val);
+ Pair key = new Pair(toggleType, sensor);
+ synchronized (mLock) {
+ Boolean val = mToggleSupportCache.get(key);
+ if (val == null) {
+ val = mService.supportsSensorToggle(toggleType, sensor);
+ mToggleSupportCache.put(key, val);
+ }
+ return val;
}
- return val;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
* @param sensor the sensor to listen to changes to
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * privacy changes.
+ *
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
*
* @hide
*/
@@ -325,6 +420,7 @@
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
@@ -333,22 +429,27 @@
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
* privacy changes.
*
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
+ *
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
+ public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId,
@NonNull OnSensorPrivacyChangedListener listener) {
- addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener);
+ addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
* @param sensor the sensor to listen to changes to
* @param executor the executor to dispatch the callback on
* @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * privacy changes.
+ *
+ * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
*
* @hide
*/
@@ -356,61 +457,69 @@
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
@NonNull OnSensorPrivacyChangedListener listener) {
- Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
- synchronized (mIndividualListeners) {
- ISensorPrivacyListener iListener = mIndividualListeners.get(key);
- if (iListener == null) {
- iListener = new ISensorPrivacyListener.Stub() {
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
- }
- };
- mIndividualListeners.put(key, iListener);
- }
- try {
- mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+ OnToggleSensorPrivacyChangedListener toggleListener = params -> {
+ if (params.getSensor() == sensor) {
+ listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled());
}
+ };
+
+ synchronized (mLock) {
+ mLegacyToggleListeners.put(pair, toggleListener);
+ addSensorPrivacyListenerLocked(executor, toggleListener);
}
}
/**
+ *
* Registers a new listener to receive notification when the state of sensor privacy
* changes.
*
- * @param sensor the sensor to listen to changes to
- * @param executor the executor to dispatch the callback on
- * @param userId the user's id
- * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
- * privacy changes.
+ * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+ * sensor privacy changes.
*
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
- @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) {
- synchronized (mIndividualListeners) {
- ISensorPrivacyListener iListener = mIndividualListeners.get(listener);
- if (iListener == null) {
- iListener = new ISensorPrivacyListener.Stub() {
- @Override
- public void onSensorPrivacyChanged(boolean enabled) {
- executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
- }
- };
- mIndividualListeners.put(new Pair<>(listener, sensor), iListener);
- }
+ public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) {
+ addSensorPrivacyListener(mContext.getMainExecutor(), listener);
+ }
+ /**
+ *
+ * Registers a new listener to receive notification when the state of sensor privacy
+ * changes.
+ *
+ * @param executor the executor to dispatch the callback on
+ * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+ * sensor privacy changes.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void addSensorPrivacyListener(@NonNull Executor executor,
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ addSensorPrivacyListenerLocked(executor, listener);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void addSensorPrivacyListenerLocked(@NonNull Executor executor,
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ if (!mToggleListenerRegistered) {
try {
- mService.addIndividualSensorPrivacyListener(userId, sensor,
- iListener);
+ mService.addToggleSensorPrivacyListener(mIToggleListener);
+ mToggleListenerRegistered = true;
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ e.rethrowFromSystemServer();
}
}
+ if (mToggleListeners.containsKey(listener)) {
+ throw new IllegalArgumentException("listener is already registered");
+ }
+ mToggleListeners.put(listener, executor);
}
/**
@@ -420,30 +529,60 @@
* @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when
* sensor privacy changes.
*
+ * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with
+ * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or
+ * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
+ *
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public void removeSensorPrivacyListener(@Sensors.Sensor int sensor,
@NonNull OnSensorPrivacyChangedListener listener) {
- synchronized (mListeners) {
- for (int i = 0; i < mIndividualListeners.size(); i++) {
- Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i);
- if (pair.second == sensor && pair.first.equals(listener)) {
- try {
- mService.removeIndividualSensorPrivacyListener(sensor,
- mIndividualListeners.valueAt(i));
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- mIndividualListeners.removeAt(i--);
- }
+ Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+ synchronized (mLock) {
+ OnToggleSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener =
+ mLegacyToggleListeners.remove(pair);
+ if (onToggleSensorPrivacyChangedListener != null) {
+ removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener);
}
}
}
/**
- * Returns whether sensor privacy is currently enabled for a specific sensor.
+ * Unregisters the specified listener from receiving notifications when the state of any sensor
+ * privacy changes.
+ *
+ * @param listener the {@link OnToggleSensorPrivacyChangedListener} to be unregistered from
+ * notifications when sensor privacy changes.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public void removeSensorPrivacyListener(
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ synchronized (mLock) {
+ removeSensorPrivacyListenerLocked(listener);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void removeSensorPrivacyListenerLocked(
+ @NonNull OnToggleSensorPrivacyChangedListener listener) {
+ mToggleListeners.remove(listener);
+ if (mToggleListeners.size() == 0) {
+ try {
+ mService.removeToggleSensorPrivacyListener(mIToggleListener);
+ mToggleListenerRegistered = false;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns whether sensor privacy is currently enabled by software control for a specific
+ * sensor.
*
* @return true if sensor privacy is currently enabled, false otherwise.
*
@@ -452,7 +591,7 @@
@SystemApi
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
- return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
+ return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor);
}
/**
@@ -463,9 +602,27 @@
* @hide
*/
@RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
- public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) {
+ public boolean isSensorPrivacyEnabled(@ToggleTypes.ToggleType int toggleType,
+ @Sensors.Sensor int sensor) {
try {
- return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
+ return mService.isToggleSensorPrivacyEnabled(toggleType, sensor);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether sensor privacy is currently enabled for a specific sensor.
+ * Combines the state of the SW + HW toggles and returns the actual privacy state.
+ *
+ * @return true if sensor privacy is currently enabled, false otherwise.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+ public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
+ try {
+ return mService.isCombinedToggleSensorPrivacyEnabled(sensor);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -524,7 +681,7 @@
public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
boolean enable, @UserIdInt int userId) {
try {
- mService.setIndividualSensorPrivacy(userId, source, sensor, enable);
+ mService.setToggleSensorPrivacy(userId, source, sensor, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -561,7 +718,7 @@
public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
@Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) {
try {
- mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable);
+ mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -592,7 +749,7 @@
public void suppressSensorPrivacyReminders(int sensor,
boolean suppress, @UserIdInt int userId) {
try {
- mService.suppressIndividualSensorPrivacyReminders(userId, sensor,
+ mService.suppressToggleSensorPrivacyReminders(userId, sensor,
token, suppress);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -667,7 +824,8 @@
if (iListener == null) {
iListener = new ISensorPrivacyListener.Stub() {
@Override
- public void onSensorPrivacyChanged(boolean enabled) {
+ public void onSensorPrivacyChanged(int toggleType, int sensor,
+ boolean enabled) {
listener.onAllSensorPrivacyChanged(enabled);
}
};
diff --git a/core/java/android/hardware/SensorPrivacyManagerInternal.java b/core/java/android/hardware/SensorPrivacyManagerInternal.java
index d12e9f8..f4de966 100644
--- a/core/java/android/hardware/SensorPrivacyManagerInternal.java
+++ b/core/java/android/hardware/SensorPrivacyManagerInternal.java
@@ -61,4 +61,9 @@
*/
public abstract void addSensorPrivacyListenerForAllUsers(int sensor,
OnUserSensorPrivacyChangedListener listener);
+
+ /**
+ * Set the HW toggle sensor value based on HW switch states, called from InputManagerService
+ */
+ public abstract void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable);
}
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index 693cda7..99791ce 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -214,6 +214,16 @@
return CONTENTS_FILE_DESCRIPTOR;
}
+ /** @hide */
+ public Object getLock() {
+ return mCloser;
+ }
+
+ /** @hide */
+ public long getNativeFence() {
+ return mNativePtr;
+ }
+
/**
* Flatten this object into a Parcel.
*
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index a979725..7b695e7 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -39,13 +39,13 @@
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_ENABLED;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_OVERHEAT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_CONTAMINANT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DOCK;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DEBUG;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_ENABLED;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
import android.Manifest;
import android.annotation.CheckResult;
@@ -400,7 +400,7 @@
}
/**
- * Enables Usb data when disabled due to {@link UsbPort#USB_DATA_STATUS_DISABLED_DOCK}
+ * Enables Usb data when disabled due to {@link UsbPort#DATA_STATUS_DISABLED_DOCK}
*
* @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or
* {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to
@@ -421,7 +421,8 @@
+ " callingUid:" + Binder.getCallingUid());
UsbPortStatus portStatus = getStatus();
if (portStatus != null &&
- !usbDataStatusToString(portStatus.getUsbDataStatus()).contains("disabled-dock")) {
+ (portStatus.getUsbDataStatus() & DATA_STATUS_DISABLED_DOCK) !=
+ DATA_STATUS_DISABLED_DOCK) {
return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED;
}
@@ -584,44 +585,43 @@
/** @hide */
public static String usbDataStatusToString(int usbDataStatus) {
- switch (usbDataStatus) {
- case USB_DATA_STATUS_UNKNOWN:
- return "unknown";
- case USB_DATA_STATUS_ENABLED:
- return "enabled";
- case USB_DATA_STATUS_DISABLED_OVERHEAT:
- return "disabled-overheat";
- case USB_DATA_STATUS_DISABLED_CONTAMINANT:
- return "disabled-contaminant";
- case USB_DATA_STATUS_DISABLED_DOCK:
- return "disabled-dock";
- case USB_DATA_STATUS_DISABLED_FORCE:
- return "disabled-force";
- case USB_DATA_STATUS_DISABLED_DEBUG:
- return "disabled-debug";
- default:
- return Integer.toString(usbDataStatus);
- }
- }
+ StringBuilder statusString = new StringBuilder();
- /** @hide */
- public static String usbDataStatusToString(int[] usbDataStatus) {
- StringBuilder modeString = new StringBuilder();
- if (usbDataStatus == null) {
+ if (usbDataStatus == DATA_STATUS_UNKNOWN) {
return "unknown";
}
- for (int i = 0; i < usbDataStatus.length; i++) {
- modeString.append(usbDataStatusToString(usbDataStatus[i]));
- if (i < usbDataStatus.length - 1) {
- modeString.append(", ");
- }
+
+ if ((usbDataStatus & DATA_STATUS_ENABLED) == DATA_STATUS_ENABLED) {
+ return "enabled";
}
- return modeString.toString();
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_OVERHEAT) == DATA_STATUS_DISABLED_OVERHEAT) {
+ statusString.append("disabled-overheat, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_CONTAMINANT)
+ == DATA_STATUS_DISABLED_CONTAMINANT) {
+ statusString.append("disabled-contaminant, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK) == DATA_STATUS_DISABLED_DOCK) {
+ statusString.append("disabled-dock, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_FORCE) == DATA_STATUS_DISABLED_FORCE) {
+ statusString.append("disabled-force, ");
+ }
+
+ if ((usbDataStatus & DATA_STATUS_DISABLED_DEBUG) == DATA_STATUS_DISABLED_DEBUG) {
+ statusString.append("disabled-debug, ");
+ }
+
+ return statusString.toString().replaceAll(", $", "");
}
/** @hide */
- public static String powerBrickStatusToString(int powerBrickStatus) {
- switch (powerBrickStatus) {
+ public static String powerBrickConnectionStatusToString(int powerBrickConnectionStatus) {
+ switch (powerBrickConnectionStatus) {
case POWER_BRICK_STATUS_UNKNOWN:
return "unknown";
case POWER_BRICK_STATUS_CONNECTED:
@@ -629,7 +629,7 @@
case POWER_BRICK_STATUS_DISCONNECTED:
return "disconnected";
default:
- return Integer.toString(powerBrickStatus);
+ return Integer.toString(powerBrickConnectionStatus);
}
}
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index d1f4246..3221ec8 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -44,8 +44,8 @@
private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
private final boolean mPowerTransferLimited;
- private final @UsbDataStatus int[] mUsbDataStatus;
- private final @PowerBrickStatus int mPowerBrickStatus;
+ private final @UsbDataStatus int mUsbDataStatus;
+ private final @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
/**
* Power role: This USB port does not have a power role.
@@ -198,38 +198,38 @@
/**
* USB data status is not known.
*/
- public static final int USB_DATA_STATUS_UNKNOWN = 0;
+ public static final int DATA_STATUS_UNKNOWN = 0;
/**
* USB data is enabled.
*/
- public static final int USB_DATA_STATUS_ENABLED = 1;
+ public static final int DATA_STATUS_ENABLED = 1 << 0;
/**
* USB data is disabled as the port is too hot.
*/
- public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+ public static final int DATA_STATUS_DISABLED_OVERHEAT = 1 << 1;
/**
* USB data is disabled due to contaminated port.
*/
- public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+ public static final int DATA_STATUS_DISABLED_CONTAMINANT = 1 << 2;
/**
* USB data is disabled due to docking event.
*/
- public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+ public static final int DATA_STATUS_DISABLED_DOCK = 1 << 3;
/**
* USB data is disabled by
* {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
*/
- public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+ public static final int DATA_STATUS_DISABLED_FORCE = 1 << 4;
/**
* USB data is disabled for debug.
*/
- public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+ public static final int DATA_STATUS_DISABLED_DEBUG = 1 << 5;
/**
* Unknown whether a power brick is connected.
@@ -276,14 +276,14 @@
@interface UsbPortMode{}
/** @hide */
- @IntDef(prefix = { "USB_DATA_STATUS_" }, value = {
- USB_DATA_STATUS_UNKNOWN,
- USB_DATA_STATUS_ENABLED,
- USB_DATA_STATUS_DISABLED_OVERHEAT,
- USB_DATA_STATUS_DISABLED_CONTAMINANT,
- USB_DATA_STATUS_DISABLED_DOCK,
- USB_DATA_STATUS_DISABLED_FORCE,
- USB_DATA_STATUS_DISABLED_DEBUG
+ @IntDef(prefix = { "DATA_STATUS_" }, flag = true, value = {
+ DATA_STATUS_UNKNOWN,
+ DATA_STATUS_ENABLED,
+ DATA_STATUS_DISABLED_OVERHEAT,
+ DATA_STATUS_DISABLED_CONTAMINANT,
+ DATA_STATUS_DISABLED_DOCK,
+ DATA_STATUS_DISABLED_FORCE,
+ DATA_STATUS_DISABLED_DEBUG
})
@Retention(RetentionPolicy.SOURCE)
@interface UsbDataStatus{}
@@ -295,13 +295,14 @@
POWER_BRICK_STATUS_CONNECTED,
})
@Retention(RetentionPolicy.SOURCE)
- @interface PowerBrickStatus{}
+ @interface PowerBrickConnectionStatus{}
/** @hide */
public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
- int contaminantDetectionStatus, @UsbDataStatus int[] usbDataStatus,
- boolean powerTransferLimited, @PowerBrickStatus int powerBrickStatus) {
+ int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
+ boolean powerTransferLimited,
+ @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
mCurrentMode = currentMode;
mCurrentPowerRole = currentPowerRole;
mCurrentDataRole = currentDataRole;
@@ -310,7 +311,7 @@
mContaminantDetectionStatus = contaminantDetectionStatus;
mUsbDataStatus = usbDataStatus;
mPowerTransferLimited = powerTransferLimited;
- mPowerBrickStatus = powerBrickStatus;
+ mPowerBrickConnectionStatus = powerBrickConnectionStatus;
}
/** @hide */
@@ -323,8 +324,8 @@
mSupportedRoleCombinations = supportedRoleCombinations;
mContaminantProtectionStatus = contaminantProtectionStatus;
mContaminantDetectionStatus = contaminantDetectionStatus;
- mUsbDataStatus = new int[]{USB_DATA_STATUS_UNKNOWN};
- mPowerBrickStatus = POWER_BRICK_STATUS_UNKNOWN;
+ mUsbDataStatus = DATA_STATUS_UNKNOWN;
+ mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
mPowerTransferLimited = false;
}
@@ -411,13 +412,13 @@
/**
* Returns UsbData status.
*
- * @return Current USB data status of the port: {@link #USB_DATA_STATUS_UNKNOWN}
- * or {@link #USB_DATA_STATUS_ENABLED} or {@link #USB_DATA_STATUS_DIASBLED_OVERHEAT}
- * or {@link #USB_DATA_STATUS_DISABLED_CONTAMINANT}
- * or {@link #USB_DATA_STATUS_DISABLED_DOCK} or {@link #USB_DATA_STATUS_DISABLED_FORCE}
- * or {@link #USB_DATA_STATUS_DISABLED_DEBUG}
+ * @return Current USB data status of the port with one or more of the following values
+ * {@link #DATA_STATUS_UNKNOWN}, {@link #DATA_STATUS_ENABLED},
+ * {@link #DATA_STATUS_DISABLED_OVERHEAT}, {@link #DATA_STATUS_DISABLED_CONTAMINANT},
+ * {@link #DATA_STATUS_DISABLED_DOCK}, {@link #DATA_STATUS_DISABLED_FORCE},
+ * {@link #DATA_STATUS_DISABLED_DEBUG}
*/
- public @UsbDataStatus @Nullable int[] getUsbDataStatus() {
+ public @UsbDataStatus int getUsbDataStatus() {
return mUsbDataStatus;
}
@@ -432,14 +433,14 @@
}
/**
- * Let's the caller know if a power brick is connected to the USB port.
+ * Returns the connection status of the power brick.
*
* @return {@link #POWER_BRICK_STATUS_UNKNOWN}
* or {@link #POWER_BRICK_STATUS_CONNECTED}
* or {@link #POWER_BRICK_STATUS_DISCONNECTED}
*/
- public @PowerBrickStatus int getPowerBrickStatus() {
- return mPowerBrickStatus;
+ public @PowerBrickConnectionStatus int getPowerBrickConnectionStatus() {
+ return mPowerBrickConnectionStatus;
}
@NonNull
@@ -459,8 +460,9 @@
+ UsbPort.usbDataStatusToString(getUsbDataStatus())
+ ", isPowerTransferLimited="
+ isPowerTransferLimited()
- +", powerBrickStatus="
- + UsbPort.powerBrickStatusToString(getPowerBrickStatus())
+ +", powerBrickConnectionStatus="
+ + UsbPort
+ .powerBrickConnectionStatusToString(getPowerBrickConnectionStatus())
+ "}";
}
@@ -477,10 +479,9 @@
dest.writeInt(mSupportedRoleCombinations);
dest.writeInt(mContaminantProtectionStatus);
dest.writeInt(mContaminantDetectionStatus);
- dest.writeInt(mUsbDataStatus.length);
- dest.writeIntArray(mUsbDataStatus);
+ dest.writeInt(mUsbDataStatus);
dest.writeBoolean(mPowerTransferLimited);
- dest.writeInt(mPowerBrickStatus);
+ dest.writeInt(mPowerBrickConnectionStatus);
}
public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -493,14 +494,13 @@
int supportedRoleCombinations = in.readInt();
int contaminantProtectionStatus = in.readInt();
int contaminantDetectionStatus = in.readInt();
- int[] usbDataStatus = new int[in.readInt()];
- in.readIntArray(usbDataStatus);
+ int usbDataStatus = in.readInt();
boolean powerTransferLimited = in.readBoolean();
- int powerBrickStatus = in.readInt();
+ int powerBrickConnectionStatus = in.readInt();
return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
- powerBrickStatus);
+ powerBrickConnectionStatus);
}
@Override
@@ -508,4 +508,126 @@
return new UsbPortStatus[size];
}
};
+
+ /**
+ * Builder is used to create {@link UsbPortStatus} objects.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private @UsbPortMode int mCurrentMode;
+ private @UsbPowerRole int mCurrentPowerRole;
+ private @UsbDataRole int mCurrentDataRole;
+ private int mSupportedRoleCombinations;
+ private @ContaminantProtectionStatus int mContaminantProtectionStatus;
+ private @ContaminantDetectionStatus int mContaminantDetectionStatus;
+ private boolean mPowerTransferLimited;
+ private @UsbDataStatus int mUsbDataStatus;
+ private @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
+
+ public Builder() {
+ mCurrentMode = MODE_NONE;
+ mCurrentPowerRole = POWER_ROLE_NONE;
+ mCurrentDataRole = DATA_ROLE_NONE;
+ mContaminantProtectionStatus = CONTAMINANT_PROTECTION_NONE;
+ mContaminantDetectionStatus = CONTAMINANT_DETECTION_NOT_SUPPORTED;
+ mUsbDataStatus = DATA_STATUS_UNKNOWN;
+ mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
+ }
+
+ /**
+ * Sets the current mode of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setCurrentMode(@UsbPortMode int currentMode) {
+ mCurrentMode = currentMode;
+ return this;
+ }
+
+ /**
+ * Sets the current power role and data role of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setCurrentRoles(@UsbPowerRole int currentPowerRole,
+ @UsbDataRole int currentDataRole) {
+ mCurrentPowerRole = currentPowerRole;
+ mCurrentDataRole = currentDataRole;
+ return this;
+ }
+
+ /**
+ * Sets supported role combinations of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setSupportedRoleCombinations(int supportedRoleCombinations) {
+ mSupportedRoleCombinations = supportedRoleCombinations;
+ return this;
+ }
+
+ /**
+ * Sets current contaminant status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setContaminantStatus(
+ @ContaminantProtectionStatus int contaminantProtectionStatus,
+ @ContaminantDetectionStatus int contaminantDetectionStatus) {
+ mContaminantProtectionStatus = contaminantProtectionStatus;
+ mContaminantDetectionStatus = contaminantDetectionStatus;
+ return this;
+ }
+
+ /**
+ * Sets power limit power transfer of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setPowerTransferLimited(boolean powerTransferLimited) {
+ mPowerTransferLimited = powerTransferLimited;
+ return this;
+ }
+
+ /**
+ * Sets the USB data status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setUsbDataStatus(@UsbDataStatus int usbDataStatus) {
+ mUsbDataStatus = usbDataStatus;
+ return this;
+ }
+
+ /**
+ * Sets the power brick connection status of {@link UsbPortStatus}
+ *
+ * @return Instance of {@link Builder}
+ */
+ @NonNull
+ public Builder setPowerBrickConnectionStatus(
+ @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
+ mPowerBrickConnectionStatus = powerBrickConnectionStatus;
+ return this;
+ }
+
+ /**
+ * Creates the {@link UsbPortStatus} object.
+ */
+ @NonNull
+ public UsbPortStatus build() {
+ UsbPortStatus status = new UsbPortStatus(mCurrentMode, mCurrentPowerRole,
+ mCurrentDataRole, mSupportedRoleCombinations, mContaminantProtectionStatus,
+ mContaminantDetectionStatus, mUsbDataStatus, mPowerTransferLimited,
+ mPowerBrickConnectionStatus);
+ return status;
+ }
+ };
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index adf2759..c3e3180 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,7 +346,7 @@
*/
@AnyThread
public static boolean canImeRenderGesturalNavButtons() {
- return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
+ return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
}
/**
@@ -989,24 +989,6 @@
public void changeInputMethodSubtype(InputMethodSubtype subtype) {
dispatchOnCurrentInputMethodSubtypeChanged(subtype);
}
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @Override
- public void setCurrentShowInputToken(IBinder showInputToken) {
- mCurShowInputToken = showInputToken;
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @Override
- public void setCurrentHideInputToken(IBinder hideInputToken) {
- mCurHideInputToken = hideInputToken;
- }
}
/**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 6f4fd76..19fa01d 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -45,7 +45,6 @@
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
-import android.view.WindowManagerPolicyConstants;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
@@ -138,7 +137,7 @@
private boolean mDestroyed = false;
- private boolean mRenderGesturalNavButtons;
+ private boolean mImeDrawsImeNavBar;
@Nullable
private NavigationBarFrame mNavigationBarFrame;
@@ -185,7 +184,7 @@
}
private void installNavigationBarFrameIfNecessary() {
- if (!mRenderGesturalNavButtons) {
+ if (!mImeDrawsImeNavBar) {
return;
}
if (mNavigationBarFrame != null) {
@@ -253,7 +252,7 @@
@Override
public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
- if (!mRenderGesturalNavButtons || mNavigationBarFrame == null
+ if (!mImeDrawsImeNavBar || mNavigationBarFrame == null
|| mService.isExtractViewShown()) {
return;
}
@@ -360,13 +359,12 @@
});
}
- private boolean isGesturalNavigationEnabled() {
+ private boolean imeDrawsImeNavBar() {
final Resources resources = mService.getResources();
if (resources == null) {
return false;
}
- return resources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode)
- == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+ return resources.getBoolean(com.android.internal.R.bool.config_imeDrawsImeNavBar);
}
@Override
@@ -381,7 +379,7 @@
if (mDestroyed) {
return;
}
- mRenderGesturalNavButtons = isGesturalNavigationEnabled();
+ mImeDrawsImeNavBar = imeDrawsImeNavBar();
if (mSystemOverlayChangedReceiver == null) {
final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
@@ -392,8 +390,8 @@
if (mDestroyed) {
return;
}
- mRenderGesturalNavButtons = isGesturalNavigationEnabled();
- if (mRenderGesturalNavButtons) {
+ mImeDrawsImeNavBar = imeDrawsImeNavBar();
+ if (mImeDrawsImeNavBar) {
installNavigationBarFrameIfNecessary();
} else {
uninstallNavigationBarFrameIfNecessary();
@@ -423,7 +421,7 @@
@Override
public void onWindowShown() {
- if (mDestroyed || !mRenderGesturalNavButtons || mNavigationBarFrame == null) {
+ if (mDestroyed || !mImeDrawsImeNavBar || mNavigationBarFrame == null) {
return;
}
final Insets systemInsets = getSystemInsets();
@@ -546,7 +544,7 @@
@Override
public String toDebugString() {
- return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
+ return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
+ " mNavigationBarFrame=" + mNavigationBarFrame
+ " mShouldShowImeSwitcherWhenImeIsShown="
+ mShouldShowImeSwitcherWhenImeIsShown
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index b9252d6..7379443 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -104,6 +104,8 @@
public final class SystemClock {
private static final String TAG = "SystemClock";
+ private static volatile IAlarmManager sIAlarmManager;
+
/**
* This class is uninstantiable.
*/
@@ -151,8 +153,7 @@
* @return if the clock was successfully set to the specified time.
*/
public static boolean setCurrentTimeMillis(long millis) {
- final IAlarmManager mgr = IAlarmManager.Stub
- .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ final IAlarmManager mgr = getIAlarmManager();
if (mgr == null) {
Slog.e(TAG, "Unable to set RTC: mgr == null");
return false;
@@ -280,8 +281,7 @@
* @hide
*/
public static long currentNetworkTimeMillis() {
- final IAlarmManager mgr = IAlarmManager.Stub
- .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ final IAlarmManager mgr = getIAlarmManager();
if (mgr != null) {
try {
return mgr.currentNetworkTimeMillis();
@@ -296,6 +296,14 @@
}
}
+ private static IAlarmManager getIAlarmManager() {
+ if (sIAlarmManager == null) {
+ sIAlarmManager = IAlarmManager.Stub
+ .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+ }
+ return sIAlarmManager;
+ }
+
/**
* Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
* synchronized using a remote network source outside the device.
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index d223a19..642c618 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -27,7 +27,7 @@
import java.util.Objects;
/**
- * A class to encapsulate a collection of attributes describing information about a vibration
+ * Encapsulates a collection of attributes describing information about a vibration.
*/
public final class VibrationAttributes implements Parcelable {
private static final String TAG = "VibrationAttributes";
@@ -174,7 +174,7 @@
FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF;
/** Creates a new {@link VibrationAttributes} instance with given usage. */
- public static @NonNull VibrationAttributes createForUsage(int usage) {
+ public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
return new VibrationAttributes.Builder().setUsage(usage).build();
}
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 21c6487..237f6ed 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -48,7 +48,7 @@
/**
* A VibrationEffect describes a haptic effect to be performed by a {@link Vibrator}.
*
- * These effects may be any number of things, from single shot vibrations to complex waveforms.
+ * <p>These effects may be any number of things, from single shot vibrations to complex waveforms.
*/
public abstract class VibrationEffect implements Parcelable {
// Stevens' coefficient to scale the perceived vibration intensity.
@@ -110,7 +110,7 @@
/**
* A texture effect meant to replicate soft ticks.
*
- * Unlike normal effects, texture effects are meant to be called repeatedly, generally in
+ * <p>Unlike normal effects, texture effects are meant to be called repeatedly, generally in
* response to some motion, in order to replicate the feeling of some texture underneath the
* user's fingers.
*
@@ -175,7 +175,7 @@
/**
* Create a one shot vibration.
*
- * One shot vibrations will vibrate constantly for the specified period of time at the
+ * <p>One shot vibrations will vibrate constantly for the specified period of time at the
* specified amplitude, and then stop.
*
* @param milliseconds The number of milliseconds to vibrate. This must be a positive number.
@@ -269,13 +269,13 @@
/**
* Create a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * This will fallback to a generic pattern if one exists and there does not exist a
+ * <p>This will fallback to a generic pattern if one exists and there does not exist a
* hardware-specific implementation of the effect.
*
* @param effectId The ID of the effect to perform:
@@ -291,13 +291,13 @@
/**
* Get a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * This will fallback to a generic pattern if one exists and there does not exist a
+ * <p>This will fallback to a generic pattern if one exists and there does not exist a
* hardware-specific implementation of the effect.
*
* @param effectId The ID of the effect to perform:
@@ -314,16 +314,16 @@
/**
* Get a predefined vibration effect.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
- * Some effects you may only want to play if there's a hardware specific implementation because
- * they may, for example, be too disruptive to the user without tuning. The {@code fallback}
- * parameter allows you to decide whether you want to fallback to the generic implementation or
- * only play if there's a tuned, hardware specific one available.
+ * <p>Some effects you may only want to play if there's a hardware specific implementation
+ * because they may, for example, be too disruptive to the user without tuning. The
+ * {@code fallback} parameter allows you to decide whether you want to fallback to the generic
+ * implementation or only play if there's a tuned, hardware specific one available.
*
* @param effectId The ID of the effect to perform:
* {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
@@ -344,9 +344,9 @@
/**
* Get a predefined vibration effect associated with a given URI.
*
- * Predefined effects are a set of common vibration effects that should be identical, regardless
- * of the app they come from, in order to provide a cohesive experience for users across
- * the entire device. They also may be custom tailored to the device hardware in order to
+ * <p>Predefined effects are a set of common vibration effects that should be identical,
+ * regardless of the app they come from, in order to provide a cohesive experience for users
+ * across the entire device. They also may be custom tailored to the device hardware in order to
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
@@ -474,7 +474,7 @@
/**
* Gets the estimated duration of the vibration in milliseconds.
*
- * For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this
+ * <p>For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this
* returns Long.MAX_VALUE. For effects with an unknown duration (e.g. Prebaked effects where
* the length is device and potentially run-time dependent), this returns -1.
*
@@ -817,28 +817,26 @@
* effect that grows in intensity and then dies off, with a longer rising portion for emphasis
* and an extra tick 100ms after:
*
- * <code>
- * VibrationEffect effect = VibrationEffect.startComposition()
+ * <pre>
+ * {@code VibrationEffect effect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE, 0.5f)
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_FALL, 0.5f)
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1.0f, 100)
- * .compose();
- * </code>
+ * .compose();}</pre>
*
* <p>Composition elements can also be {@link VibrationEffect} instances, including other
* compositions, and off durations, which are periods of time when the vibrator will be
* turned off. Here is an example of a composition that "warms up" with a light tap,
* a stronger double tap, then repeats a vibration pattern indefinitely:
*
- * <code>
- * VibrationEffect repeatingEffect = VibrationEffect.startComposition()
+ * <pre>
+ * {@code VibrationEffect repeatingEffect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_LOW_TICK)
* .addOffDuration(Duration.ofMillis(10))
* .addEffect(VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK))
* .addOffDuration(Duration.ofMillis(50))
* .addEffect(VibrationEffect.createWaveform(pattern, repeatIndex))
- * .compose();
- * </code>
+ * .compose();}</pre>
*
* <p>When choosing to play a composed effect, you should check that individual components are
* supported by the device by using the appropriate vibrator method:
@@ -932,7 +930,7 @@
/**
* Adds a time duration to the current composition, during which the vibrator will be
- * turned off
+ * turned off.
*
* @param duration The length of time the vibrator should be off. Value must be non-negative
* and will be truncated to milliseconds.
@@ -1004,7 +1002,7 @@
/**
* Add a haptic primitive to the end of the current composition.
*
- * Similar to {@link #addPrimitive(int, float, int)}, but with no delay and a
+ * <p>Similar to {@link #addPrimitive(int, float, int)}, but with no delay and a
* default scale applied.
*
* @param primitiveId The primitive to add
@@ -1021,7 +1019,7 @@
/**
* Add a haptic primitive to the end of the current composition.
*
- * Similar to {@link #addPrimitive(int, float, int)}, but with no delay.
+ * <p>Similar to {@link #addPrimitive(int, float, int)}, but with no delay.
*
* @param primitiveId The primitive to add
* @param scale The scale to apply to the intensity of the primitive.
@@ -1081,9 +1079,9 @@
/**
* Compose all of the added primitives together into a single {@link VibrationEffect}.
*
- * The {@link Composition} object is still valid after this call, so you can continue adding
- * more primitives to it and generating more {@link VibrationEffect}s by calling this method
- * again.
+ * <p>The {@link Composition} object is still valid after this call, so you can continue
+ * adding more primitives to it and generating more {@link VibrationEffect}s by calling this
+ * method again.
*
* @return The {@link VibrationEffect} resulting from the composition of the primitives.
*/
@@ -1099,7 +1097,7 @@
}
/**
- * Convert the primitive ID to a human readable string for debugging
+ * Convert the primitive ID to a human readable string for debugging.
* @param id The ID to convert
* @return The ID in a human readable format.
* @hide
@@ -1139,16 +1137,15 @@
* <p>The following example ramps a vibrator turned off to full amplitude at 120Hz, over 100ms
* starting at 60Hz, then holds that state for 200ms and ramps back down again over 100ms:
*
- * <code>
- * import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
+ * <pre>
+ * {@code import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
* import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
*
* VibrationEffect effect = VibrationEffect.startWaveform(targetFrequency(60))
* .addTransition(Duration.ofMillis(100), targetAmplitude(1), targetFrequency(120))
* .addSustain(Duration.ofMillis(200))
* .addTransition(Duration.ofMillis(100), targetAmplitude(0), targetFrequency(60))
- * .build();
- * </code>
+ * .build();}</pre>
*
* <p>The initial state of the waveform can be set via
* {@link VibrationEffect#startWaveform(VibrationParameter)} or
@@ -1169,8 +1166,8 @@
* a {@link VibrationEffect.Composition}. The resulting effect will have a tick followed by a
* repeated beating effect with a rise that stretches out and a sharp finish.
*
- * <code>
- * VibrationEffect patternToBeRepeated = VibrationEffect.startWaveform(targetAmplitude(0.2f))
+ * <pre>
+ * {@code VibrationEffect patternToRepeat = VibrationEffect.startWaveform(targetAmplitude(0.2f))
* .addSustain(Duration.ofMillis(10))
* .addTransition(Duration.ofMillis(20), targetAmplitude(0.4f))
* .addSustain(Duration.ofMillis(30))
@@ -1182,16 +1179,15 @@
* VibrationEffect effect = VibrationEffect.startComposition()
* .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
* .addOffDuration(Duration.ofMillis(20))
- * .repeatEffectIndefinitely(patternToBeRepeated)
- * .compose();
- * </code>
+ * .repeatEffectIndefinitely(patternToRepeat)
+ * .compose();}</pre>
*
* <p>The amplitude step waveforms that can be created via
* {@link VibrationEffect#createWaveform(long[], int[], int)} can also be created with
* {@link WaveformBuilder} by adding zero duration transitions:
*
- * <code>
- * // These two effects are the same
+ * <pre>
+ * {@code // These two effects are the same
* VibrationEffect waveform = VibrationEffect.createWaveform(
* new long[] { 10, 20, 30 }, // timings in milliseconds
* new int[] { 51, 102, 204 }, // amplitudes in [0,255]
@@ -1203,8 +1199,7 @@
* .addSustain(Duration.ofMillis(20))
* .addTransition(Duration.ZERO, targetAmplitude(0.8f))
* .addSustain(Duration.ofMillis(30))
- * .build();
- * </code>
+ * .build();}</pre>
*
* @see VibrationEffect#startWaveform
*/
@@ -1307,7 +1302,7 @@
/**
* Build the waveform as a single {@link VibrationEffect}.
*
- * The {@link WaveformBuilder} object is still valid after this call, so you can
+ * <p>The {@link WaveformBuilder} object is still valid after this call, so you can
* continue adding more primitives to it and generating more {@link VibrationEffect}s by
* calling this method again.
*
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 78f1cb1..7f0d634 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -83,7 +83,7 @@
/**
* Vibration effect support: unknown
*
- * The hardware doesn't report it's supported effects, so we can't determine whether the
+ * <p>The hardware doesn't report its supported effects, so we can't determine whether the
* effect is supported or not.
*/
public static final int VIBRATION_EFFECT_SUPPORT_UNKNOWN = 0;
@@ -91,14 +91,14 @@
/**
* Vibration effect support: supported
*
- * This effect is supported by the underlying hardware.
+ * <p>This effect is supported by the underlying hardware.
*/
public static final int VIBRATION_EFFECT_SUPPORT_YES = 1;
/**
* Vibration effect support: unsupported
*
- * This effect is <b>not</b> natively supported by the underlying hardware, although
+ * <p>This effect is <b>not</b> natively supported by the underlying hardware, although
* the system may still play a fallback vibration.
*/
public static final int VIBRATION_EFFECT_SUPPORT_NO = 2;
@@ -317,7 +317,7 @@
/**
* Vibrate constantly for the specified period of time.
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param milliseconds The number of milliseconds to vibrate.
* @deprecated Use {@link #vibrate(VibrationEffect)} instead.
@@ -331,7 +331,7 @@
/**
* Vibrate constantly for the specified period of time.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param milliseconds The number of milliseconds to vibrate.
@@ -368,7 +368,7 @@
* to start the repeat, or -1 to disable repeating.
* </p>
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param pattern an array of longs of times for which to turn the vibrator on or off.
* @param repeat the index into pattern at which to repeat, or -1 if
@@ -395,7 +395,7 @@
* to start the repeat, or -1 to disable repeating.
* </p>
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param pattern an array of longs of times for which to turn the vibrator on or off.
@@ -428,7 +428,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen.</p>
+ * <p>The app should be in the foreground for the vibration to happen.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
*/
@@ -440,7 +440,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
@@ -461,7 +461,7 @@
/**
* Vibrate with a given effect.
*
- * <p>The app should be in foreground for the vibration to happen. Background apps should
+ * <p>The app should be in the foreground for the vibration to happen. Background apps should
* specify a ringtone, notification or alarm usage in order to vibrate.</p>
*
* @param vibe {@link VibrationEffect} describing the vibration to be performed.
@@ -477,7 +477,7 @@
/**
* Like {@link #vibrate(VibrationEffect, VibrationAttributes)}, but allows the
- * caller to specify the vibration is owned by someone else and set reason for vibration.
+ * caller to specify the vibration is owned by someone else and set a reason for vibration.
*
* @hide
*/
@@ -519,7 +519,7 @@
}
/**
- * Query whether the vibrator supports all of the given effects.
+ * Query whether the vibrator supports all the given effects.
*
* <p>If an effect is not supported, the system may still automatically fall back to a simpler
* vibration instead, which is not optimised for the specific device, however vibration isn't
@@ -533,7 +533,7 @@
* vibration.
*
* <p>If the result is {@link #VIBRATION_EFFECT_SUPPORT_UNKNOWN}, the system doesn't know
- * whether all of the effects are supported. It may support any or all of the queried effects,
+ * whether all the effects are supported. It may support any or all of the queried effects,
* but there's no way to programmatically know whether a {@link #vibrate} call will successfully
* cause a vibration. It's guaranteed, however, that none of the queried effects are
* definitively unsupported by the hardware.
@@ -541,7 +541,7 @@
* <p>Use {@link #areEffectsSupported(int...)} to get individual results for each effect.
*
* @param effectIds Which effects to query for.
- * @return Whether all of the effects are natively supported by the device.
+ * @return Whether all the effects are natively supported by the device.
*/
@VibrationEffectSupport
public final int areAllEffectsSupported(
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 00ce14f..71ec096 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -35,7 +35,8 @@
/**
* A VibratorInfo describes the capabilities of a {@link Vibrator}.
*
- * This description includes its capabilities, list of supported effects and composition primitives.
+ * <p>This description includes its capabilities, list of supported effects and composition
+ * primitives.
*
* @hide
*/
diff --git a/core/java/android/os/VibratorManager.java b/core/java/android/os/VibratorManager.java
index c82a516..f506ef8 100644
--- a/core/java/android/os/VibratorManager.java
+++ b/core/java/android/os/VibratorManager.java
@@ -25,7 +25,7 @@
import android.util.Log;
/**
- * Class that provides access to all vibrators from the device, as well as the ability to run them
+ * Provides access to all vibrators from the device, as well as the ability to run them
* in a synchronized fashion.
* <p>
* If your process exits, any vibration you started will stop.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4e1337f..cc98339 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1538,6 +1538,8 @@
* be reserved for cached data depending on the device state which is then passed on
* to getStorageCacheBytes.
*
+ * Input File path must point to a storage volume.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
diff --git a/core/java/android/os/vibrator/VibratorFrequencyProfile.java b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
index 23b45ae..0f2aa15 100644
--- a/core/java/android/os/vibrator/VibratorFrequencyProfile.java
+++ b/core/java/android/os/vibrator/VibratorFrequencyProfile.java
@@ -61,8 +61,7 @@
* <p>The returned list will not be empty, and will have entries representing frequencies from
* {@link #getMinFrequency()} to {@link #getMaxFrequency()}, inclusive.
*
- * @return Array of maximum relative amplitude measurements, each value is between 0 and 1,
- * inclusive.
+ * @return Array of maximum relative amplitude measurements.
*/
@NonNull
@FloatRange(from = 0, to = 1)
diff --git a/core/java/android/service/autofill/OWNERS b/core/java/android/service/autofill/OWNERS
index a088632..9a30e82 100644
--- a/core/java/android/service/autofill/OWNERS
+++ b/core/java/android/service/autofill/OWNERS
@@ -1,9 +1,3 @@
# Bug component: 351486
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
-augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+include /core/java/android/view/autofill/OWNERS
diff --git a/core/java/android/service/contentcapture/OWNERS b/core/java/android/service/contentcapture/OWNERS
index 6337327..24561c5 100644
--- a/core/java/android/service/contentcapture/OWNERS
+++ b/core/java/android/service/contentcapture/OWNERS
@@ -1,9 +1,3 @@
# Bug component: 544200
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
-augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+include /core/java/android/view/contentcapture/OWNERS
diff --git a/core/java/android/service/contentsuggestions/OWNERS b/core/java/android/service/contentsuggestions/OWNERS
index 46b5ea0..72fe0b1 100644
--- a/core/java/android/service/contentsuggestions/OWNERS
+++ b/core/java/android/service/contentsuggestions/OWNERS
@@ -1,7 +1,2 @@
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
-augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+
+include /core/java/android/app/contentsuggestions/OWNERS
diff --git a/core/java/android/service/resumeonreboot/OWNERS b/core/java/android/service/resumeonreboot/OWNERS
index 3a127d5..721fbaf 100644
--- a/core/java/android/service/resumeonreboot/OWNERS
+++ b/core/java/android/service/resumeonreboot/OWNERS
@@ -1,2 +1 @@
-xunchang@google.com
-zhaojiac@google.com
+ejyzhang@google.com
\ No newline at end of file
diff --git a/core/java/android/service/textclassifier/OWNERS b/core/java/android/service/textclassifier/OWNERS
index a535f52..c85c69e 100644
--- a/core/java/android/service/textclassifier/OWNERS
+++ b/core/java/android/service/textclassifier/OWNERS
@@ -1,9 +1,3 @@
# Bug component: 709498
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
-augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+include /core/java/android/view/textclassifier/OWNERS
diff --git a/core/java/android/service/translation/OWNERS b/core/java/android/service/translation/OWNERS
index a1e663a..440f9a8 100644
--- a/core/java/android/service/translation/OWNERS
+++ b/core/java/android/service/translation/OWNERS
@@ -1,8 +1,3 @@
# Bug component: 994311
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+include /core/java/android/view/translation/OWNERS
diff --git a/core/java/android/service/voice/OWNERS b/core/java/android/service/voice/OWNERS
index 46b5ea0..59a0c2e 100644
--- a/core/java/android/service/voice/OWNERS
+++ b/core/java/android/service/voice/OWNERS
@@ -1,7 +1,3 @@
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
-augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+# Bug component: 533220
+
+include /core/java/android/app/assist/OWNERS
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index e075c05..832db91 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -17,6 +17,7 @@
package android.speech;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -38,7 +39,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import com.android.internal.R;
@@ -49,6 +49,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Queue;
+import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
/**
@@ -206,10 +207,9 @@
handleSetTemporaryComponent((ComponentName) msg.obj);
break;
case MSG_CHECK_RECOGNITION_SUPPORT:
- Pair<Intent, RecognitionSupportCallback> intentAndListener =
- (Pair<Intent, RecognitionSupportCallback>) msg.obj;
+ CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj;
handleCheckRecognitionSupport(
- intentAndListener.first, intentAndListener.second);
+ args.mIntent, args.mCallbackExecutor, args.mCallback);
break;
case MSG_TRIGGER_MODEL_DOWNLOAD:
handleTriggerModelDownload((Intent) msg.obj);
@@ -492,6 +492,7 @@
*/
public void checkRecognitionSupport(
@NonNull Intent recognizerIntent,
+ @NonNull @CallbackExecutor Executor executor,
@NonNull RecognitionSupportCallback supportListener) {
Objects.requireNonNull(recognizerIntent, "intent must not be null");
Objects.requireNonNull(supportListener, "listener must not be null");
@@ -508,13 +509,13 @@
connectToSystemService();
}
putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
- Pair.create(recognizerIntent, supportListener)));
+ new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener)));
}
/**
* Attempts to download the support for the given {@code recognizerIntent}. This might trigger
* user interaction to approve the download. Callers can verify the status of the request via
- * {@link #checkRecognitionSupport(Intent, RecognitionSupportCallback)}.
+ * {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}.
*
* @param recognizerIntent contains parameters for the recognition to be performed. The intent
* may also contain optional extras, see {@link RecognizerIntent}.
@@ -625,18 +626,20 @@
}
private void handleCheckRecognitionSupport(
- Intent recognizerIntent, RecognitionSupportCallback recognitionSupportCallback) {
+ Intent recognizerIntent,
+ Executor callbackExecutor,
+ RecognitionSupportCallback recognitionSupportCallback) {
if (!maybeInitializeManagerService()) {
return;
}
try {
mService.checkRecognitionSupport(
recognizerIntent,
- new InternalSupportCallback(recognitionSupportCallback));
+ new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
if (DBG) Log.d(TAG, "service support command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "checkRecognitionSupport() failed", e);
- mListener.onError(ERROR_CLIENT);
+ callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT));
}
}
@@ -780,6 +783,21 @@
return ComponentName.unflattenFromString(serviceComponent);
}
+ private static class CheckRecognitionSupportArgs {
+ final Intent mIntent;
+ final Executor mCallbackExecutor;
+ final RecognitionSupportCallback mCallback;
+
+ private CheckRecognitionSupportArgs(
+ Intent intent,
+ Executor callbackExecutor,
+ RecognitionSupportCallback callback) {
+ mIntent = intent;
+ mCallbackExecutor = callbackExecutor;
+ mCallback = callback;
+ }
+ }
+
/**
* Internal wrapper of IRecognitionListener which will propagate the results to
* RecognitionListener
@@ -890,40 +908,22 @@
}
private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub {
+ private final Executor mExecutor;
private final RecognitionSupportCallback mCallback;
- private static final int MSG_SUPPORT_RESULT = 1;
- private static final int MSG_ERROR = 2;
-
- private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- if (mCallback == null) {
- return;
- }
- switch (msg.what) {
- case MSG_SUPPORT_RESULT:
- mCallback.onSupportResult((RecognitionSupport) msg.obj);
- break;
- case MSG_ERROR:
- mCallback.onError((Integer) msg.obj);
- break;
- }
- }
- };
-
- private InternalSupportCallback(RecognitionSupportCallback callback) {
+ private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) {
+ this.mExecutor = executor;
this.mCallback = callback;
}
@Override
public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_SUPPORT_RESULT, recognitionSupport).sendToTarget();
+ mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport));
}
@Override
public void onError(int errorCode) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ERROR, errorCode).sendToTarget();
+ mExecutor.execute(() -> mCallback.onError(errorCode));
}
}
}
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 748d551..bedd409 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -287,6 +287,16 @@
}
/**
+ * Retrieves the font metrics for the given range.
+ *
+ * This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
+ */
+ public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @NonNull Paint.FontMetricsInt fmi) {
+ mMeasuredText.getFontMetricsInt(start, end, fmi);
+ }
+
+ /**
* Returns a width of the character at the offset.
*
* This is available only if the MeasuredParagraph is computed with buildForStaticLayout.
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index be66db2..9307e56 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -21,6 +21,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.MeasuredText;
@@ -697,6 +698,38 @@
}
/**
+ * Retrieves the text font metrics for the given range.
+ * Both {@code start} and {@code end} offset need to be in the same paragraph, otherwise
+ * IllegalArgumentException will be thrown.
+ *
+ * @param start the inclusive start offset in the text
+ * @param end the exclusive end offset in the text
+ * @param outMetrics the output font metrics
+ * @throws IllegalArgumentException if start and end offset are in the different paragraph.
+ */
+ public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @NonNull Paint.FontMetricsInt outMetrics) {
+ Preconditions.checkArgument(0 <= start && start <= mText.length(), "invalid start offset");
+ Preconditions.checkArgument(0 <= end && end <= mText.length(), "invalid end offset");
+ Preconditions.checkArgument(start <= end, "start offset can not be larger than end offset");
+ Objects.requireNonNull(outMetrics);
+ if (start == end) {
+ mParams.getTextPaint().getFontMetricsInt(outMetrics);
+ return;
+ }
+ final int paraIndex = findParaIndex(start);
+ final int paraStart = getParagraphStart(paraIndex);
+ final int paraEnd = getParagraphEnd(paraIndex);
+ if (start < paraStart || paraEnd < end) {
+ throw new IllegalArgumentException("Cannot measured across the paragraph:"
+ + "para: (" + paraStart + ", " + paraEnd + "), "
+ + "request: (" + start + ", " + end + ")");
+ }
+ getMeasuredParagraph(paraIndex).getFontMetricsInt(start - paraStart,
+ end - paraStart, outMetrics);
+ }
+
+ /**
* Returns a width of a character at offset
*
* @param offset an offset of the text.
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 49e2111..e39231c 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -866,8 +866,12 @@
wp.getFontMetricsInt(mChars, start, count, contextStart, contextCount, runIsRtl,
fmi);
} else {
- wp.getFontMetricsInt(mText, mStart + start, count, mStart + contextStart, contextCount,
- runIsRtl, fmi);
+ if (mComputed == null) {
+ wp.getFontMetricsInt(mText, mStart + start, count, mStart + contextStart,
+ contextCount, runIsRtl, fmi);
+ } else {
+ mComputed.getFontMetricsInt(mStart + start, mStart + end, fmi);
+ }
}
updateMetrics(fmi, previousTop, previousAscent, previousDescent, previousBottom,
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 048b94f..188bc3f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -67,6 +67,13 @@
public static final String SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME =
"settings_app_allow_dark_theme_activation_at_bedtime";
+ /**
+ * Hide back key in the Settings two pane design.
+ * @hide
+ */
+ public static final String SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE =
+ "settings_hide_secondary_page_back_button_in_two_pane";
+
private static final Map<String, String> DEFAULT_FLAGS;
static {
@@ -92,6 +99,7 @@
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_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
@@ -101,6 +109,7 @@
PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
+ PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE);
}
/**
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index b8eb602..8e3cc34 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -499,9 +499,9 @@
*
* @param callback The extended frame callback to run during the next frame.
*
- * @see #removeExtendedFrameCallback
+ * @see #removeVsyncCallback
*/
- public void postExtendedFrameCallback(@NonNull ExtendedFrameCallback callback) {
+ public void postVsyncCallback(@NonNull VsyncCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
@@ -603,9 +603,9 @@
*
* @param callback The extended frame callback to remove.
*
- * @see #postExtendedFrameCallback
+ * @see #postVsyncCallback
*/
- public void removeExtendedFrameCallback(@Nullable ExtendedFrameCallback callback) {
+ public void removeVsyncCallback(@Nullable VsyncCallback callback) {
if (callback == null) {
throw new IllegalArgumentException("callback must not be null");
}
@@ -1021,7 +1021,7 @@
* The time in {@link System#nanoTime()} timebase which this frame is expected to be
* presented.
*/
- public long getExpectedPresentTimeNanos() {
+ public long getExpectedPresentationTimeNanos() {
return mExpectedPresentTimeNanos;
}
@@ -1034,7 +1034,7 @@
}
/**
- * The payload for {@link ExtendedFrameCallback} which includes frame information such as when
+ * The payload for {@link VsyncCallback} which includes frame information such as when
* the frame started being rendered, and multiple possible frame timelines and their
* information including deadline and expected present time.
*/
@@ -1101,7 +1101,7 @@
*
* @see FrameCallback
*/
- public interface ExtendedFrameCallback {
+ public interface VsyncCallback {
/**
* Called when a new display frame is being rendered.
*
@@ -1214,7 +1214,7 @@
void run(FrameData frameData) {
if (token == EXTENDED_FRAME_CALLBACK_TOKEN) {
- ((ExtendedFrameCallback) action).onVsync(frameData);
+ ((VsyncCallback) action).onVsync(frameData);
} else {
run(frameData.getFrameTimeNanos());
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 36baa04..ce21086 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,7 +65,7 @@
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
/**
* System private interface to the window manager.
@@ -926,21 +926,21 @@
* registered, the registered callback will not be unregistered until
* {@link unregisterTaskFpsCallback()} is called
* @param taskId task id of the task.
- * @param listener listener to be registered.
+ * @param callback callback to be registered.
*
* @hide
*/
- void registerTaskFpsCallback(in int taskId, in IOnFpsCallbackListener listener);
+ void registerTaskFpsCallback(in int taskId, in ITaskFpsCallback callback);
/**
* Unregisters the frame rate per second count callback which was registered with
* {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
*
- * @param listener listener to be unregistered.
+ * @param callback callback to be unregistered.
*
* @hide
*/
- void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
+ void unregisterTaskFpsCallback(in ITaskFpsCallback listener);
/**
* Take a snapshot using the same path that's used for Recents. This is used for Testing only.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ce54968..c08177e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -46,10 +46,13 @@
import android.gui.DropInputMode;
import android.hardware.DataSpace;
import android.hardware.HardwareBuffer;
+import android.hardware.SyncFence;
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSync;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
@@ -209,7 +212,7 @@
private static native void nativeReparent(long transactionObj, long nativeObject,
long newParentNativeObject);
private static native void nativeSetBuffer(long transactionObj, long nativeObject,
- HardwareBuffer buffer);
+ HardwareBuffer buffer, long fencePtr);
private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
int transform);
private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -3692,8 +3695,44 @@
*/
public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
@Nullable HardwareBuffer buffer) {
+ return setBuffer(sc, buffer, null);
+ }
+
+ /**
+ * Updates the HardwareBuffer displayed for the SurfaceControl.
+ *
+ * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
+ * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
+ * be composited using either an overlay or using the GPU.
+ *
+ * A presentation fence may be passed to improve performance by allowing the buffer
+ * to complete rendering while it is waiting for the transaction to be applied.
+ * For example, if the buffer is being produced by rendering with OpenGL ES then
+ * a fence created with
+ * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
+ * used to allow the GPU rendering to be concurrent with the transaction. The compositor
+ * will wait for the fence to be signaled before the buffer is displayed. If multiple
+ * buffers are set as part of the same transaction, the presentation fences of all of them
+ * must signal before any buffer is displayed. That is, the entire transaction is delayed
+ * until all presentation fences have signaled, ensuring the transaction remains consistent.
+ *
+ * @param sc The SurfaceControl to update
+ * @param buffer The buffer to be displayed
+ * @param fence The presentation fence. If null or invalid, this is equivalent to
+ * {@link #setBuffer(SurfaceControl, HardwareBuffer)}
+ * @return this
+ */
+ public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
+ @Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
checkPreconditions(sc);
- nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer);
+ if (fence != null) {
+ synchronized (fence.getLock()) {
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
+ fence.getNativeFence());
+ }
+ } else {
+ nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
+ }
return this;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 179f6ee..4dc1fca 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11785,7 +11785,10 @@
* user and that ideally it should not be covered. Setting this is only appropriate for UI
* where the user would likely take action to uncover it.
* <p>
- * The system will try to respect this, but when not possible will ignore it.
+ * The system will try to respect this preference, but when not possible will ignore it.
+ * <p>
+ * Note: while this is set to {@code true}, the system will ignore the {@code Rect}s provided
+ * through {@link #setPreferKeepClearRects} (but not clear them).
* <p>
* @see #setPreferKeepClearRects
* @see #isPreferKeepClear
@@ -11817,11 +11820,11 @@
* user and that ideally they should not be covered. Setting this is only appropriate for UI
* where the user would likely take action to uncover it.
* <p>
- * If the whole view is preferred to be clear ({@link #isPreferKeepClear}), the rects set here
- * will be ignored.
- * <p>
* The system will try to respect this preference, but when not possible will ignore it.
* <p>
+ * Note: While {@link #isPreferKeepClear} is {@code true}, the {@code Rect}s set here are
+ * ignored.
+ * <p>
* @see #setPreferKeepClear
* @see #getPreferKeepClearRects
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8236fbb..8444032 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1201,7 +1201,7 @@
mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
setFrame(mTmpFrames.frame);
registerBackCallbackOnWindow();
- if (WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// For apps requesting legacy back behavior, we add a compat callback that
// dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
// This way from system point of view, these apps are providing custom
@@ -6507,7 +6507,7 @@
if (isBack(event)
&& mContext != null
- && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+ && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
// Invoke the appropriate {@link OnBackInvokedCallback} if the new back
// navigation should be used, and the key event is not handled by anything else.
OnBackInvokedCallback topCallback =
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 771d40b..1c27046 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4865,21 +4865,24 @@
* Registers the frame rate per second count callback for one given task ID.
* Each callback can only register for receiving FPS callback for one task id until unregister
* is called. If there's no task associated with the given task id,
- * {@link IllegalArgumentException} will be thrown. If a task id destroyed after a callback is
- * registered, the registered callback will not be unregistered until
- * {@link #unregisterTaskFpsCallback(TaskFpsCallback))} is called
+ * {@link IllegalArgumentException} will be thrown. Registered callbacks should always be
+ * unregistered via {@link #unregisterTaskFpsCallback(TaskFpsCallback)}
+ * even when the task id has been destroyed.
+ *
* @param taskId task id of the task.
+ * @param executor Executor to execute the callback.
* @param callback callback to be registered.
*
* @hide
*/
@SystemApi
default void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
+ @NonNull Executor executor,
@NonNull TaskFpsCallback callback) {}
/**
* Unregisters the frame rate per second count callback which was registered with
- * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
+ * {@link #registerTaskFpsCallback(Executor, int, TaskFpsCallback)}.
*
* @param callback callback to be unregistered.
*
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f4353eb..20cdad4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -39,14 +39,18 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
+import android.window.ITaskFpsCallback;
import android.window.TaskFpsCallback;
import android.window.WindowContext;
import android.window.WindowProvider;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -99,6 +103,10 @@
@Nullable
private final IBinder mWindowContextToken;
+ @GuardedBy("mOnFpsCallbackListenerProxies")
+ private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies =
+ new ArrayList<>();
+
public WindowManagerImpl(Context context) {
this(context, null /* parentWindow */, null /* clientToken */);
}
@@ -424,20 +432,56 @@
}
@Override
- public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, TaskFpsCallback callback) {
+ public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, @NonNull Executor executor,
+ TaskFpsCallback callback) {
+ final OnFpsCallbackListenerProxy onFpsCallbackListenerProxy =
+ new OnFpsCallbackListenerProxy(executor, callback);
try {
WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback(
- taskId, callback.getListener());
+ taskId, onFpsCallbackListenerProxy);
} catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ synchronized (mOnFpsCallbackListenerProxies) {
+ mOnFpsCallbackListenerProxies.add(onFpsCallbackListenerProxy);
}
}
@Override
public void unregisterTaskFpsCallback(TaskFpsCallback callback) {
- try {
- WindowManagerGlobal.getWindowManagerService().unregisterTaskFpsCallback(
- callback.getListener());
- } catch (RemoteException e) {
+ synchronized (mOnFpsCallbackListenerProxies) {
+ final Iterator<OnFpsCallbackListenerProxy> iterator =
+ mOnFpsCallbackListenerProxies.iterator();
+ while (iterator.hasNext()) {
+ final OnFpsCallbackListenerProxy proxy = iterator.next();
+ if (proxy.mCallback == callback) {
+ try {
+ WindowManagerGlobal.getWindowManagerService()
+ .unregisterTaskFpsCallback(proxy);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ private static class OnFpsCallbackListenerProxy
+ extends ITaskFpsCallback.Stub {
+ private final Executor mExecutor;
+ private final TaskFpsCallback mCallback;
+
+ private OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void onFpsReported(float fps) {
+ mExecutor.execute(() -> {
+ mCallback.onFpsReported(fps);
+ });
}
}
diff --git a/core/java/android/view/autofill/OWNERS b/core/java/android/view/autofill/OWNERS
index a088632..108c42c 100644
--- a/core/java/android/view/autofill/OWNERS
+++ b/core/java/android/view/autofill/OWNERS
@@ -1,9 +1,7 @@
# Bug component: 351486
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+joannechung@google.com
+markpun@google.com
+lpeter@google.com
+tymtsai@google.com
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index ad48ea0..48d2970 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -218,6 +218,7 @@
public static final boolean DEBUG = false;
/** @hide */
+ @TestApi
public static final String DUMPABLE_NAME = "ContentCaptureManager";
/** Error happened during the data sharing session. */
diff --git a/core/java/android/view/contentcapture/OWNERS b/core/java/android/view/contentcapture/OWNERS
index 6337327..1a5cb1e4 100644
--- a/core/java/android/view/contentcapture/OWNERS
+++ b/core/java/android/view/contentcapture/OWNERS
@@ -1,9 +1,7 @@
# Bug component: 544200
-joannechung@google.com
-adamhe@google.com
-tymtsai@google.com
-lpeter@google.com
augale@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
+joannechung@google.com
+markpun@google.com
+lpeter@google.com
+tymtsai@google.com
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 08cc31c..69ad739 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -391,22 +391,6 @@
public void changeInputMethodSubtype(InputMethodSubtype subtype);
/**
- * Update token of the client window requesting {@link #showSoftInput(int, ResultReceiver)}
- * @param showInputToken placeholder app window token for window requesting
- * {@link InputMethodManager#showSoftInput(View, int)}
- * @hide
- */
- public void setCurrentShowInputToken(IBinder showInputToken);
-
- /**
- * Update token of the client window requesting {@link #hideSoftInput(int, ResultReceiver)}
- * @param hideInputToken placeholder app window token for window requesting
- * {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}
- * @hide
- */
- public void setCurrentHideInputToken(IBinder hideInputToken);
-
- /**
* Checks if IME is ready to start stylus handwriting session.
* If yes, {@link #startStylusHandwriting(InputChannel, List)} is called.
* @param requestId
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 9a70667..d7c1846 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -64,6 +64,7 @@
* @attr ref android.R.styleable#InputMethod_isDefault
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
* @attr ref android.R.styleable#InputMethod_supportsInlineSuggestions
+ * @attr ref android.R.styleable#InputMethod_supportsInlineSuggestionsWithTouchExploration
* @attr ref android.R.styleable#InputMethod_suppressesSpellChecker
* @attr ref android.R.styleable#InputMethod_showInInputMethodPicker
* @attr ref android.R.styleable#InputMethod_configChanges
@@ -125,6 +126,11 @@
private final boolean mInlineSuggestionsEnabled;
/**
+ * The flag whether this IME supports inline suggestions when touch exploration is enabled.
+ */
+ private final boolean mSupportsInlineSuggestionsWithTouchExploration;
+
+ /**
* The flag whether this IME suppresses spell checker.
*/
private final boolean mSuppressesSpellChecker;
@@ -189,6 +195,7 @@
boolean isAuxIme = true;
boolean supportsSwitchingToNextInputMethod = false; // false as default
boolean inlineSuggestionsEnabled = false; // false as default
+ boolean supportsInlineSuggestionsWithTouchExploration = false; // false as default
boolean suppressesSpellChecker = false; // false as default
boolean showInInputMethodPicker = true; // true as default
mForceDefault = false;
@@ -234,6 +241,9 @@
false);
inlineSuggestionsEnabled = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsInlineSuggestions, false);
+ supportsInlineSuggestionsWithTouchExploration = sa.getBoolean(
+ com.android.internal.R.styleable
+ .InputMethod_supportsInlineSuggestionsWithTouchExploration, false);
suppressesSpellChecker = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_suppressesSpellChecker, false);
showInInputMethodPicker = sa.getBoolean(
@@ -314,6 +324,8 @@
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
+ mSupportsInlineSuggestionsWithTouchExploration =
+ supportsInlineSuggestionsWithTouchExploration;
mSuppressesSpellChecker = suppressesSpellChecker;
mShowInInputMethodPicker = showInInputMethodPicker;
mIsVrOnly = isVrOnly;
@@ -326,6 +338,7 @@
mIsAuxIme = source.readInt() == 1;
mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
mInlineSuggestionsEnabled = source.readInt() == 1;
+ mSupportsInlineSuggestionsWithTouchExploration = source.readInt() == 1;
mSuppressesSpellChecker = source.readBoolean();
mShowInInputMethodPicker = source.readBoolean();
mIsVrOnly = source.readBoolean();
@@ -345,7 +358,8 @@
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
- 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */);
+ 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */,
+ false /* inlineSuggestionsEnabled */);
}
/**
@@ -360,7 +374,8 @@
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
false /* inlineSuggestionsEnabled */, false /* isVrOnly */, handledConfigChanges,
- false /* supportsStylusHandwriting */);
+ false /* supportsStylusHandwriting */,
+ false /* inlineSuggestionsEnabled */);
}
/**
@@ -373,7 +388,8 @@
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
true /* supportsSwitchingToNextInputMethod */, false /* inlineSuggestionsEnabled */,
false /* isVrOnly */, 0 /* handledconfigChanges */,
- false /* supportsStylusHandwriting */);
+ false /* supportsStylusHandwriting */,
+ false /* inlineSuggestionsEnabled */);
}
/**
@@ -385,7 +401,8 @@
boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
supportsSwitchingToNextInputMethod, false /* inlineSuggestionsEnabled */, isVrOnly,
- 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */);
+ 0 /* handledConfigChanges */, false /* supportsStylusHandwriting */,
+ false /* inlineSuggestionsEnabled */);
}
/**
@@ -395,7 +412,8 @@
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
boolean supportsSwitchingToNextInputMethod, boolean inlineSuggestionsEnabled,
- boolean isVrOnly, int handledConfigChanges, boolean supportsStylusHandwriting) {
+ boolean isVrOnly, int handledConfigChanges, boolean supportsStylusHandwriting,
+ boolean supportsInlineSuggestionsWithTouchExploration) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -406,6 +424,8 @@
mForceDefault = forceDefault;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
mInlineSuggestionsEnabled = inlineSuggestionsEnabled;
+ mSupportsInlineSuggestionsWithTouchExploration =
+ supportsInlineSuggestionsWithTouchExploration;
mSuppressesSpellChecker = false;
mShowInInputMethodPicker = true;
mIsVrOnly = isVrOnly;
@@ -583,6 +603,8 @@
+ " mIsVrOnly=" + mIsVrOnly
+ " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
+ " mInlineSuggestionsEnabled=" + mInlineSuggestionsEnabled
+ + " mSupportsInlineSuggestionsWithTouchExploration="
+ + mSupportsInlineSuggestionsWithTouchExploration
+ " mSuppressesSpellChecker=" + mSuppressesSpellChecker
+ " mShowInInputMethodPicker=" + mShowInInputMethodPicker
+ " mSupportsStylusHandwriting=" + mSupportsStylusHandwriting);
@@ -654,6 +676,15 @@
}
/**
+ * Returns {@code true} if this input method supports inline suggestions when touch exploration
+ * is enabled.
+ * @hide
+ */
+ public boolean supportsInlineSuggestionsWithTouchExploration() {
+ return mSupportsInlineSuggestionsWithTouchExploration;
+ }
+
+ /**
* Return {@code true} if this input method suppresses spell checker.
*/
public boolean suppressesSpellChecker() {
@@ -683,6 +714,7 @@
dest.writeInt(mIsAuxIme ? 1 : 0);
dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
dest.writeInt(mInlineSuggestionsEnabled ? 1 : 0);
+ dest.writeInt(mSupportsInlineSuggestionsWithTouchExploration ? 1 : 0);
dest.writeBoolean(mSuppressesSpellChecker);
dest.writeBoolean(mShowInInputMethodPicker);
dest.writeBoolean(mIsVrOnly);
diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS
index d7db7c7..9fa7e8f 100644
--- a/core/java/android/view/inputmethod/OWNERS
+++ b/core/java/android/view/inputmethod/OWNERS
@@ -3,4 +3,4 @@
include /services/core/java/com/android/server/inputmethod/OWNERS
-per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS
+per-file *InlineSuggestion* = file:/core/java/android/view/autofill/OWNERS
diff --git a/core/java/android/view/textclassifier/OWNERS b/core/java/android/view/textclassifier/OWNERS
index 4bcdeea..a205be2 100644
--- a/core/java/android/view/textclassifier/OWNERS
+++ b/core/java/android/view/textclassifier/OWNERS
@@ -2,8 +2,6 @@
mns@google.com
toki@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
augale@google.com
joannechung@google.com
tonymak@google.com
diff --git a/core/java/android/view/textclassifier/logging/OWNERS b/core/java/android/view/textclassifier/logging/OWNERS
deleted file mode 100644
index ac80d9f..0000000
--- a/core/java/android/view/textclassifier/logging/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Bug component: 709498
-
-mns@google.com
-toki@google.com
-svetoslavganov@android.com
-svetoslavganov@google.com
-augale@google.com
-joannechung@google.com
diff --git a/core/java/android/view/translation/OWNERS b/core/java/android/view/translation/OWNERS
index a1e663a..b772ad3 100644
--- a/core/java/android/view/translation/OWNERS
+++ b/core/java/android/view/translation/OWNERS
@@ -1,8 +1,7 @@
# Bug component: 994311
-adamhe@google.com
augale@google.com
joannechung@google.com
+markpun@google.com
lpeter@google.com
-svetoslavganov@google.com
tymtsai@google.com
diff --git a/core/java/android/widget/inline/OWNERS b/core/java/android/widget/inline/OWNERS
new file mode 100644
index 0000000..9a30e82
--- /dev/null
+++ b/core/java/android/widget/inline/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 351486
+
+include /core/java/android/view/autofill/OWNERS
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/window/ITaskFpsCallback.aidl
similarity index 95%
rename from core/java/android/window/IOnFpsCallbackListener.aidl
rename to core/java/android/window/ITaskFpsCallback.aidl
index 3091df3..aee403e9 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/window/ITaskFpsCallback.aidl
@@ -19,7 +19,7 @@
/**
* @hide
*/
-oneway interface IOnFpsCallbackListener {
+oneway interface ITaskFpsCallback {
/**
* Reports the fps from the registered task
diff --git a/core/java/android/window/TaskFpsCallback.java b/core/java/android/window/TaskFpsCallback.java
index a8e01b6..19b9f28 100644
--- a/core/java/android/window/TaskFpsCallback.java
+++ b/core/java/android/window/TaskFpsCallback.java
@@ -21,8 +21,6 @@
import android.annotation.SystemApi;
import android.os.RemoteException;
-import java.util.concurrent.Executor;
-
/**
* Callback for sampling the frames per second for a task and its children.
* This should only be used by a system component that needs to listen to a task's
@@ -30,44 +28,19 @@
* Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
*
* Each callback can only register for receiving FPS report for one task id until
- * {@link WindowManager#unregister()} is called.
+ * {@link WindowManager#unregisterTaskFpsCallback()} is called.
*
* @hide
*/
@SystemApi
-public final class TaskFpsCallback {
+public abstract class TaskFpsCallback {
/**
- * Listener interface to receive frame per second of a task.
+ * Reports the fps from the registered task
+ * @param fps The frame per second of the task that has the registered task id
+ * and its children.
*/
- public interface OnFpsCallbackListener {
- /**
- * Reports the fps from the registered task
- * @param fps The frame per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(float fps);
- }
-
- private final IOnFpsCallbackListener mListener;
-
- public TaskFpsCallback(@NonNull Executor executor, @NonNull OnFpsCallbackListener listener) {
- mListener = new IOnFpsCallbackListener.Stub() {
- @Override
- public void onFpsReported(float fps) {
- executor.execute(() -> {
- listener.onFpsReported(fps);
- });
- }
- };
- }
-
- /**
- * @hide
- */
- public IOnFpsCallbackListener getListener() {
- return mListener;
- }
+ public abstract void onFpsReported(float fps);
/**
* Dispatch the collected sample.
@@ -76,7 +49,7 @@
*/
@BinderThread
private static void dispatchOnFpsReported(
- @NonNull IOnFpsCallbackListener listener, float fps) {
+ @NonNull ITaskFpsCallback listener, float fps) {
try {
listener.onFpsReported(fps);
} catch (RemoteException e) {
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 62292f97..0503c40 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -19,9 +19,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.compat.CompatChanges;
+import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.text.TextUtils;
import android.util.Log;
import android.view.IWindow;
import android.view.IWindowSession;
@@ -50,10 +52,9 @@
private IWindowSession mWindowSession;
private IWindow mWindow;
private static final String TAG = "WindowOnBackDispatcher";
- private static final boolean DEBUG = false;
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<>();
@@ -227,10 +228,23 @@
*
* Legacy back behavior dispatches KEYCODE_BACK instead of invoking the application registered
* {@link android.view.OnBackInvokedCallback}.
- *
*/
- public static boolean shouldUseLegacyBack() {
- return !CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME)
- || !IS_BACK_PREDICTABILITY_ENABLED;
+ public static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) {
+ // new back is enabled if the app targets T AND the feature flag is enabled AND the app
+ // does not explicitly request legacy back.
+ boolean targetsT = CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME);
+ boolean featureFlagEnabled = IS_BACK_PREDICTABILITY_ENABLED;
+ // If the context is null, we assume true and fallback on the two other conditions.
+ boolean appRequestsLegacy =
+ context == null || !context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
+
+ if (DEBUG) {
+ Log.d(TAG, TextUtils.formatSimple("App: %s isChangeEnabled=%s featureFlagEnabled=%s "
+ + "onBackInvokedEnabled=%s",
+ context != null ? context.getApplicationInfo().packageName : "null context",
+ targetsT, featureFlagEnabled, !appRequestsLegacy));
+ }
+
+ return targetsT && featureFlagEnabled && !appRequestsLegacy;
}
}
diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java
index 0443ad0..0835824 100644
--- a/core/java/com/android/internal/infra/AndroidFuture.java
+++ b/core/java/com/android/internal/infra/AndroidFuture.java
@@ -455,7 +455,14 @@
if (mSourceU != null) {
// T done
mResultT = (T) res;
- mSourceU.whenComplete(this);
+
+ // Subscribe to the second job completion.
+ mSourceU.whenComplete((r, e) -> {
+ // Mark the first job completion by setting mSourceU to null, so that next time
+ // the execution flow goes to the else case below.
+ mSourceU = null;
+ accept(r, e);
+ });
} else {
// U done
try {
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index b32a6b0..1eb446e 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -249,7 +249,7 @@
dump.write("is_power_transfer_limited", UsbPortStatusProto.IS_POWER_TRANSFER_LIMITED,
status.isPowerTransferLimited());
dump.write("usb_power_brick_status", UsbPortStatusProto.USB_POWER_BRICK_STATUS,
- UsbPort.powerBrickStatusToString(status.getPowerBrickStatus()));
+ UsbPort.powerBrickConnectionStatusToString(status.getPowerBrickConnectionStatus()));
dump.end(token);
}
}
diff --git a/core/java/com/android/internal/util/PerfettoTrigger.java b/core/java/com/android/internal/util/PerfettoTrigger.java
index c758504..f3af528 100644
--- a/core/java/com/android/internal/util/PerfettoTrigger.java
+++ b/core/java/com/android/internal/util/PerfettoTrigger.java
@@ -18,6 +18,7 @@
import android.os.SystemClock;
import android.util.Log;
+import android.util.SparseLongArray;
import java.io.IOException;
@@ -28,8 +29,9 @@
public class PerfettoTrigger {
private static final String TAG = "PerfettoTrigger";
private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
- private static final long THROTTLE_MILLIS = 60000;
- private static volatile long sLastTriggerTime = -THROTTLE_MILLIS;
+ private static final long THROTTLE_MILLIS = 300000;
+ private static final SparseLongArray sLastInvocationPerTrigger = new SparseLongArray(100);
+ private static final Object sLock = new Object();
/**
* @param triggerName The name of the trigger. Must match the value defined in the AOT
@@ -38,18 +40,23 @@
public static void trigger(String triggerName) {
// Trace triggering has a non-negligible cost (fork+exec).
// To mitigate potential excessive triggering by the API client we ignore calls that happen
- // too quickl after the most recent trigger.
- long sinceLastTrigger = SystemClock.elapsedRealtime() - sLastTriggerTime;
- if (sinceLastTrigger < THROTTLE_MILLIS) {
- Log.v(TAG, "Not triggering " + triggerName + " - not enough time since last trigger");
- return;
+ // too quickly after the most recent trigger.
+ synchronized (sLock) {
+ long lastTrigger = sLastInvocationPerTrigger.get(triggerName.hashCode());
+ long sinceLastTrigger = SystemClock.elapsedRealtime() - lastTrigger;
+ if (sinceLastTrigger < THROTTLE_MILLIS) {
+ Log.v(TAG, "Not triggering " + triggerName
+ + " - not enough time since last trigger");
+ return;
+ }
+
+ sLastInvocationPerTrigger.put(triggerName.hashCode(), SystemClock.elapsedRealtime());
}
try {
ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
Log.v(TAG, "Triggering " + String.join(" ", pb.command()));
pb.start();
- sLastTriggerTime = SystemClock.elapsedRealtime();
} catch (IOException e) {
Log.w(TAG, "Failed to trigger " + triggerName, e);
}
diff --git a/core/java/com/android/internal/util/UserIcons.java b/core/java/com/android/internal/util/UserIcons.java
index 17b84ff..d9c1e57 100644
--- a/core/java/com/android/internal/util/UserIcons.java
+++ b/core/java/com/android/internal/util/UserIcons.java
@@ -46,11 +46,21 @@
* Converts a given drawable to a bitmap.
*/
public static Bitmap convertToBitmap(Drawable icon) {
+ return convertToBitmapAtSize(icon, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
+ }
+
+ /**
+ * Converts a given drawable to a bitmap, with width and height equal to the default icon size.
+ */
+ public static Bitmap convertToBitmapAtUserIconSize(Resources res, Drawable icon) {
+ int size = res.getDimensionPixelSize(R.dimen.user_icon_size);
+ return convertToBitmapAtSize(icon, size, size);
+ }
+
+ private static Bitmap convertToBitmapAtSize(Drawable icon, int width, int height) {
if (icon == null) {
return null;
}
- final int width = icon.getIntrinsicWidth();
- final int height = icon.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
icon.setBounds(0, 0, width, height);
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index cfb2bf9..869da1f 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -20,15 +20,14 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.ContentObserver;
-import android.graphics.Point;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.Display;
import android.view.IWindowManager;
import android.view.Surface;
import android.view.WindowManagerGlobal;
@@ -73,19 +72,16 @@
* otherwise Configuration.ORIENTATION_UNDEFINED if any orientation is lockable.
*/
public static int getRotationLockOrientation(Context context) {
- if (!areAllRotationsAllowed(context)) {
- final Point size = new Point();
- final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
- try {
- final int displayId = context.getDisplayId();
- wm.getInitialDisplaySize(displayId, size);
- return size.x < size.y ?
- Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to get the display size");
- }
+ if (areAllRotationsAllowed(context)) {
+ return Configuration.ORIENTATION_UNDEFINED;
}
- return Configuration.ORIENTATION_UNDEFINED;
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ final int rotation =
+ context.getResources().getConfiguration().windowConfiguration.getRotation();
+ final boolean rotated = rotation % 2 != 0;
+ final int w = rotated ? metrics.heightPixels : metrics.widthPixels;
+ final int h = rotated ? metrics.widthPixels : metrics.heightPixels;
+ return w < h ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
}
/**
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 78bb53d..5fa4a65 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -150,6 +150,7 @@
private Icon mShortcutIcon;
private View mAppNameDivider;
private TouchDelegateComposite mTouchDelegate = new TouchDelegateComposite(this);
+ private ArrayList<MessagingGroup> mToRecycle = new ArrayList<>();
public ConversationLayout(@NonNull Context context) {
super(context);
@@ -472,6 +473,12 @@
updateTitleAndNamesDisplay();
updateConversationLayout();
+
+ // Recycle everything at the end of the update, now that we know it's no longer needed.
+ for (MessagingGroup group : mToRecycle) {
+ group.recycle();
+ }
+ mToRecycle.clear();
}
/**
@@ -745,18 +752,18 @@
MessagingGroup group = oldGroups.get(i);
if (!mGroups.contains(group)) {
List<MessagingMessage> messages = group.getMessages();
- Runnable endRunnable = () -> {
- mMessagingLinearLayout.removeTransientView(group);
- group.recycle();
- };
-
boolean wasShown = group.isShown();
mMessagingLinearLayout.removeView(group);
if (wasShown && !MessagingLinearLayout.isGone(group)) {
mMessagingLinearLayout.addTransientView(group, 0);
- group.removeGroupAnimated(endRunnable);
+ group.removeGroupAnimated(() -> {
+ mMessagingLinearLayout.removeTransientView(group);
+ group.recycle();
+ });
} else {
- endRunnable.run();
+ // Defer recycling until after the update is done, since we may still need the
+ // old group around to perform other updates.
+ mToRecycle.add(group);
}
mMessages.removeAll(messages);
mHistoricMessages.removeAll(messages);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 47cb754..4aa00f6 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -64,7 +64,6 @@
"libbase",
"libcutils",
"libharfbuzz_ng",
- "libhwui",
"liblog",
"libminikin",
"libz",
@@ -266,6 +265,7 @@
"libui",
"libgraphicsenv",
"libgui",
+ "libhwui",
"libmediandk",
"libpermission",
"libsensor",
@@ -344,9 +344,21 @@
],
static_libs: [
"libandroidfw",
- "libcompiler_rt",
- "libutils",
+ "libbinary_parse",
+ "libdng_sdk",
+ "libft2",
"libhostgraphics",
+ "libhwui",
+ "libimage_type_recognition",
+ "libjpeg",
+ "libpiex",
+ "libpng",
+ "libtiff_directory",
+ "libui-types",
+ "libutils",
+ "libwebp-decode",
+ "libwebp-encode",
+ "libwuffs_mirror_release_c",
],
},
linux_glibc: {
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index 3e513df..93ba23b 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -14,15 +14,31 @@
* limitations under the License.
*/
-#include "jni.h"
-#include "core_jni_helpers.h"
-
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/graphics/jni_runtime.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/jni_macros.h>
#include <unicode/putil.h>
+#include <unicode/udata.h>
+
#include <clocale>
#include <sstream>
#include <unordered_map>
#include <vector>
+#include "core_jni_helpers.h"
+#include "jni.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#endif
+
+#include <iostream>
+
using namespace std;
/*
@@ -33,6 +49,33 @@
*/
static JavaVM* javaVM;
+static jclass bridge;
+static jclass layoutLog;
+static jmethodID getLogId;
+static jmethodID logMethodId;
+
+extern int register_android_os_Binder(JNIEnv* env);
+extern int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env);
+
+typedef void (*FreeFunction)(void*);
+
+static void NativeAllocationRegistry_Delegate_nativeApplyFreeFunction(JNIEnv*, jclass,
+ jlong freeFunction,
+ jlong ptr) {
+ void* nativePtr = reinterpret_cast<void*>(static_cast<uintptr_t>(ptr));
+ FreeFunction nativeFreeFunction =
+ reinterpret_cast<FreeFunction>(static_cast<uintptr_t>(freeFunction));
+ nativeFreeFunction(nativePtr);
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(NativeAllocationRegistry_Delegate, nativeApplyFreeFunction, "(JJ)V"),
+};
+
+int register_libcore_util_NativeAllocationRegistry_Delegate(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "libcore/util/NativeAllocationRegistry_Delegate", gMethods,
+ NELEM(gMethods));
+}
namespace android {
@@ -47,6 +90,7 @@
extern int register_android_database_SQLiteDebug(JNIEnv* env);
extern int register_android_os_FileObserver(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
+extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv* env);
extern int register_android_os_Trace(JNIEnv* env);
@@ -54,6 +98,11 @@
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_jar_StrictJarFile(JNIEnv* env);
+extern int register_android_view_KeyCharacterMap(JNIEnv* env);
+extern int register_android_view_KeyEvent(JNIEnv* env);
+extern int register_android_view_MotionEvent(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
+extern int register_android_view_VelocityTracker(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
#define REG_JNI(name) { name }
@@ -78,8 +127,10 @@
{"android.content.res.StringBlock", REG_JNI(register_android_content_StringBlock)},
{"android.content.res.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
#ifdef __linux__
+ {"android.os.Binder", REG_JNI(register_android_os_Binder)},
{"android.os.FileObserver", REG_JNI(register_android_os_FileObserver)},
{"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)},
+ {"android.os.Parcel", REG_JNI(register_android_os_Parcel)},
#endif
{"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
{"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
@@ -88,11 +139,15 @@
{"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
{"android.util.Log", REG_JNI(register_android_util_Log)},
{"android.util.jar.StrictJarFile", REG_JNI(register_android_util_jar_StrictJarFile)},
+ {"android.view.KeyCharacterMap", REG_JNI(register_android_view_KeyCharacterMap)},
+ {"android.view.KeyEvent", REG_JNI(register_android_view_KeyEvent)},
+ {"android.view.MotionEvent", REG_JNI(register_android_view_MotionEvent)},
+ {"android.view.VelocityTracker", REG_JNI(register_android_view_VelocityTracker)},
{"com.android.internal.util.VirtualRefBasePtr",
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr)},
+ {"libcore.util.NativeAllocationRegistry_Delegate",
+ REG_JNI(register_libcore_util_NativeAllocationRegistry_Delegate)},
};
-// Vector to store the names of classes that need delegates of their native methods
-static vector<string> classesToDelegate;
static int register_jni_procs(const std::unordered_map<std::string, RegJNIRec>& jniRegMap,
const vector<string>& classesToRegister, JNIEnv* env) {
@@ -102,36 +157,17 @@
return -1;
}
}
+
+ if (register_android_graphics_classes(env) < 0) {
+ return -1;
+ }
+
return 0;
}
int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods) {
- string classNameString = string(className);
- if (find(classesToDelegate.begin(), classesToDelegate.end(), classNameString)
- != classesToDelegate.end()) {
- // Register native methods to the delegate class <classNameString>_NativeDelegate
- // by adding _Original to the name of each method.
- replace(classNameString.begin(), classNameString.end(), '$', '_');
- string delegateClassName = classNameString + "_NativeDelegate";
- jclass clazz = env->FindClass(delegateClassName.c_str());
- JNINativeMethod gTypefaceDelegateMethods[numMethods];
- for (int i = 0; i < numMethods; i++) {
- JNINativeMethod gTypefaceMethod = gMethods[i];
- string newName = string(gTypefaceMethod.name) + "_Original";
- gTypefaceDelegateMethods[i].name = strdup(newName.c_str());
- gTypefaceDelegateMethods[i].signature = gTypefaceMethod.signature;
- gTypefaceDelegateMethods[i].fnPtr = gTypefaceMethod.fnPtr;
- }
- int result = env->RegisterNatives(clazz, gTypefaceDelegateMethods, numMethods);
- for (int i = 0; i < numMethods; i++) {
- free((char*)gTypefaceDelegateMethods[i].name);
- }
- return result;
- }
-
- jclass clazz = env->FindClass(className);
- return env->RegisterNatives(clazz, gMethods, numMethods);
+ return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
JNIEnv* AndroidRuntime::getJNIEnv() {
@@ -164,6 +200,125 @@
return result;
}
+void LayoutlibLogger(base::LogId, base::LogSeverity severity, const char* tag, const char* file,
+ unsigned int line, const char* message) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jint logPrio = severity;
+ jstring tagString = env->NewStringUTF(tag);
+ jstring messageString = env->NewStringUTF(message);
+
+ jobject bridgeLog = env->CallStaticObjectMethod(bridge, getLogId);
+
+ env->CallVoidMethod(bridgeLog, logMethodId, logPrio, tagString, messageString);
+
+ env->DeleteLocalRef(tagString);
+ env->DeleteLocalRef(messageString);
+ env->DeleteLocalRef(bridgeLog);
+}
+
+void LayoutlibAborter(const char* abort_message) {
+ // Layoutlib should not call abort() as it would terminate Studio.
+ // Throw an exception back to Java instead.
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jniThrowRuntimeException(env, "The Android framework has encountered a fatal error");
+}
+
+// This method has been copied/adapted from system/core/init/property_service.cpp
+// If the ro.product.cpu.abilist* properties have not been explicitly
+// set, derive them from ro.system.product.cpu.abilist* properties.
+static void property_initialize_ro_cpu_abilist() {
+ const std::string EMPTY = "";
+ const char* kAbilistProp = "ro.product.cpu.abilist";
+ const char* kAbilist32Prop = "ro.product.cpu.abilist32";
+ const char* kAbilist64Prop = "ro.product.cpu.abilist64";
+
+ // If the properties are defined explicitly, just use them.
+ if (base::GetProperty(kAbilistProp, EMPTY) != EMPTY) {
+ return;
+ }
+
+ std::string abilist32_prop_val;
+ std::string abilist64_prop_val;
+ const auto abilist32_prop = "ro.system.product.cpu.abilist32";
+ const auto abilist64_prop = "ro.system.product.cpu.abilist64";
+ abilist32_prop_val = base::GetProperty(abilist32_prop, EMPTY);
+ abilist64_prop_val = base::GetProperty(abilist64_prop, EMPTY);
+
+ // Merge ABI lists for ro.product.cpu.abilist
+ auto abilist_prop_val = abilist64_prop_val;
+ if (abilist32_prop_val != EMPTY) {
+ if (abilist_prop_val != EMPTY) {
+ abilist_prop_val += ",";
+ }
+ abilist_prop_val += abilist32_prop_val;
+ }
+
+ // Set these properties
+ const std::pair<const char*, const std::string&> set_prop_list[] = {
+ {kAbilistProp, abilist_prop_val},
+ {kAbilist32Prop, abilist32_prop_val},
+ {kAbilist64Prop, abilist64_prop_val},
+ };
+ for (const auto& [prop, prop_val] : set_prop_list) {
+ base::SetProperty(prop, prop_val);
+ }
+}
+
+static void* mmapFile(const char* dataFilePath) {
+#ifdef _WIN32
+ // Windows needs file path in wide chars to handle unicode file paths
+ int size = MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, NULL, 0);
+ std::vector<wchar_t> wideDataFilePath(size);
+ MultiByteToWideChar(CP_UTF8, 0, dataFilePath, -1, wideDataFilePath.data(), size);
+ HANDLE file =
+ CreateFileW(wideDataFilePath.data(), GENERIC_READ, FILE_SHARE_READ, nullptr,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
+ if ((HANDLE)INVALID_HANDLE_VALUE == file) {
+ return nullptr;
+ }
+
+ struct CloseHandleWrapper {
+ void operator()(HANDLE h) { CloseHandle(h); }
+ };
+ std::unique_ptr<void, CloseHandleWrapper> mmapHandle(
+ CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
+ if (!mmapHandle) {
+ return nullptr;
+ }
+ return MapViewOfFile(mmapHandle.get(), FILE_MAP_READ, 0, 0, 0);
+#else
+ int fd = open(dataFilePath, O_RDONLY);
+ if (fd == -1) {
+ return nullptr;
+ }
+
+ struct stat sb;
+ if (fstat(fd, &sb) == -1) {
+ close(fd);
+ return nullptr;
+ }
+
+ void* addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED) {
+ close(fd);
+ return nullptr;
+ }
+
+ close(fd);
+ return addr;
+#endif
+}
+
+static bool init_icu(const char* dataPath) {
+ void* addr = mmapFile(dataPath);
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(addr, &err);
+ if (err != U_ZERO_ERROR) {
+ return false;
+ }
+ return true;
+}
+
} // namespace android
using namespace android;
@@ -175,37 +330,82 @@
return JNI_ERR;
}
+ init_android_graphics();
+
// Configuration is stored as java System properties.
// Get a reference to System.getProperty
jclass system = FindClassOrDie(env, "java/lang/System");
jmethodID getPropertyMethod = GetStaticMethodIDOrDie(env, system, "getProperty",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
- // Get the names of classes that have to delegate their native methods
- auto delegateNativesToNativesString =
- (jstring) env->CallStaticObjectMethod(system,
- getPropertyMethod, env->NewStringUTF("delegate_natives_to_natives"),
- env->NewStringUTF(""));
- classesToDelegate = parseCsv(env, delegateNativesToNativesString);
-
// Get the names of classes that need to register their native methods
auto nativesClassesJString =
- (jstring) env->CallStaticObjectMethod(system,
- getPropertyMethod, env->NewStringUTF("native_classes"),
- env->NewStringUTF(""));
+ (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+ env->NewStringUTF("core_native_classes"),
+ env->NewStringUTF(""));
vector<string> classesToRegister = parseCsv(env, nativesClassesJString);
+ jstring registerProperty =
+ (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+ env->NewStringUTF(
+ "register_properties_during_load"),
+ env->NewStringUTF(""));
+ const char* registerPropertyString = env->GetStringUTFChars(registerProperty, 0);
+ if (strcmp(registerPropertyString, "true") == 0) {
+ // Set the system properties first as they could be used in the static initialization of
+ // other classes
+ if (register_android_os_SystemProperties(env) < 0) {
+ return JNI_ERR;
+ }
+ classesToRegister.erase(find(classesToRegister.begin(), classesToRegister.end(),
+ "android.os.SystemProperties"));
+ bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
+ bridge = MakeGlobalRefOrDie(env, bridge);
+ jmethodID setSystemPropertiesMethod =
+ GetStaticMethodIDOrDie(env, bridge, "setSystemProperties", "()V");
+ env->CallStaticVoidMethod(bridge, setSystemPropertiesMethod);
+ property_initialize_ro_cpu_abilist();
+ }
+ env->ReleaseStringUTFChars(registerProperty, registerPropertyString);
+
if (register_jni_procs(gRegJNIMap, classesToRegister, env) < 0) {
return JNI_ERR;
}
// Set the location of ICU data
- auto stringPath = (jstring) env->CallStaticObjectMethod(system,
- getPropertyMethod, env->NewStringUTF("icu.dir"),
- env->NewStringUTF(""));
+ auto stringPath = (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+ env->NewStringUTF("icu.data.path"),
+ env->NewStringUTF(""));
const char* path = env->GetStringUTFChars(stringPath, 0);
- u_setDataDirectory(path);
+ bool icuInitialized = init_icu(path);
env->ReleaseStringUTFChars(stringPath, path);
+ if (!icuInitialized) {
+ return JNI_ERR;
+ }
+
+ jstring useJniProperty =
+ (jstring)env->CallStaticObjectMethod(system, getPropertyMethod,
+ env->NewStringUTF("use_bridge_for_logging"),
+ env->NewStringUTF(""));
+ const char* useJniString = env->GetStringUTFChars(useJniProperty, 0);
+ if (strcmp(useJniString, "true") == 0) {
+ layoutLog = FindClassOrDie(env, "com/android/ide/common/rendering/api/ILayoutLog");
+ layoutLog = MakeGlobalRefOrDie(env, layoutLog);
+ logMethodId = GetMethodIDOrDie(env, layoutLog, "logAndroidFramework",
+ "(ILjava/lang/String;Ljava/lang/String;)V");
+ if (bridge == nullptr) {
+ bridge = FindClassOrDie(env, "com/android/layoutlib/bridge/Bridge");
+ bridge = MakeGlobalRefOrDie(env, bridge);
+ }
+ getLogId = GetStaticMethodIDOrDie(env, bridge, "getLog",
+ "()Lcom/android/ide/common/rendering/api/ILayoutLog;");
+ android::base::SetLogger(LayoutlibLogger);
+ android::base::SetAborter(LayoutlibAborter);
+ } else {
+ // initialize logging, so ANDROD_LOG_TAGS env variable is respected
+ android::base::InitLogging(nullptr, android::base::StderrLogger);
+ }
+ env->ReleaseStringUTFChars(useJniProperty, useJniString);
// Use English locale for number format to ensure correct parsing of floats when using strtof
setlocale(LC_NUMERIC, "en_US.UTF-8");
@@ -213,3 +413,9 @@
return JNI_VERSION_1_6;
}
+JNIEXPORT void JNI_OnUnload(JavaVM* vm, void*) {
+ JNIEnv* env = nullptr;
+ vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ env->DeleteGlobalRef(bridge);
+ env->DeleteGlobalRef(layoutLog);
+}
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index d7eeb5f..93ce377 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -130,10 +130,6 @@
mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
- mInfo.flags = Flags<WindowInfo::Flag>(
- env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
- mInfo.type = static_cast<WindowInfo::Type>(
- env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
mInfo.dispatchingTimeout = std::chrono::milliseconds(
env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
mInfo.frameLeft = env->GetIntField(obj,
@@ -159,14 +155,72 @@
env->DeleteLocalRef(regionObj);
}
- mInfo.visible = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.visible);
- mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
- mInfo.hasWallpaper = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.hasWallpaper);
- mInfo.paused = env->GetBooleanField(obj,
- gInputWindowHandleClassInfo.paused);
- mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay);
+ const auto flags = Flags<WindowInfo::Flag>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
+ const auto type = static_cast<WindowInfo::Type>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
+ mInfo.layoutParamsFlags = flags;
+ mInfo.layoutParamsType = type;
+
+ using InputConfig = gui::WindowInfo::InputConfig;
+ // Determine the value for each of the InputConfig flags. We rely on a switch statement and
+ // -Wswitch-enum to give us a build error if we forget to explicitly handle an InputConfig flag.
+ mInfo.inputConfig = InputConfig::NONE;
+ InputConfig enumerationStart = InputConfig::NONE;
+ switch (enumerationStart) {
+ case InputConfig::NONE:
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_VISIBLE:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.visible) == JNI_FALSE) {
+ mInfo.inputConfig |= InputConfig::NOT_VISIBLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_FOCUSABLE:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable) == JNI_FALSE) {
+ mInfo.inputConfig |= InputConfig::NOT_FOCUSABLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::NOT_TOUCHABLE:
+ if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+ mInfo.inputConfig |= InputConfig::NOT_TOUCHABLE;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::PREVENT_SPLITTING:
+ if (!flags.test(WindowInfo::Flag::SPLIT_TOUCH)) {
+ mInfo.inputConfig |= InputConfig::PREVENT_SPLITTING;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.hasWallpaper) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::IS_WALLPAPER:
+ if (type == WindowInfo::Type::WALLPAPER) {
+ mInfo.inputConfig |= InputConfig::IS_WALLPAPER;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::PAUSE_DISPATCHING:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::PAUSE_DISPATCHING;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::TRUSTED_OVERLAY:
+ if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay) == JNI_TRUE) {
+ mInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::WATCH_OUTSIDE_TOUCH:
+ if (flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+ mInfo.inputConfig |= InputConfig::WATCH_OUTSIDE_TOUCH;
+ }
+ FALLTHROUGH_INTENDED;
+ case InputConfig::SLIPPERY:
+ if (flags.test(WindowInfo::Flag::SLIPPERY)) {
+ mInfo.inputConfig |= InputConfig::SLIPPERY;
+ }
+ }
+
mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
mInfo.ownerPid = env->GetIntField(obj,
@@ -274,9 +328,9 @@
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name,
env->NewStringUTF(windowInfo.name.data()));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
- static_cast<uint32_t>(windowInfo.flags.get()));
+ static_cast<uint32_t>(windowInfo.layoutParamsFlags.get()));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
- static_cast<int32_t>(windowInfo.type));
+ static_cast<int32_t>(windowInfo.layoutParamsType));
env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
std::chrono::duration_cast<std::chrono::milliseconds>(
windowInfo.dispatchingTimeout)
@@ -305,15 +359,17 @@
env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
regionObj.get());
+ using InputConfig = gui::WindowInfo::InputConfig;
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible,
- windowInfo.visible);
+ !windowInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable,
- windowInfo.focusable);
+ !windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper,
- windowInfo.hasWallpaper);
- env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused);
+ windowInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
+ env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused,
+ windowInfo.inputConfig.test(InputConfig::PAUSE_DISPATCHING));
env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay,
- windowInfo.trustedOverlay);
+ windowInfo.inputConfig.test(InputConfig::TRUSTED_OVERLAY));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
static_cast<int32_t>(windowInfo.touchOcclusionMode));
env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index d91d526..19402f7 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -118,11 +118,11 @@
ScopedLocalRef<jobjectArray>
frameTimelineObjs(env,
- env->NewObjectArray(vsyncEventData.frameTimelines.size(),
+ env->NewObjectArray(VsyncEventData::kFrameTimelinesLength,
gDisplayEventReceiverClassInfo
.frameTimelineClassInfo.clazz,
/*initial element*/ NULL));
- for (int i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+ for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
ScopedLocalRef<jobject>
frameTimelineObj(env,
@@ -130,8 +130,8 @@
.frameTimelineClassInfo.clazz,
gDisplayEventReceiverClassInfo
.frameTimelineClassInfo.init,
- frameTimeline.id,
- frameTimeline.expectedPresentTime,
+ frameTimeline.vsyncId,
+ frameTimeline.expectedPresentationTime,
frameTimeline.deadlineTimestamp));
env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 336161c..fb5b5ff 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -625,12 +625,16 @@
}
static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
- jobject bufferObject) {
+ jobject bufferObject, jlong fencePtr) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, bufferObject)));
- transaction->setBuffer(ctrl, graphicBuffer);
+ std::optional<sp<Fence>> optFence = std::nullopt;
+ if (fencePtr != 0) {
+ optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
+ }
+ transaction->setBuffer(ctrl, graphicBuffer, optFence);
}
static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2133,7 +2137,7 @@
(void*)nativeGetDisplayedContentSample },
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
(void*)nativeSetGeometry },
- {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;)V",
+ {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
(void*)nativeSetBuffer },
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
{"nativeSetDataSpace", "(JJI)V",
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 009df4a..0db08fb 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -45,6 +45,10 @@
<item name="config_pictureInPictureExpandedVerticalWidth"
format="dimension" type="dimen">110dp</item>
+ <!-- The behavior when an activity has not specified a preference to dock big overlays or not.
+ Docking puts the activity side-by-side next to the big overlay windows. -->
+ <bool name="config_dockBigOverlayWindows">true</bool>
+
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">false</bool>
@@ -57,6 +61,12 @@
com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
</string>
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of hardware privacy switches. -->
+ <string name="config_sensorUseStartedActivity_hwToggle" translatable="false">
+ com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
+ </string>
+
<!-- Component name of the activity that shows the request for access to a usb device. -->
<string name="config_usbPermissionActivity" translatable="false">
com.android.systemui/com.android.systemui.usb.tv.TvUsbPermissionActivity
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fca2bd1..7150fca 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3364,7 +3364,7 @@
area for the user and that ideally it should not be covered. Setting this is only
appropriate for UI where the user would likely take action to uncover it.
<p>The system will try to respect this, but when not possible will ignore it.
- See {@link android.view.View#setPreferKeepClear}. -->
+ <p>This is equivalent to {@link android.view.View#setPreferKeepClear}.-->
<attr name="preferKeepClear" format="boolean" />
<!-- <p>Whether or not the auto handwriting initiation is enabled in this View.
@@ -3644,6 +3644,14 @@
<attr name="__removed2" format="boolean" />
<!-- Specifies whether the IME supports showing inline suggestions. -->
<attr name="supportsInlineSuggestions" format="boolean" />
+ <!-- Specifies whether the IME supports showing inline suggestions when touch
+ exploration is enabled. This does nothing if supportsInlineSuggestions is false.
+ The default value is false and most IMEs should not set this
+ to true since the older menu-style Autofill works better with touch exploration.
+ This attribute should be set to true in special situations, such as if this is an
+ accessibility-focused IME which blocks user interaction with the app window while the
+ IME is displayed. -->
+ <attr name="supportsInlineSuggestionsWithTouchExploration" format="boolean" />
<!-- Specifies whether the IME suppresses system spell checker.
The default value is false. If an IME sets this attribute to true,
the system spell checker will be disabled while the IME has an
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6dc975b..0e0c6a3 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2030,6 +2030,14 @@
-->
<attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
<attr name="knownActivityEmbeddingCerts" />
+
+ <!-- If false, {@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK} and
+ {@link android.app.Activity#onBackPressed Activity.onBackPressed()}
+ and related event will be forwarded to the Activities and View, otherwise those events
+ will be replaced by a call to
+ {@link android.view.OnBackInvokedCallback#onBackInvoked
+ OnBackInvokedCallback.onBackInvoked()} on the focused window. -->
+ <attr name="enableOnBackInvokedCallback" format="boolean"/>
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fdb85a9..05894d5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2902,6 +2902,11 @@
<string name="config_sensorUseStartedActivity" translatable="false"
>com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of hardware privacy switches. -->
+ <string name="config_sensorUseStartedActivity_hwToggle" translatable="false"
+ >com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+
<!-- Component name of the activity used to ask a user to confirm system language change after
receiving <Set Menu Language> CEC message. -->
<string name="config_hdmiCecSetMenuLanguageActivity"
@@ -3733,6 +3738,10 @@
must be no less than 3 for back compatibility. -->
<integer name="config_pictureInPictureMaxNumberOfActions">3</integer>
+ <!-- The behavior when an activity has not specified a preference to dock big overlays or not.
+ Docking puts the activity side-by-side next to the big overlay windows. -->
+ <bool name="config_dockBigOverlayWindows">false</bool>
+
<!-- Controls the snap mode for the docked stack divider
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
@@ -5473,10 +5482,16 @@
<!-- On-device package for providing companion device associations. -->
<string name="config_systemCompanionDeviceProvider" translatable="false"></string>
- <!-- Whether this device is supporting the microphone toggle -->
+ <!-- Whether this device is supporting the software microphone toggle -->
<bool name="config_supportsMicToggle">false</bool>
<!-- Whether this device is supporting the camera toggle -->
<bool name="config_supportsCamToggle">false</bool>
+ <!-- Whether this device is supporting the hardware microphone toggle -->
+ <bool name="config_supportsHardwareMicToggle">false</bool>
+ <!-- Whether this device is supporting the hardware camera toggle -->
+ <bool name="config_supportsHardwareCamToggle">false</bool>
+ <!-- Whether a camera intent is launched when the lens cover is toggled -->
+ <bool name="config_launchCameraOnCameraLensCoverToggle">true</bool>
<!-- List containing the allowed install sources for accessibility service. -->
<string-array name="config_accessibility_allowed_install_source" translatable="false"/>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 4874e65..39b41b5 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -991,4 +991,7 @@
<dimen name="secondary_rounded_corner_radius_adjustment">0px</dimen>
<dimen name="secondary_rounded_corner_radius_top_adjustment">0px</dimen>
<dimen name="secondary_rounded_corner_radius_bottom_adjustment">0px</dimen>
+
+ <!-- Default size for user icons (a.k.a. avatar images) -->
+ <dimen name="user_icon_size">190dp</dimen>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bf34a1..3beb4b2 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3279,6 +3279,8 @@
<public name="allowUntrustedActivityEmbedding" />
<public name="knownActivityEmbeddingCerts" />
<public name="intro" />
+ <public name="enableOnBackInvokedCallback" />
+ <public name="supportsInlineSuggestionsWithTouchExploration" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index db66777..f531c3a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -375,6 +375,7 @@
<java-symbol type="string" name="config_usbConfirmActivity" />
<java-symbol type="string" name="config_usbResolverActivity" />
<java-symbol type="string" name="config_sensorUseStartedActivity" />
+ <java-symbol type="string" name="config_sensorUseStartedActivity_hwToggle" />
<java-symbol type="string" name="config_hdmiCecSetMenuLanguageActivity" />
<java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
<java-symbol type="integer" name="config_maxNumVisibleRecentTasks_lowRam" />
@@ -417,6 +418,7 @@
<java-symbol type="integer" name="config_pictureInPictureMaxNumberOfActions" />
<java-symbol type="dimen" name="config_pictureInPictureExpandedHorizontalHeight" />
<java-symbol type="dimen" name="config_pictureInPictureExpandedVerticalWidth" />
+ <java-symbol type="bool" name="config_dockBigOverlayWindows" />
<java-symbol type="dimen" name="config_closeToSquareDisplayMaxAspectRatio" />
<java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
<java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
@@ -543,6 +545,7 @@
<java-symbol type="dimen" name="immersive_mode_cling_width" />
<java-symbol type="dimen" name="accessibility_magnification_indicator_width" />
<java-symbol type="dimen" name="circular_display_mask_thickness" />
+ <java-symbol type="dimen" name="user_icon_size" />
<java-symbol type="string" name="add_account_button_label" />
<java-symbol type="string" name="addToDictionary" />
@@ -2233,7 +2236,6 @@
<java-symbol type="string" name="config_dreamsDefaultComponent" />
<java-symbol type="array" name="config_supportedDreamComplications" />
<java-symbol type="array" name="config_dreamComplicationsEnabledByDefault" />
- <java-symbol type="drawable" name="default_dream_preview" />
<java-symbol type="array" name="config_disabledDreamComponents" />
<java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
@@ -4649,6 +4651,9 @@
<java-symbol type="bool" name="config_supportsMicToggle" />
<java-symbol type="bool" name="config_supportsCamToggle" />
+ <java-symbol type="bool" name="config_supportsHardwareMicToggle" />
+ <java-symbol type="bool" name="config_supportsHardwareCamToggle" />
+ <java-symbol type="bool" name="config_launchCameraOnCameraLensCoverToggle" />
<java-symbol type="dimen" name="starting_surface_icon_size" />
<java-symbol type="dimen" name="starting_surface_default_icon_size" />
diff --git a/core/res/res/drawable/default_dream_preview.xml b/core/tests/coretests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
similarity index 63%
copy from core/res/res/drawable/default_dream_preview.xml
copy to core/tests/coretests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
index bf4a04b..3440208 100644
--- a/core/res/res/drawable/default_dream_preview.xml
+++ b/core/tests/coretests/res/xml/ime_meta_inline_suggestions_with_touch_exploration.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
+
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -15,6 +16,13 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <solid android:color="@android:color/white"/>
-</shape>
\ No newline at end of file
+<input-method
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
+ android:supportsInlineSuggestionsWithTouchExploration="true"
+>
+ <subtype
+ android:label="subtype1"
+ android:imeSubtypeLocale="en_US"
+ android:imeSubtypeMode="keyboard" />
+</input-method>
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 8718b95..e7d7d640 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -55,11 +55,13 @@
assertThat(imi.supportsSwitchingToNextInputMethod(), is(false));
assertThat(imi.isInlineSuggestionsEnabled(), is(false));
+ assertThat(imi.supportsInlineSuggestionsWithTouchExploration(), is(false));
final InputMethodInfo clone = cloneViaParcel(imi);
assertThat(clone.supportsSwitchingToNextInputMethod(), is(false));
assertThat(imi.isInlineSuggestionsEnabled(), is(false));
+ assertThat(imi.supportsInlineSuggestionsWithTouchExploration(), is(false));
}
@Test
@@ -85,6 +87,18 @@
}
@Test
+ public void testInlineSuggestionsEnabledWithTouchExploration() throws Exception {
+ final InputMethodInfo imi =
+ buildInputMethodForTest(R.xml.ime_meta_inline_suggestions_with_touch_exploration);
+
+ assertThat(imi.supportsInlineSuggestionsWithTouchExploration(), is(true));
+
+ final InputMethodInfo clone = cloneViaParcel(imi);
+
+ assertThat(clone.supportsInlineSuggestionsWithTouchExploration(), is(true));
+ }
+
+ @Test
public void testIsVrOnly() throws Exception {
final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_vr_only);
diff --git a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
index bf508db..2dadb20 100644
--- a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
+++ b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
@@ -53,14 +53,15 @@
@Test
public void testRegisterAndUnregister() {
- final TaskFpsCallback.OnFpsCallbackListener listener = fps -> {
- // Ignore
+ final TaskFpsCallback callback = new TaskFpsCallback() {
+ @Override
+ public void onFpsReported(float fps) {
+ // Ignore
+ }
};
- final TaskFpsCallback callback = new TaskFpsCallback(Runnable::run, listener);
-
final List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1);
assertEquals(tasks.size(), 1);
- mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, callback);
+ mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, Runnable::run, callback);
mWindowManager.unregisterTaskFpsCallback(callback);
}
}
diff --git a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
index a2bc77a..3a27225 100644
--- a/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
+++ b/core/tests/coretests/src/com/android/internal/infra/AndroidFutureTest.java
@@ -29,6 +29,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
+import java.util.function.BiFunction;
/**
* Unit test for {@link AndroidFuture}.
@@ -154,4 +155,35 @@
expectThrows(ExecutionException.class, future1::get);
assertThat(executionException.getCause()).isInstanceOf(UnsupportedOperationException.class);
}
+
+ @Test
+ public void testThenCombine() throws Exception {
+ String nearFutureString = "near future comes";
+ AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
+ String farFutureString = " before far future.";
+ AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
+ AndroidFuture<String> combinedFuture =
+ nearFuture.thenCombine(farFuture, ((s1, s2) -> s1 + s2));
+
+ assertThat(combinedFuture.get()).isEqualTo(nearFutureString + farFutureString);
+ }
+
+ @Test
+ public void testThenCombine_functionThrowingException() throws Exception {
+ String nearFutureString = "near future comes";
+ AndroidFuture<String> nearFuture = AndroidFuture.supply(() -> nearFutureString);
+ String farFutureString = " before far future.";
+ AndroidFuture<String> farFuture = AndroidFuture.supply(() -> farFutureString);
+ UnsupportedOperationException exception = new UnsupportedOperationException(
+ "Unsupported operation exception thrown!");
+ BiFunction<String, String, String> throwingFunction = (s1, s2) -> {
+ throw exception;
+ };
+ AndroidFuture<String> combinedFuture = nearFuture.thenCombine(farFuture, throwingFunction);
+
+ ExecutionException thrown = expectThrows(ExecutionException.class,
+ () -> combinedFuture.get());
+
+ assertThat(thrown.getCause()).isSameInstanceAs(exception);
+ }
}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 88228f2..2a82d8e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C} 2018 The Android Open Source Project
+// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License"};
// you may not use this file except in compliance with the License.
@@ -140,13 +140,6 @@
}
prebuilt_etc {
- name: "privapp_whitelist_com.android.networkstack.tethering",
- sub_dir: "permissions",
- src: "com.android.networkstack.tethering.xml",
- filename_from_src: true,
-}
-
-prebuilt_etc {
name: "privapp_whitelist_com.android.provision",
system_ext_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml
deleted file mode 100644
index f26a961..0000000
--- a/data/etc/com.android.networkstack.tethering.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
--->
-
-<permissions>
- <privapp-permissions package="com.android.networkstack.tethering">
- <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
- <permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.MODIFY_PHONE_STATE"/>
- <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
- <permission name="android.permission.TETHER_PRIVILEGED"/>
- <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
- <permission name="android.permission.UPDATE_DEVICE_STATS"/>
- </privapp-permissions>
-</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 4aa0f07..1779655 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2653,6 +2653,12 @@
"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",
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 6d691c1..3f7f088 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -34,6 +34,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* Result of text shaping of the single paragraph string.
@@ -56,18 +57,22 @@
public class MeasuredText {
private static final String TAG = "MeasuredText";
- private long mNativePtr;
- private boolean mComputeHyphenation;
- private boolean mComputeLayout;
- private @NonNull char[] mChars;
+ private final long mNativePtr;
+ private final boolean mComputeHyphenation;
+ private final boolean mComputeLayout;
+ @NonNull private final char[] mChars;
+ private final int mTop;
+ private final int mBottom;
// Use builder instead.
private MeasuredText(long ptr, @NonNull char[] chars, boolean computeHyphenation,
- boolean computeLayout) {
+ boolean computeLayout, int top, int bottom) {
mNativePtr = ptr;
mChars = chars;
mComputeHyphenation = computeHyphenation;
mComputeLayout = computeLayout;
+ mTop = top;
+ mBottom = bottom;
}
/**
@@ -124,6 +129,30 @@
}
/**
+ * Retrieves the font metrics of the given range
+ *
+ * @param start an inclusive start index of the range
+ * @param end an exclusive end index of the range
+ * @param outMetrics an output metrics object
+ */
+ public void getFontMetricsInt(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
+ @NonNull Paint.FontMetricsInt outMetrics) {
+ Preconditions.checkArgument(0 <= start && start <= mChars.length,
+ "start(%d) must be 0 <= start <= %d", start, mChars.length);
+ Preconditions.checkArgument(0 <= end && end <= mChars.length,
+ "end(%d) must be 0 <= end <= %d", end, mChars.length);
+ Preconditions.checkArgument(start <= end,
+ "start(%d) is larger than end(%d)", start, end);
+ Objects.requireNonNull(outMetrics);
+
+ long packed = nGetExtent(mNativePtr, mChars, start, end);
+ outMetrics.ascent = (int) (packed >> 32);
+ outMetrics.descent = (int) (packed & 0xFFFFFFFF);
+ outMetrics.top = Math.min(outMetrics.ascent, mTop);
+ outMetrics.bottom = Math.max(outMetrics.descent, mBottom);
+ }
+
+ /**
* Returns the width of the character at the given offset.
*
* @param offset an offset of the character.
@@ -160,6 +189,8 @@
@CriticalNative
private static native float nGetCharWidthAt(long nativePtr, int offset);
+ private static native long nGetExtent(long nativePtr, char[] buf, int start, int end);
+
/**
* Helper class for creating a {@link MeasuredText}.
* <p>
@@ -189,6 +220,9 @@
private boolean mFastHyphenation = false;
private int mCurrentOffset = 0;
private @Nullable MeasuredText mHintMt = null;
+ private int mTop = 0;
+ private int mBottom = 0;
+ private Paint.FontMetricsInt mCachedMetrics = new Paint.FontMetricsInt();
/**
* Construct a builder.
@@ -269,6 +303,10 @@
nAddStyleRun(mNativePtr, paint.getNativeInstance(), lbStyle, lbWordStyle,
mCurrentOffset, end, isRtl);
mCurrentOffset = end;
+
+ paint.getFontMetricsInt(mCachedMetrics);
+ mTop = Math.min(mTop, mCachedMetrics.top);
+ mBottom = Math.max(mBottom, mCachedMetrics.bottom);
return this;
}
@@ -419,7 +457,7 @@
long ptr = nBuildMeasuredText(mNativePtr, hintPtr, mText, mComputeHyphenation,
mComputeLayout, mFastHyphenation);
final MeasuredText res = new MeasuredText(ptr, mText, mComputeHyphenation,
- mComputeLayout);
+ mComputeLayout, mTop, mBottom);
sRegistry.registerNativeAllocation(res, ptr);
return res;
} finally {
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 d35ecbd..0bf078d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -833,8 +833,8 @@
if (shouldExpand(null, intent, getSplitRules())) {
setLaunchingInExpandedContainer(launchingActivity, options);
- } else if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
- setLaunchingInSameContainer(launchingActivity, intent, options);
+ } else if (!splitWithLaunchingActivity(launchingActivity, intent, options)) {
+ setLaunchingInSameSideContainer(launchingActivity, intent, options);
}
return super.onStartActivity(who, intent, options);
@@ -853,9 +853,9 @@
/**
* Returns {@code true} if the activity that is going to be started via the
* {@code intent} should be paired with the {@code launchingActivity} and is set to be
- * launched in an empty side container.
+ * launched in the side container.
*/
- private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
+ private boolean splitWithLaunchingActivity(Activity launchingActivity, Intent intent,
Bundle options) {
final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
getSplitRules());
@@ -863,9 +863,14 @@
return false;
}
- // Create a new split with an empty side container
- final TaskFragmentContainer secondaryContainer = mPresenter
- .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+ // Check if there is any existing side container to launch into.
+ TaskFragmentContainer secondaryContainer = findSideContainerForNewLaunch(
+ launchingActivity, splitPairRule);
+ if (secondaryContainer == null) {
+ // Create a new split with an empty side container.
+ secondaryContainer = mPresenter
+ .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+ }
// Amend the request to let the WM know that the activity should be placed in the
// dedicated container.
@@ -875,12 +880,39 @@
}
/**
+ * Finds if there is an existing split side {@link TaskFragmentContainer} that can be used
+ * for the new rule.
+ */
+ @Nullable
+ private TaskFragmentContainer findSideContainerForNewLaunch(Activity launchingActivity,
+ SplitPairRule splitPairRule) {
+ final TaskFragmentContainer launchingContainer = getContainerWithActivity(
+ launchingActivity.getActivityToken());
+ if (launchingContainer == null) {
+ return null;
+ }
+
+ // We only check if the launching activity is the primary of the split. We will check
+ // if the launching activity is the secondary in #setLaunchingInSameSideContainer.
+ final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
+ if (splitContainer == null
+ || splitContainer.getPrimaryContainer() != launchingContainer) {
+ return null;
+ }
+
+ if (canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+ return splitContainer.getSecondaryContainer();
+ }
+ return null;
+ }
+
+ /**
* Checks if the activity that is going to be started via the {@code intent} should be
* paired with the existing top activity which is currently paired with the
- * {@code launchingActivity}. If so, set the activity to be launched in the same
+ * {@code launchingActivity}. If so, set the activity to be launched in the same side
* container of the {@code launchingActivity}.
*/
- private void setLaunchingInSameContainer(Activity launchingActivity, Intent intent,
+ private void setLaunchingInSameSideContainer(Activity launchingActivity, Intent intent,
Bundle options) {
final TaskFragmentContainer launchingContainer = getContainerWithActivity(
launchingActivity.getActivityToken());
@@ -911,6 +943,11 @@
return;
}
+ // Can only launch in the same container if the rules share the same presentation.
+ if (!canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+ return;
+ }
+
// Amend the request to let the WM know that the activity should be placed in the
// dedicated container. This is necessary for the case that the activity is started
// into a new Task, or new Task will be escaped from the current host Task and be
@@ -928,4 +965,31 @@
public boolean isActivityEmbedded(@NonNull Activity activity) {
return mPresenter.isActivityEmbedded(activity.getActivityToken());
}
+
+ /**
+ * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
+ * there is any.
+ */
+ private static boolean canReuseContainer(SplitRule rule1, SplitRule rule2) {
+ if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
+ return false;
+ }
+ return rule1.getSplitRatio() == rule2.getSplitRatio()
+ && rule1.getLayoutDirection() == rule2.getLayoutDirection();
+ }
+
+ /**
+ * Whether it is ok for other rule to reuse the {@link TaskFragmentContainer} of the given
+ * rule.
+ */
+ private static boolean isContainerReusableRule(SplitRule rule) {
+ // We don't expect to reuse the placeholder rule.
+ if (!(rule instanceof SplitPairRule)) {
+ return false;
+ }
+ final SplitPairRule pairRule = (SplitPairRule) rule;
+
+ // Not reuse if it needs to destroy the existing.
+ return !pairRule.shouldClearTop();
+ }
}
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..e50ad38 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
@@ -54,7 +54,7 @@
private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
public static final boolean IS_ENABLED = SystemProperties
- .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
"persist.debug.back_predictability_progress_threshold";
private static final int PROGRESS_THRESHOLD = SystemProperties
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 6ffcf10..241f1a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -423,7 +423,6 @@
WindowContainerTransaction t) {
// This is triggered right before the rotation is applied
if (fromRotation != toRotation) {
- mBubblePositioner.setRotation(toRotation);
if (mStackView != null) {
// Layout listener set on stackView will update the positioner
// once the rotation is applied
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 127d5a8..75b19fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.PointF;
@@ -112,10 +113,6 @@
update();
}
- public void setRotation(int rotation) {
- mRotation = rotation;
- }
-
/**
* Available space and inset information. Call this when config changes
* occur or when added to a window.
@@ -273,7 +270,8 @@
/** @return whether the device is in landscape orientation. */
public boolean isLandscape() {
- return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
+ return mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE;
}
/** @return whether the screen is considered large. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index e616172..77fd228 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -620,7 +620,7 @@
setCurrentValue(bounds);
final Rect insets = computeInsets(fraction);
final float degree, x, y;
- if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
if (rotationDelta == ROTATION_90) {
degree = 90 * (1 - fraction);
x = fraction * (end.left - start.left)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index d022ec1..13137fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -97,9 +97,8 @@
* Start a pair of intent and task using legacy transition system.
*/
oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
- in Intent fillInIntent, int taskId, boolean intentFirst, in Bundle mainOptions,
- in Bundle sideOptions, int sidePosition, float splitRatio,
- in RemoteAnimationAdapter adapter) = 12;
+ in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions,
+ int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter) = 12;
/**
* Blocking call that notifies and gets additional split-screen targets when entering
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 990b53a..e88eef9 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
@@ -349,17 +349,20 @@
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
- mStageCoordinator.updateSurfaceBounds(null /* layout */, t);
-
- if (apps != null) {
- for (int i = 0; i < apps.length; ++i) {
- if (apps[i].mode == MODE_OPENING) {
- t.show(apps[i].leash);
- }
- }
+ if (apps == null || apps.length == 0) {
+ // Do nothing when the animation was cancelled.
+ t.apply();
+ return;
}
+ mStageCoordinator.updateSurfaceBounds(null /* layout */, t);
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING) {
+ t.show(apps[i].leash);
+ }
+ }
t.apply();
+
if (finishedCallback != null) {
try {
finishedCallback.onAnimationFinished();
@@ -642,14 +645,13 @@
@Override
public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
- Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
- Bundle sideOptions, int sidePosition, float splitRatio,
- RemoteAnimationAdapter adapter) {
+ Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions,
+ int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
executeRemoteCallWithTaskPermission(mController,
"startIntentAndTaskWithLegacyTransition", (controller) ->
controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
- pendingIntent, fillInIntent, taskId, intentFirst, mainOptions,
- sideOptions, sidePosition, splitRatio, adapter));
+ pendingIntent, fillInIntent, taskId, mainOptions, sideOptions,
+ sidePosition, splitRatio, adapter));
}
@Override
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 029d073..81dacdb 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
@@ -373,6 +373,23 @@
void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
float splitRatio, RemoteAnimationAdapter adapter) {
+ startWithLegacyTransition(mainTaskId, sideTaskId, null /* pendingIntent */,
+ null /* fillInIntent */, mainOptions, sideOptions, sidePosition, splitRatio,
+ adapter);
+ }
+
+ /** Start an intent and a task ordered by {@code intentFirst}. */
+ void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
+ int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+ startWithLegacyTransition(taskId, INVALID_TASK_ID, pendingIntent, fillInIntent,
+ mainOptions, sideOptions, sidePosition, splitRatio, adapter);
+ }
+
+ private void startWithLegacyTransition(int mainTaskId, int sideTaskId,
+ @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent,
+ @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+ @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
// Init divider first to make divider leash for remote animation target.
mSplitLayout.init();
// Set false to avoid record new bounds with old task still on top;
@@ -466,124 +483,19 @@
addActivityOptions(sideOptions, mSideStage);
// Add task launch requests
- wct.startTask(mainTaskId, mainOptions);
- wct.startTask(sideTaskId, sideOptions);
+ if (pendingIntent != null && fillInIntent != null) {
+ wct.startTask(mainTaskId, mainOptions);
+ wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
+ } else {
+ wct.startTask(mainTaskId, mainOptions);
+ wct.startTask(sideTaskId, sideOptions);
+ }
// Using legacy transitions, so we can't use blast sync since it conflicts.
mTaskOrganizer.applyTransaction(wct);
mSyncQueue.runInSync(t -> updateSurfaceBounds(mSplitLayout, t));
}
- /** Start an intent and a task ordered by {@code intentFirst}. */
- void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
- int taskId, boolean intentFirst, @Nullable Bundle mainOptions,
- @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
- RemoteAnimationAdapter adapter) {
- // TODO: try pulling the first chunk of this method into a method so that it can be shared
- // with startTasksWithLegacyTransition. So far attempts to do so result in failure in split.
-
- // Init divider first to make divider leash for remote animation target.
- mSplitLayout.init();
- // Set false to avoid record new bounds with old task still on top;
- mShouldUpdateRecents = false;
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
- prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
- // Need to add another wrapper here in shell so that we can inject the divider bar
- // and also manage the process elevation via setRunningRemote
- IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- final IRemoteAnimationFinishedCallback finishedCallback) {
- RemoteAnimationTarget[] augmentedNonApps =
- new RemoteAnimationTarget[nonApps.length + 1];
- for (int i = 0; i < nonApps.length; ++i) {
- augmentedNonApps[i] = nonApps[i];
- }
- augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
-
- IRemoteAnimationFinishedCallback wrapCallback =
- new IRemoteAnimationFinishedCallback.Stub() {
- @Override
- public void onAnimationFinished() throws RemoteException {
- mShouldUpdateRecents = true;
- mSyncQueue.queue(evictWct);
- mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
- finishedCallback.onAnimationFinished();
- }
- };
- try {
- try {
- ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
- adapter.getCallingApplication());
- } catch (SecurityException e) {
- Slog.e(TAG, "Unable to boost animation thread. This should only happen"
- + " during unit tests");
- }
- adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
- augmentedNonApps, wrapCallback);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- }
-
- @Override
- public void onAnimationCancelled() {
- mShouldUpdateRecents = true;
- mSyncQueue.queue(evictWct);
- mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
- try {
- adapter.getRunner().onAnimationCancelled();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error starting remote animation", e);
- }
- }
- };
- RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
- wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
-
- if (mainOptions == null) {
- mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
- } else {
- ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
- mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
- mainOptions = mainActivityOptions.toBundle();
- }
-
- sideOptions = sideOptions != null ? sideOptions : new Bundle();
- setSideStagePosition(sidePosition, wct);
-
- mSplitLayout.setDivideRatio(splitRatio);
- if (mMainStage.isActive()) {
- mMainStage.moveToTop(getMainStageBounds(), wct);
- } else {
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
- }
- mSideStage.moveToTop(getSideStageBounds(), wct);
-
- // Make sure the launch options will put tasks in the corresponding split roots
- addActivityOptions(mainOptions, mMainStage);
- addActivityOptions(sideOptions, mSideStage);
-
- // Add task launch requests
- if (intentFirst) {
- wct.sendPendingIntent(pendingIntent, fillInIntent, mainOptions);
- wct.startTask(taskId, sideOptions);
- } else {
- wct.startTask(taskId, mainOptions);
- wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
- }
-
- // Using legacy transitions, so we can't use blast sync since it conflicts.
- mTaskOrganizer.applyTransaction(wct);
- }
-
/**
* Collects all the current child tasks of a specific split and prepares transaction to evict
* them to display.
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 86b73fc..efb52a5 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
@@ -74,6 +74,8 @@
/** Set to {@code true} to enable shell transitions. */
public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
+ public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
+ && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
/** Transition type for exiting PIP via the Shell, via pressing the expand button. */
public static final int TRANSIT_EXIT_PIP = TRANSIT_FIRST_CUSTOM + 1;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index a20a201..0a3321e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -16,8 +16,8 @@
package com.android.wm.shell.flicker.bubble
-import android.platform.test.annotations.Presubmit
-import androidx.test.filters.RequiresDevice
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.annotation.Group4
@@ -25,8 +25,8 @@
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import org.junit.Assume
import org.junit.Before
-import org.junit.runner.RunWith
import org.junit.Test
+import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
@@ -57,7 +57,7 @@
}
}
- @Presubmit
+ @FlakyTest(bugId = 218642026)
@Test
open fun testAppIsAlwaysVisible() {
testSpec.assertLayers {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 467cadc..f2c5093 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -167,7 +166,7 @@
* Checks that the focus changes between the [pipApp] window and the launcher when
* closing the pip window
*/
- @Postsubmit
+ @Presubmit
@Test
fun focusChanges() {
testSpec.assertEventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 173140d..c22d3f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -16,7 +16,6 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import com.android.server.wm.flicker.FlickerTestParameter
@@ -98,11 +97,11 @@
/**
* Checks that the focus doesn't change between windows during the transition
*/
- @Postsubmit
+ @Presubmit
@Test
open fun focusDoesNotChange() {
testSpec.assertEventLog {
this.focusDoesNotChange()
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 931d060..4f98b70 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -54,6 +54,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
+@FlakyTest(bugId = 219750830)
class ExitPipViaExpandButtonClickTest(
testSpec: FlickerTestParameter
) : ExitPipToAppTransition(testSpec) {
@@ -101,4 +102,4 @@
supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
}
}
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 07c3b15..19e020a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -16,10 +16,9 @@
package com.android.wm.shell.flicker.pip
-import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
@@ -149,7 +148,7 @@
/**
* Checks that the focus doesn't change between windows during the transition
*/
- @Postsubmit
+ @FlakyTest(bugId = 216306753)
@Test
fun focusDoesNotChange() {
testSpec.assertEventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index e91bef1..8729bb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -55,7 +55,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class MovePipDownShelfHeightChangeTest(
+open class MovePipDownShelfHeightChangeTest(
testSpec: FlickerTestParameter
) : MovePipShelfHeightTransition(testSpec) {
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
new file mode 100644
index 0000000..6c80daa
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest_ShellTransit.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (decrease).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
+ *
+ * Actions:
+ * Launch [pipApp] in pip mode
+ * Launch [testApp]
+ * Press home
+ * Check if pip window moves down (visually)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+@FlakyTest(bugId = 219693385)
+class MovePipDownShelfHeightChangeTest_ShellTransit(
+ testSpec: FlickerTestParameter
+) : MovePipDownShelfHeightChangeTest(testSpec) {
+ @Before
+ fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 7e66cd3..4bc8eb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -16,15 +16,18 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.traces.region.RegionSubject
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,6 +61,11 @@
class MovePipUpShelfHeightChangeTest(
testSpec: FlickerTestParameter
) : MovePipShelfHeightTransition(testSpec) {
+ @Before
+ fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/libs/hwui/jni/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index 76ea2d5..c13c800 100644
--- a/libs/hwui/jni/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -134,6 +134,21 @@
GraphicsJNI::irect_to_jrect(ir, env, bounds);
}
+// Regular JNI
+static jlong nGetExtent(JNIEnv* env, jobject, jlong ptr, jcharArray javaText, jint start,
+ jint end) {
+ ScopedCharArrayRO text(env, javaText);
+ const minikin::U16StringPiece textBuffer(text.get(), text.size());
+ const minikin::Range range(start, end);
+
+ minikin::MinikinExtent extent = toMeasuredParagraph(ptr)->getExtent(textBuffer, range);
+
+ int32_t ascent = SkScalarRoundToInt(extent.ascent);
+ int32_t descent = SkScalarRoundToInt(extent.descent);
+
+ return (((jlong)(ascent)) << 32) | ((jlong)descent);
+}
+
// CriticalNative
static jlong nGetReleaseFunc(CRITICAL_JNI_PARAMS) {
return toJLong(&releaseMeasuredParagraph);
@@ -153,12 +168,13 @@
};
static const JNINativeMethod gMTMethods[] = {
- // MeasuredParagraph native functions.
- {"nGetWidth", "(JII)F", (void*) nGetWidth}, // Critical Natives
- {"nGetBounds", "(J[CIILandroid/graphics/Rect;)V", (void*) nGetBounds}, // Regular JNI
- {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives
- {"nGetMemoryUsage", "(J)I", (void*) nGetMemoryUsage}, // Critical Native
- {"nGetCharWidthAt", "(JI)F", (void*) nGetCharWidthAt}, // Critical Native
+ // MeasuredParagraph native functions.
+ {"nGetWidth", "(JII)F", (void*)nGetWidth}, // Critical Natives
+ {"nGetBounds", "(J[CIILandroid/graphics/Rect;)V", (void*)nGetBounds}, // Regular JNI
+ {"nGetExtent", "(J[CII)J", (void*)nGetExtent}, // Regular JNI
+ {"nGetReleaseFunc", "()J", (void*)nGetReleaseFunc}, // Critical Natives
+ {"nGetMemoryUsage", "(J)I", (void*)nGetMemoryUsage}, // Critical Native
+ {"nGetCharWidthAt", "(JI)F", (void*)nGetCharWidthAt}, // Critical Native
};
int register_android_graphics_text_MeasuredText(JNIEnv* env) {
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
new file mode 100644
index 0000000..0e9c99b
--- /dev/null
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -0,0 +1,192 @@
+/*
+ * 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 android.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ * AudioDeviceVolumeManager provides access to audio device volume control.
+ */
+public class AudioDeviceVolumeManager {
+
+ // define when using Log.*
+ //private static final String TAG = "AudioDeviceVolumeManager";
+ private static IAudioService sService;
+
+ private final String mPackageName;
+
+ public AudioDeviceVolumeManager(Context context) {
+ mPackageName = context.getApplicationContext().getOpPackageName();
+ }
+
+ /**
+ * @hide
+ * Interface to receive volume changes on a device that behaves in absolute volume mode.
+ * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, Executor,
+ * OnAudioDeviceVolumeChangeListener)
+ * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, Executor,
+ * OnAudioDeviceVolumeChangeListener)
+ */
+ public interface OnAudioDeviceVolumeChangedListener {
+ /**
+ * Called the device for the given audio device has changed.
+ * @param device the audio device whose volume has changed
+ * @param vol the new volume for the device
+ */
+ void onAudioDeviceVolumeChanged(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull VolumeInfo vol);
+ }
+
+ static class ListenerInfo {
+ final @NonNull OnAudioDeviceVolumeChangedListener mListener;
+ final @NonNull Executor mExecutor;
+ final @NonNull AudioDeviceAttributes mDevice;
+
+ ListenerInfo(@NonNull OnAudioDeviceVolumeChangedListener listener, @NonNull Executor exe,
+ @NonNull AudioDeviceAttributes device) {
+ mListener = listener;
+ mExecutor = exe;
+ mDevice = device;
+ }
+ }
+
+ private final Object mDeviceVolumeListenerLock = new Object();
+ /**
+ * List of listeners for volume changes, the associated device, and their associated Executor.
+ * List is lazy-initialized on first registration
+ */
+ @GuardedBy("mDeviceVolumeListenerLock")
+ private @Nullable ArrayList<ListenerInfo> mDeviceVolumeListeners;
+
+ @GuardedBy("mDeviceVolumeListenerLock")
+ private DeviceVolumeDispatcherStub mDeviceVolumeDispatcherStub;
+
+ final class DeviceVolumeDispatcherStub extends IAudioDeviceVolumeDispatcher.Stub {
+ /**
+ * Register / unregister the stub
+ * @param register true for registering, false for unregistering
+ * @param device device for which volume is monitored
+ */
+ public void register(boolean register, @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes) {
+ try {
+ getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
+ this, mPackageName,
+ Objects.requireNonNull(device), Objects.requireNonNull(volumes));
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void dispatchDeviceVolumeChanged(
+ @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol) {
+ final ArrayList<ListenerInfo> volumeListeners;
+ synchronized (mDeviceVolumeListenerLock) {
+ volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone();
+ }
+ for (ListenerInfo listenerInfo : volumeListeners) {
+ if (listenerInfo.mDevice.equals(device)) {
+ listenerInfo.mExecutor.execute(
+ () -> listenerInfo.mListener.onAudioDeviceVolumeChanged(device, vol));
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model, and registers a listener for receiving
+ * volume updates to apply on that device
+ * @param device the audio device set to absolute volume mode
+ * @param volume the type of volume this device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteVolumeBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull VolumeInfo volume,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+ final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
+ volumes.add(volume);
+ setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener);
+ }
+
+ /**
+ * @hide
+ * Configures a device to use absolute volume model applied to different volume types, and
+ * registers a listener for receiving volume updates to apply on that device
+ * @param device the audio device set to absolute multi-volume mode
+ * @param volumes the list of volumes the given device responds to
+ * @param executor the Executor used for receiving volume updates through the listener
+ * @param vclistener the callback for volume updates
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void setDeviceAbsoluteMultiVolumeBehavior(
+ @NonNull AudioDeviceAttributes device,
+ @NonNull List<VolumeInfo> volumes,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+ Objects.requireNonNull(device);
+ Objects.requireNonNull(volumes);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(vclistener);
+
+ // TODO verify not already registered
+ //final ListenerInfo listenerInfo = new ListenerInfo(vclistener, executor, device);
+ synchronized (mDeviceVolumeListenerLock) {
+ if (mDeviceVolumeListeners == null) {
+ mDeviceVolumeListeners = new ArrayList<>();
+ }
+ if (mDeviceVolumeListeners.size() == 0) {
+ if (mDeviceVolumeDispatcherStub == null) {
+ mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub();
+ }
+ }
+ mDeviceVolumeDispatcherStub.register(true, device, volumes);
+ }
+ }
+
+ private static IAudioService getService() {
+ if (sService != null) {
+ return sService;
+ }
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ return sService;
+ }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3887372..6e695e6 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7294,8 +7294,13 @@
* Ultrasound playback and capture, false otherwise.
*/
@SystemApi
- public static boolean isUltrasoundSupported() {
- return AudioSystem.isUltrasoundSupported();
+ @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
+ public boolean isUltrasoundSupported() {
+ try {
+ return getService().isUltrasoundSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
similarity index 65%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
index 3091df3..65633fe 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-package android.window;
+package android.media;
+
+import android.media.AudioDeviceAttributes;
+import android.media.VolumeInfo;
/**
- * @hide
+ * AIDL for the AudioService to signal audio device volume changes.
+ *
+ * {@hide}
*/
-oneway interface IOnFpsCallbackListener {
+oneway interface IAudioDeviceVolumeDispatcher {
- /**
- * Reports the fps from the registered task
- * @param fps The frame rate per second of the task that has the registered task id
- * and its children.
- */
- void onFpsReported(in float fps);
+ void dispatchDeviceVolumeChanged(in AudioDeviceAttributes device, in VolumeInfo vol);
+
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index a6fdf6c..d702eb9 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -44,6 +45,7 @@
import android.media.IVolumeController;
import android.media.IVolumeController;
import android.media.PlayerBase;
+import android.media.VolumeInfo;
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.AudioProductStrategy;
@@ -136,6 +138,8 @@
boolean isMicrophoneMuted();
+ boolean isUltrasoundSupported();
+
void setMicrophoneMute(boolean on, String callingPackage, int userId, in String attributionTag);
oneway void setMicrophoneMuteFromSwitch(boolean on);
@@ -456,6 +460,8 @@
boolean isVolumeFixed();
+ VolumeInfo getDefaultVolumeInfo();
+
boolean isPstnCallAudioInterceptable();
oneway void muteAwaitConnection(in int[] usagesToMute, in AudioDeviceAttributes dev,
@@ -474,6 +480,7 @@
boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
+
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
void addAssistantServicesUids(in int[] assistantUID);
@@ -488,4 +495,10 @@
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
int[] getActiveAssistantServiceUids();
+
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+ void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+ in IAudioDeviceVolumeDispatcher cb,
+ in String packageName,
+ in AudioDeviceAttributes device, in List<VolumeInfo> volumes);
}
diff --git a/media/java/android/media/VolumeInfo.aidl b/media/java/android/media/VolumeInfo.aidl
new file mode 100644
index 0000000..aa82f52
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable VolumeInfo;
diff --git a/media/java/android/media/VolumeInfo.java b/media/java/android/media/VolumeInfo.java
new file mode 100644
index 0000000..c61b0e5
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.java
@@ -0,0 +1,380 @@
+/*
+ * 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 android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.audiopolicy.AudioVolumeGroup;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @hide
+ * A class to represent type of volume information.
+ * Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
+ * Volume index is optional when used to represent a category of volume.
+ * Index ranges are supported too, making the representation of volume changes agnostic to the
+ * range (e.g. can be used to map BT A2DP absolute volume range to internal range).
+ *
+ * Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
+ * particularly in parts of the audio framework that suffer from code ambiguity when
+ * dealing with different volume ranges / units.
+ */
+public final class VolumeInfo implements Parcelable {
+ private static final String TAG = "VolumeInfo";
+
+ private final boolean mUsesStreamType; // false implies AudioVolumeGroup is used
+ private final boolean mIsMuted;
+ private final int mVolIndex;
+ private final int mMinVolIndex;
+ private final int mMaxVolIndex;
+ private final int mVolGroupId;
+ private final int mStreamType;
+
+ private static IAudioService sService;
+ private static VolumeInfo sDefaultVolumeInfo;
+
+ private VolumeInfo(boolean usesStreamType, boolean isMuted, int volIndex,
+ int minVolIndex, int maxVolIndex,
+ int volGroupId, int streamType) {
+ mUsesStreamType = usesStreamType;
+ mIsMuted = isMuted;
+ mVolIndex = volIndex;
+ mMinVolIndex = minVolIndex;
+ mMaxVolIndex = maxVolIndex;
+ mVolGroupId = volGroupId;
+ mStreamType = streamType;
+ }
+
+ /**
+ * Indicates whether this instance has a stream type associated to it.
+ * Note this method returning true implies {@link #hasVolumeGroup()} returns false.
+ * (e.g. {@link AudioManager#STREAM_MUSIC}).
+ * @return true if it has stream type information
+ */
+ public boolean hasStreamType() {
+ return mUsesStreamType;
+ }
+
+ /**
+ * Returns the associated stream type, or will throw if {@link #hasStreamType()} returned false.
+ * @return a stream type value, see AudioManager.STREAM_*
+ */
+ public int getStreamType() {
+ if (!mUsesStreamType) {
+ throw new IllegalStateException("VolumeInfo doesn't use stream types");
+ }
+ return mStreamType;
+ }
+
+ /**
+ * Indicates whether this instance has a {@link AudioVolumeGroup} associated to it.
+ * Note this method returning true implies {@link #hasStreamType()} returns false.
+ * @return true if it has volume group information
+ */
+ public boolean hasVolumeGroup() {
+ return !mUsesStreamType;
+ }
+
+ /**
+ * Returns the associated volume group, or will throw if {@link #hasVolumeGroup()} returned
+ * false.
+ * @return the volume group corresponding to this VolumeInfo, or null if an error occurred
+ * in the volume group management
+ */
+ public @Nullable AudioVolumeGroup getVolumeGroup() {
+ if (mUsesStreamType) {
+ throw new IllegalStateException("VolumeInfo doesn't use AudioVolumeGroup");
+ }
+ List<AudioVolumeGroup> volGroups = AudioVolumeGroup.getAudioVolumeGroups();
+ for (AudioVolumeGroup group : volGroups) {
+ if (group.getId() == mVolGroupId) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether this instance is conveying a mute state.
+ * @return true if the volume state is muted
+ */
+ public boolean isMuted() {
+ return mIsMuted;
+ }
+
+ /**
+ * A value used to express no volume index has been set.
+ */
+ public static final int INDEX_NOT_SET = -100;
+
+ /**
+ * Returns the volume index.
+ * @return a volume index, or {@link #INDEX_NOT_SET} if no index was set, in which case this
+ * instance is used to express a volume representation type (stream vs group) and
+ * optionally its volume range
+ */
+ public int getVolumeIndex() {
+ return mVolIndex;
+ }
+
+ /**
+ * Returns the minimum volume index.
+ * @return the minimum volume index, or {@link #INDEX_NOT_SET} if no minimum index was set.
+ */
+ public int getMinVolumeIndex() {
+ return mMinVolIndex;
+ }
+
+ /**
+ * Returns the maximum volume index.
+ * @return the maximum volume index, or {@link #INDEX_NOT_SET} if no maximum index was
+ * set.
+ */
+ public int getMaxVolumeIndex() {
+ return mMaxVolIndex;
+ }
+
+ /**
+ * Returns the default info for the platform, typically initialized
+ * to STREAM_MUSIC with min/max initialized to the associated range
+ * @return the default VolumeInfo for the device
+ */
+ public static @NonNull VolumeInfo getDefaultVolumeInfo() {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+ sService = IAudioService.Stub.asInterface(b);
+ }
+ if (sDefaultVolumeInfo == null) {
+ try {
+ sDefaultVolumeInfo = sService.getDefaultVolumeInfo();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling getDefaultVolumeInfo", e);
+ // return a valid value, but don't cache it
+ return new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build();
+ }
+ }
+ return sDefaultVolumeInfo;
+ }
+
+ /**
+ * The builder class for creating and initializing, or copying and modifying VolumeInfo
+ * instances
+ */
+ public static final class Builder {
+ private boolean mUsesStreamType = true; // false implies AudioVolumeGroup is used
+ private int mStreamType = AudioManager.STREAM_MUSIC;
+ private boolean mIsMuted = false;
+ private int mVolIndex = INDEX_NOT_SET;
+ private int mMinVolIndex = INDEX_NOT_SET;
+ private int mMaxVolIndex = INDEX_NOT_SET;
+ private int mVolGroupId = -Integer.MIN_VALUE;
+
+ /**
+ * Builder constructor for stream type-based VolumeInfo
+ */
+ public Builder(int streamType) {
+ // TODO validate stream type
+ mUsesStreamType = true;
+ mStreamType = streamType;
+ }
+
+ /**
+ * Builder constructor for volume group-based VolumeInfo
+ */
+ public Builder(@NonNull AudioVolumeGroup volGroup) {
+ Objects.requireNonNull(volGroup);
+ mUsesStreamType = false;
+ mStreamType = -Integer.MIN_VALUE;
+ mVolGroupId = volGroup.getId();
+ }
+
+ /**
+ * Builder constructor to copy a given VolumeInfo.
+ * Note you can't change the stream type or volume group later.
+ */
+ public Builder(@NonNull VolumeInfo info) {
+ Objects.requireNonNull(info);
+ mUsesStreamType = info.mUsesStreamType;
+ mStreamType = info.mStreamType;
+ mIsMuted = info.mIsMuted;
+ mVolIndex = info.mVolIndex;
+ mMinVolIndex = info.mMinVolIndex;
+ mMaxVolIndex = info.mMaxVolIndex;
+ mVolGroupId = info.mVolGroupId;
+ }
+
+ /**
+ * Sets whether the volume is in a muted state
+ * @param isMuted
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMuted(boolean isMuted) {
+ mIsMuted = isMuted;
+ return this;
+ }
+
+ /**
+ * Sets the volume index
+ * @param volIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ // TODO should we allow muted true + volume index set? (useful when toggling mute on/off?)
+ public @NonNull Builder setVolumeIndex(int volIndex) {
+ if (volIndex != INDEX_NOT_SET && volIndex < 0) {
+ throw new IllegalArgumentException("Volume index cannot be negative");
+ }
+ mVolIndex = volIndex;
+ return this;
+ }
+
+ /**
+ * Sets the minimum volume index
+ * @param minIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMinVolumeIndex(int minIndex) {
+ if (minIndex != INDEX_NOT_SET && minIndex < 0) {
+ throw new IllegalArgumentException("Min volume index cannot be negative");
+ }
+ mMinVolIndex = minIndex;
+ return this;
+ }
+
+ /**
+ * Sets the maximum volume index
+ * @param maxIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+ * @return the same builder instance
+ */
+ public @NonNull Builder setMaxVolumeIndex(int maxIndex) {
+ if (maxIndex != INDEX_NOT_SET && maxIndex < 0) {
+ throw new IllegalArgumentException("Max volume index cannot be negative");
+ }
+ mMaxVolIndex = maxIndex;
+ return this;
+ }
+
+ /**
+ * Builds the VolumeInfo with the data given to the builder
+ * @return the new VolumeInfo instance
+ */
+ public @NonNull VolumeInfo build() {
+ if (mVolIndex != INDEX_NOT_SET) {
+ if (mMinVolIndex != INDEX_NOT_SET && mVolIndex < mMinVolIndex) {
+ throw new IllegalArgumentException("Volume index:" + mVolIndex
+ + " lower than min index:" + mMinVolIndex);
+ }
+ if (mMaxVolIndex != INDEX_NOT_SET && mVolIndex > mMaxVolIndex) {
+ throw new IllegalArgumentException("Volume index:" + mVolIndex
+ + " greater than max index:" + mMaxVolIndex);
+ }
+ }
+ if (mMinVolIndex != INDEX_NOT_SET && mMaxVolIndex != INDEX_NOT_SET
+ && mMinVolIndex > mMaxVolIndex) {
+ throw new IllegalArgumentException("Min volume index:" + mMinVolIndex
+ + " greater than max index:" + mMaxVolIndex);
+ }
+ return new VolumeInfo(mUsesStreamType, mIsMuted,
+ mVolIndex, mMinVolIndex, mMaxVolIndex,
+ mVolGroupId, mStreamType);
+ }
+ }
+
+ //-----------------------------------------------
+ // Parcelable
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUsesStreamType, mStreamType, mIsMuted,
+ mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroupId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VolumeInfo that = (VolumeInfo) o;
+ return ((mUsesStreamType == that.mUsesStreamType)
+ && (mStreamType == that.mStreamType)
+ && (mIsMuted == that.mIsMuted)
+ && (mVolIndex == that.mVolIndex)
+ && (mMinVolIndex == that.mMinVolIndex)
+ && (mMaxVolIndex == that.mMaxVolIndex)
+ && (mVolGroupId == that.mVolGroupId));
+ }
+
+ @Override
+ public String toString() {
+ return new String("VolumeInfo:"
+ + (mUsesStreamType ? (" streamType:" + mStreamType)
+ : (" volGroupId" + mVolGroupId))
+ + " muted:" + mIsMuted
+ + ((mVolIndex != INDEX_NOT_SET) ? (" volIndex:" + mVolIndex) : "")
+ + ((mMinVolIndex != INDEX_NOT_SET) ? (" min:" + mMinVolIndex) : "")
+ + ((mMaxVolIndex != INDEX_NOT_SET) ? (" max:" + mMaxVolIndex) : ""));
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mUsesStreamType);
+ dest.writeInt(mStreamType);
+ dest.writeBoolean(mIsMuted);
+ dest.writeInt(mVolIndex);
+ dest.writeInt(mMinVolIndex);
+ dest.writeInt(mMaxVolIndex);
+ dest.writeInt(mVolGroupId);
+ }
+
+ private VolumeInfo(@NonNull Parcel in) {
+ mUsesStreamType = in.readBoolean();
+ mStreamType = in.readInt();
+ mIsMuted = in.readBoolean();
+ mVolIndex = in.readInt();
+ mMinVolIndex = in.readInt();
+ mMaxVolIndex = in.readInt();
+ mVolGroupId = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<VolumeInfo> CREATOR =
+ new Parcelable.Creator<VolumeInfo>() {
+ /**
+ * Rebuilds a VolumeInfo previously stored with writeToParcel().
+ * @param p Parcel object to read the VolumeInfo from
+ * @return a new VolumeInfo created from the data in the parcel
+ */
+ public VolumeInfo createFromParcel(Parcel p) {
+ return new VolumeInfo(p);
+ }
+
+ public VolumeInfo[] newArray(int size) {
+ return new VolumeInfo[size];
+ }
+ };
+}
diff --git a/native/android/input.cpp b/native/android/input.cpp
index c06c81e..a231d8f 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -283,6 +283,21 @@
axis, pointer_index, history_index);
}
+int32_t AMotionEvent_getActionButton(const AInputEvent* motion_event) {
+ return static_cast<const MotionEvent*>(motion_event)->getActionButton();
+}
+
+int32_t AMotionEvent_getClassification(const AInputEvent* motion_event) {
+ switch (static_cast<const MotionEvent*>(motion_event)->getClassification()) {
+ case android::MotionClassification::NONE:
+ return AMOTION_EVENT_CLASSIFICATION_NONE;
+ case android::MotionClassification::AMBIGUOUS_GESTURE:
+ return AMOTION_EVENT_CLASSIFICATION_AMBIGUOUS_GESTURE;
+ case android::MotionClassification::DEEP_PRESS:
+ return AMOTION_EVENT_CLASSIFICATION_DEEP_PRESS;
+ }
+}
+
const AInputEvent* AMotionEvent_fromJava(JNIEnv* env, jobject motionEvent) {
MotionEvent* eventSrc = android::android_view_MotionEvent_getNativePtr(env, motionEvent);
if (eventSrc == nullptr) {
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 3009a36..67a98a9 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -114,8 +114,10 @@
ALooper_removeFd;
ALooper_wake;
AMotionEvent_getAction;
+ AMotionEvent_getActionButton; # introduced=Tiramisu
AMotionEvent_getAxisValue; # introduced-arm=13 introduced-arm64=21 introduced-mips=13 introduced-mips64=21 introduced-x86=13 introduced-x86_64=21
AMotionEvent_getButtonState; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
+ AMotionEvent_getClassification; # introduced=Tiramisu
AMotionEvent_getDownTime;
AMotionEvent_getEdgeFlags;
AMotionEvent_getEventTime;
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 0e60873..6ded1637 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -39,6 +39,7 @@
static_libs: [
"androidx.lifecycle_lifecycle-livedata",
"androidx.lifecycle_lifecycle-extensions",
+ "androidx.recyclerview_recyclerview",
"androidx.appcompat_appcompat",
],
diff --git a/core/res/res/drawable/default_dream_preview.xml b/packages/CompanionDeviceManager/res/color/selector.xml
similarity index 72%
rename from core/res/res/drawable/default_dream_preview.xml
rename to packages/CompanionDeviceManager/res/color/selector.xml
index bf4a04b..fda827d 100644
--- a/core/res/res/drawable/default_dream_preview.xml
+++ b/packages/CompanionDeviceManager/res/color/selector.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
@@ -15,6 +14,7 @@
~ limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
- <solid android:color="@android:color/white"/>
-</shape>
\ No newline at end of file
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@android:color/darker_gray"/> <!-- pressed -->
+ <item android:color="@android:color/white"/>
+</selector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
index 313e164..70cbfdf 100644
--- a/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/activity_confirmation.xml
@@ -49,8 +49,8 @@
android:layout_height="0dp"
android:layout_weight="1">
- <ListView
- android:id="@+id/device_list"
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/device_list"
style="@android:style/Widget.Material.ListView"
android:layout_width="match_parent"
android:layout_height="200dp" />
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index d79aea6..153fc1f 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -19,7 +19,8 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:padding="12dp">
+ android:padding="12dp"
+ android:background="@color/selector">
<!-- Do NOT change the ID of the root LinearLayout above: it's referenced in CTS tests. -->
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 9d3fc7f..b51d310 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -46,10 +46,13 @@
import android.util.Log;
import android.view.View;
import android.widget.Button;
-import android.widget.ListView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.List;
/**
* A CompanionDevice activity response for showing the available
@@ -92,9 +95,9 @@
// regular.
private Button mButtonAllow;
- // The list is only shown for multiple-device regular association request, after at least one
- // matching device is found.
- private @Nullable ListView mListView;
+ // The recycler view is only shown for multiple-device regular association request, after
+ // at least one matching device is found.
+ private @Nullable RecyclerView mRecyclerView;
private @Nullable DeviceListAdapter mAdapter;
// The flag used to prevent double taps, that may lead to sending several requests for creating
@@ -193,21 +196,19 @@
mTitle = findViewById(R.id.title);
mSummary = findViewById(R.id.summary);
- mListView = findViewById(R.id.device_list);
- mListView.setOnItemClickListener((av, iv, position, id) -> onListItemClick(position));
+ mRecyclerView = findViewById(R.id.device_list);
+ mAdapter = new DeviceListAdapter(this, this::onListItemClick);
mButtonAllow = findViewById(R.id.btn_positive);
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
final CharSequence appLabel = getApplicationLabel(this, mRequest.getPackageName());
+
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
} else if (mRequest.isSingleDevice()) {
- // TODO(b/211722613)
- // Treat singleDevice as the multipleDevices for now
- // initUiForSingleDevice(appLabel);
- initUiForMultipleDevices(appLabel);
+ initUiForSingleDevice(appLabel);
} else {
initUiForMultipleDevices(appLabel);
}
@@ -221,12 +222,6 @@
}
private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
- if (mSelectedDevice != null) {
- if (DEBUG) Log.w(TAG, "Already selected.");
- return;
- }
- mSelectedDevice = requireNonNull(selectedDevice);
-
final MacAddress macAddress = selectedDevice.getMacAddress();
onAssociationApproved(macAddress);
}
@@ -340,19 +335,32 @@
mTitle.setText(title);
mSummary.setText(summary);
- mListView.setVisibility(View.GONE);
+ mRecyclerView.setVisibility(View.GONE);
}
private void initUiForSingleDevice(CharSequence appLabel) {
if (DEBUG) Log.i(TAG, "initUiFor_SingleDevice()");
- // TODO: use real name
- final String deviceName = "<device>";
final String deviceProfile = mRequest.getDeviceProfile();
+ CompanionDeviceDiscoveryService.getScanResult().observe(this,
+ deviceFilterPairs -> updateSingleDeviceUi(
+ deviceFilterPairs, deviceProfile, appLabel));
+
+ mRecyclerView.setVisibility(View.GONE);
+ }
+
+ private void updateSingleDeviceUi(List<DeviceFilterPair<?>> deviceFilterPairs,
+ String deviceProfile, CharSequence appLabel) {
+ // Ignore "empty" scan reports.
+ if (deviceFilterPairs.isEmpty()) return;
+ mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
+
+ final String deviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
this, R.string.confirmation_title, appLabel, deviceName);
final Spanned summary;
+
if (deviceProfile == null) {
summary = getHtmlFromResources(this, R.string.summary_generic);
} else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
@@ -363,8 +371,6 @@
mTitle.setText(title);
mSummary.setText(summary);
-
- mListView.setVisibility(View.GONE);
}
private void initUiForMultipleDevices(CharSequence appLabel) {
@@ -389,10 +395,12 @@
mTitle.setText(title);
mSummary.setText(summary);
- mAdapter = new DeviceListAdapter(this);
+ mAdapter = new DeviceListAdapter(this, this::onListItemClick);
// TODO: hide the list and show a spinner until a first device matching device is found.
- mListView.setAdapter(mAdapter);
+ mRecyclerView.setAdapter(mAdapter);
+ mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
+
CompanionDeviceDiscoveryService.getScanResult().observe(
/* lifecycleOwner */ this,
/* observer */ mAdapter);
@@ -405,6 +413,16 @@
if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
+
+ if (mSelectedDevice != null) {
+ if (DEBUG) Log.w(TAG, "Already selected.");
+ return;
+ }
+ // Notify the adapter to highlight the selected item.
+ mAdapter.setSelectedPosition(position);
+
+ mSelectedDevice = requireNonNull(selectedDevice);
+
onUserSelectedDevice(selectedDevice);
}
@@ -417,9 +435,7 @@
if (mRequest.isSelfManaged()) {
onAssociationApproved(null);
} else {
- // TODO(b/211722613): call onUserSelectedDevice().
- throw new UnsupportedOperationException(
- "isSingleDevice() requests are not supported yet.");
+ onUserSelectedDevice(mSelectedDevice);
}
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5d48708..5f07fcf 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -103,6 +103,8 @@
private final Runnable mTimeoutRunnable = this::timeout;
+ private boolean mStopAfterFirstMatch;;
+
/**
* A state enum for devices' discovery.
*/
@@ -163,8 +165,7 @@
break;
case ACTION_STOP_DISCOVERY:
- stopDiscoveryAndFinish();
- sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+ stopDiscoveryAndFinish(/* timeout */ false);
break;
}
return START_NOT_STICKY;
@@ -182,6 +183,7 @@
requireNonNull(request);
if (mDiscoveryStarted) throw new RuntimeException("Discovery in progress.");
+ mStopAfterFirstMatch = request.isSingleDevice();
mDiscoveryStarted = true;
sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
sScanResultsLiveData.setValue(Collections.emptyList());
@@ -208,7 +210,7 @@
}
@MainThread
- private void stopDiscoveryAndFinish() {
+ private void stopDiscoveryAndFinish(boolean timeout) {
if (DEBUG) Log.i(TAG, "stopDiscovery()");
if (!mDiscoveryStarted) {
@@ -243,6 +245,12 @@
Handler.getMain().removeCallbacks(mTimeoutRunnable);
+ if (timeout) {
+ sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+ } else {
+ sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+ }
+
// "Finish".
stopSelf();
}
@@ -332,6 +340,7 @@
private void onDeviceFound(@NonNull DeviceFilterPair<?> device) {
runOnMainThread(() -> {
if (DEBUG) Log.v(TAG, "onDeviceFound() " + device);
+ if (mDiscoveryStopped) return;
if (mDevicesFound.contains(device)) {
// TODO: update the device instead of ignoring (new found device may contain
// additional/updated info, eg. name of the device).
@@ -347,6 +356,10 @@
mDevicesFound.add(device);
// Then: notify observers.
sScanResultsLiveData.setValue(mDevicesFound);
+ // Stop discovery when there's one device found for singleDevice.
+ if (mStopAfterFirstMatch) {
+ stopDiscoveryAndFinish(/* timeout */ false);
+ }
});
}
@@ -378,8 +391,7 @@
private void timeout() {
if (DEBUG) Log.i(TAG, "timeout()");
- stopDiscoveryAndFinish();
- sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+ stopDiscoveryAndFinish(/* timeout */ true);
}
@Override
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
index 198b778..e5513b0 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceListAdapter.java
@@ -15,73 +15,84 @@
*/
package com.android.companiondevicemanager;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.lifecycle.Observer;
+import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
-
/**
* Adapter for the list of "found" devices.
*/
-class DeviceListAdapter extends BaseAdapter implements Observer<List<DeviceFilterPair<?>>> {
+class DeviceListAdapter extends RecyclerView.Adapter<DeviceListAdapter.ViewHolder> implements
+ Observer<List<DeviceFilterPair<?>>> {
+ public int mSelectedPosition = RecyclerView.NO_POSITION;
+
private final Context mContext;
// List if pairs (display name, address)
private List<DeviceFilterPair<?>> mDevices;
- DeviceListAdapter(Context context) {
+ private OnItemClickListener mListener;
+
+ private static final int TYPE_WIFI = 0;
+ private static final int TYPE_BT = 1;
+
+ DeviceListAdapter(Context context, OnItemClickListener listener) {
mContext = context;
+ mListener = listener;
}
- @Override
- public int getCount() {
- return mDevices != null ? mDevices.size() : 0;
- }
-
- @Override
public DeviceFilterPair<?> getItem(int position) {
return mDevices.get(position);
}
@Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.list_item_device, parent, false);
+ ViewHolder viewHolder = new ViewHolder(view);
+ if (viewType == TYPE_WIFI) {
+ viewHolder.mImageView.setImageDrawable(getIcon(
+ com.android.internal.R.drawable.ic_wifi_signal_3));
+ } else {
+ viewHolder.mImageView.setImageDrawable(getIcon(
+ android.R.drawable.stat_sys_data_bluetooth));
+ }
+ return viewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.itemView.setSelected(mSelectedPosition == position);
+ holder.mTextView.setText(mDevices.get(position).getDisplayName());
+ holder.itemView.setOnClickListener(v -> mListener.onItemClick(position));
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return isWifiDevice(position) ? TYPE_WIFI : TYPE_BT;
+ }
+
+ @Override
public long getItemId(int position) {
return position;
}
@Override
- public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
- final View view = convertView != null
- ? convertView
- : LayoutInflater.from(mContext).inflate(R.layout.list_item_device, parent, false);
-
- final DeviceFilterPair<?> item = getItem(position);
- bindView(view, item);
-
- return view;
+ public int getItemCount() {
+ return mDevices != null ? mDevices.size() : 0;
}
- private void bindView(@NonNull View view, DeviceFilterPair<?> item) {
- final TextView textView = view.findViewById(android.R.id.text1);
- textView.setText(item.getDisplayName());
-
- final ImageView iconView = view.findViewById(android.R.id.icon);
-
- // TODO(b/211417476): Set either Bluetooth or WiFi icon.
- iconView.setVisibility(View.GONE);
- // final int iconRes = isBt ? android.R.drawable.stat_sys_data_bluetooth
- // : com.android.internal.R.drawable.ic_wifi_signal_3;
- // final Drawable icon = getTintedIcon(mResources, iconRes);
- // iconView.setImageDrawable(icon);
+ public void setSelectedPosition(int position) {
+ mSelectedPosition = position;
}
@Override
@@ -89,4 +100,28 @@
mDevices = deviceFilterPairs;
notifyDataSetChanged();
}
+
+ static class ViewHolder extends RecyclerView.ViewHolder {
+ private TextView mTextView;
+ private ImageView mImageView;
+ ViewHolder(View itemView) {
+ super(itemView);
+ mTextView = itemView.findViewById(android.R.id.text1);
+ mImageView = itemView.findViewById(android.R.id.icon);
+ }
+ }
+
+ private boolean isWifiDevice(int position) {
+ return mDevices.get(position).getDevice() instanceof android.net.wifi.ScanResult;
+ }
+
+ private Drawable getIcon(int resId) {
+ Drawable icon = mContext.getResources().getDrawable(resId, null);
+ icon.setTint(Color.DKGRAY);
+ return icon;
+ }
+
+ public interface OnItemClickListener {
+ void onItemClick(int position);
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index 1a955c4..72243f9 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -146,7 +146,7 @@
* @param iface the name of the interface.
* @param state the current state of the interface, or {@link #STATE_ABSENT} if the
* interface was removed.
- * @param role whether the interface is in the client mode or server mode.
+ * @param role whether the interface is in client mode or server mode.
* @param configuration the current IP configuration of the interface.
* @hide
*/
diff --git a/packages/SettingsLib/ActivityEmbedding/Android.bp b/packages/SettingsLib/ActivityEmbedding/Android.bp
index fc82b79..2569198 100644
--- a/packages/SettingsLib/ActivityEmbedding/Android.bp
+++ b/packages/SettingsLib/ActivityEmbedding/Android.bp
@@ -14,6 +14,8 @@
static_libs: [
"androidx.annotation_annotation",
+ "androidx.core_core",
+ "windowExtLib",
"SettingsLibUtils",
],
sdk_version: "system_current",
diff --git a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
index 7f17d26..44b3b4e 100644
--- a/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
+++ b/packages/SettingsLib/ActivityEmbedding/src/com/android/settingslib/activityembedding/ActivityEmbeddingUtils.java
@@ -16,8 +16,14 @@
package com.android.settingslib.activityembedding;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import androidx.core.os.BuildCompat;
+import androidx.window.embedding.SplitController;
import com.android.settingslib.utils.BuildCompatUtils;
@@ -44,6 +50,33 @@
return false;
}
+ /**
+ * Whether current activity is embedded in the Settings app or not.
+ */
+ public static boolean isActivityEmbedded(Activity activity) {
+ return SplitController.getInstance().isActivityEmbedded(activity);
+ }
+
+ /**
+ * Whether current activity is suggested to show back button or not.
+ */
+ public static boolean shouldHideBackButton(Activity activity, boolean isSecondaryLayerPage) {
+ if (!BuildCompat.isAtLeastT()) {
+ return false;
+ }
+ if (!isSecondaryLayerPage) {
+ return false;
+ }
+ final String shouldHideBackButton = Settings.Global.getString(activity.getContentResolver(),
+ "settings_hide_secondary_page_back_button_in_two_pane");
+
+ if (TextUtils.isEmpty(shouldHideBackButton)
+ || TextUtils.equals("true", shouldHideBackButton)) {
+ return isActivityEmbedded(activity);
+ }
+ return false;
+ }
+
private ActivityEmbeddingUtils() {
}
}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 684f4de..7a5ea47 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -48,7 +48,6 @@
"SettingsLibCollapsingToolbarBaseActivity",
"SettingsLibTwoTargetPreference",
"SettingsLibSettingsTransition",
- "SettingsLibActivityEmbedding",
"SettingsLibButtonPreference",
"setupdesign",
],
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 30748e6..d2a4de4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
android:tint="?android:attr/colorAccent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@android:drawable/ic_info"
+ android:src="@drawable/settingslib_ic_info"
android:visibility="gone" />
<Switch
diff --git a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
index 923d022..52d7775 100644
--- a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
+++ b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
@@ -34,14 +34,4 @@
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:textColor="?android:attr/textColorAlertDialogListItem" />
- <ImageView
- android:id="@+id/restricted_icon"
- android:layout_width="@*android:dimen/config_restrictedIconSize"
- android:layout_height="@*android:dimen/config_restrictedIconSize"
- android:layout_alignParentRight="true"
- android:scaleType="centerInside"
- android:src="@*android:drawable/ic_info"
- android:tint="?android:attr/colorAccent"
- android:visibility="gone" />
-
</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml b/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
deleted file mode 100644
index 69df751..0000000
--- a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <include layout="@layout/restricted_icon"/>
-
- <include layout="@layout/preference_widget_primary_switch"/>
-</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
deleted file mode 100644
index 1520ac8..0000000
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/restricted_icon"
- android:layout_width="@dimen/two_target_min_width"
- android:layout_height="@*android:dimen/config_restrictedIconSize"
- android:tint="?android:attr/colorAccent"
- android:src="@*android:drawable/ic_info"
- android:gravity="center" />
- <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
- <Switch xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/switch_widget"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:focusable="false"
- android:clickable="false"
- android:background="@null" />
-</merge>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 25d6c555..d893d09 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -22,8 +22,6 @@
<!-- The translation for disappearing security views after having solved them. -->
<dimen name="disappear_y_translation">-32dp</dimen>
- <dimen name="circle_avatar_size">190dp</dimen>
-
<!-- Height of a user icon view -->
<dimen name="user_icon_view_height">24dp</dimen>
<!-- User spinner -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
index 246fc8dd..b43b444 100644
--- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -59,7 +59,7 @@
@Override
protected int getSecondTargetResId() {
- return R.layout.restricted_preference_widget_primary_switch;
+ return R.layout.preference_widget_primary_switch;
}
@Override
@@ -67,7 +67,6 @@
super.onBindViewHolder(holder);
final View switchWidget = holder.findViewById(R.id.switchWidget);
if (switchWidget != null) {
- switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
switchWidget.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 81146fa..db2a6ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -22,7 +22,6 @@
import android.os.Process;
import android.os.UserHandle;
import android.util.AttributeSet;
-import android.view.View;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.PreferenceManager;
@@ -67,23 +66,9 @@
}
@Override
- protected int getSecondTargetResId() {
- return R.layout.restricted_icon;
- }
-
- @Override
- protected boolean shouldHideSecondTarget() {
- return !isDisabledByAdmin();
- }
-
- @Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
- final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
- if (restrictedIcon != null) {
- restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
- }
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 342189d..c607d74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -46,7 +46,6 @@
public RestrictedSwitchPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- setWidgetLayoutResource(R.layout.restricted_switch_widget);
mHelper = new RestrictedPreferenceHelper(context, this, attrs);
if (attrs != null) {
final TypedArray attributes = context.obtainStyledAttributes(attrs,
@@ -108,15 +107,6 @@
switchSummary = mRestrictedSwitchSummary;
}
- final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
- final View switchWidget = holder.findViewById(android.R.id.switch_widget);
- if (restrictedIcon != null) {
- restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
- }
- if (switchWidget != null) {
- switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
- }
-
final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
if (mIconSize > 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 883e080..f6e3557 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -144,7 +144,7 @@
* Returns a circular icon for a user.
*/
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
- final int iconSize = UserIconDrawable.getSizeForList(context);
+ final int iconSize = UserIconDrawable.getDefaultSize(context);
if (user.isManagedProfile()) {
Drawable drawable = UserIconDrawable.getManagedUserDrawable(context);
drawable.setBounds(0, 0, iconSize, iconSize);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
index e5ea446..7db00f3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -31,8 +31,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
-import com.android.settingslib.R;
-
/**
* Converts the user avatar icon to a circularly clipped one.
* TODO: Move this to an internal framework class and share with the one in Keyguard.
@@ -49,9 +47,9 @@
public static CircleFramedDrawable getInstance(Context context, Bitmap icon) {
Resources res = context.getResources();
- float iconSize = res.getDimension(R.dimen.circle_avatar_size);
+ int iconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.user_icon_size);
- CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize);
+ CircleFramedDrawable instance = new CircleFramedDrawable(icon, iconSize);
return instance;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 035fafd..d01f2b4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -49,8 +49,6 @@
import androidx.annotation.VisibleForTesting;
import androidx.core.os.BuildCompat;
-import com.android.settingslib.R;
-
/**
* Converts the user avatar icon to a circularly clipped one with an optional badge and frame
*/
@@ -120,8 +118,9 @@
* @param context
* @return size in pixels
*/
- public static int getSizeForList(Context context) {
- return (int) context.getResources().getDimension(R.dimen.circle_avatar_size);
+ public static int getDefaultSize(Context context) {
+ return context.getResources()
+ .getDimensionPixelSize(com.android.internal.R.dimen.user_icon_size);
}
public UserIconDrawable() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index bd3deae..fcb56d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -50,7 +50,6 @@
public class DreamBackend {
private static final String TAG = "DreamBackend";
private static final boolean DEBUG = false;
- private final Drawable mDreamPreviewDefault;
public static class DreamInfo {
public CharSequence caption;
@@ -135,8 +134,6 @@
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefault = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
- mDreamPreviewDefault = resources.getDrawable(
- com.android.internal.R.drawable.default_dream_preview);
mDisabledDreams = Arrays.stream(resources.getStringArray(
com.android.internal.R.array.config_disabledDreamComponents))
.map(ComponentName::unflattenFromString)
@@ -182,9 +179,6 @@
dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
dreamInfo.previewImage = dreamMetadata.previewImage;
}
- if (dreamInfo.previewImage == null) {
- dreamInfo.previewImage = mDreamPreviewDefault;
- }
dreamInfos.add(dreamInfo);
}
dreamInfos.sort(mComparator);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index f8bb38b..5862f60 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -16,19 +16,17 @@
package com.android.settingslib.users;
-import android.annotation.NonNull;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.widget.ImageView;
import com.android.internal.util.UserIcons;
-import com.android.settingslib.R;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.settingslib.utils.ThreadUtils;
@@ -114,10 +112,10 @@
private void onDefaultIconSelected(int tintColor) {
try {
ThreadUtils.postOnBackgroundThread(() -> {
+ Resources res = mActivity.getResources();
Drawable drawable =
- UserIcons.getDefaultUserIconInColor(mActivity.getResources(), tintColor);
- Bitmap bitmap = convertToBitmap(drawable,
- (int) mActivity.getResources().getDimension(R.dimen.circle_avatar_size));
+ UserIcons.getDefaultUserIconInColor(res, tintColor);
+ Bitmap bitmap = UserIcons.convertToBitmapAtUserIconSize(res, drawable);
ThreadUtils.postOnMainThread(() -> onPhotoProcessed(bitmap));
}).get();
@@ -126,14 +124,6 @@
}
}
- private static Bitmap convertToBitmap(@NonNull Drawable icon, int size) {
- Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- icon.setBounds(0, 0, size, size);
- icon.draw(canvas);
- return bitmap;
- }
-
private void onPhotoCropped(final Uri data) {
ThreadUtils.postOnBackgroundThread(() -> {
InputStream imageStream = null;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
index 4e2b63b..9c16740 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -53,13 +53,7 @@
mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
com.android.settingslib.R.layout.preference_two_target, null));
mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame);
- inflater.inflate(R.layout.restricted_preference_widget_primary_switch, mWidgetView, true);
- }
-
- @Test
- public void createNewPreference_shouldSetLayout() {
- assertThat(mPreference.getWidgetLayoutResource())
- .isEqualTo(R.layout.restricted_preference_widget_primary_switch);
+ inflater.inflate(R.layout.preference_widget_primary_switch, mWidgetView, true);
}
@Test
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 208825c..d8b050a 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -76,14 +76,14 @@
enum class Style(internal val coreSpec: CoreSpec) {
SPRITZ(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
- a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
- a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
+ a1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
+ a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
+ a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0))
+ n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0))
)),
TONAL_SPOT(CoreSpec(
- a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
+ a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 32.0)),
a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 4.0)),
@@ -91,17 +91,17 @@
)),
VIBRANT(CoreSpec(
a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
- a2 = TonalSpec(Hue(HueStrategy.ADD, 10.0), Chroma(ChromaStrategy.EQ, 24.0)),
- a3 = TonalSpec(Hue(HueStrategy.ADD, 20.0), Chroma(ChromaStrategy.GTE, 32.0)),
+ a2 = TonalSpec(Hue(HueStrategy.ADD, 15.0), Chroma(ChromaStrategy.EQ, 24.0)),
+ a3 = TonalSpec(Hue(HueStrategy.ADD, 30.0), Chroma(ChromaStrategy.GTE, 32.0)),
n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 8.0)),
n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
)),
EXPRESSIVE(CoreSpec(
- a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 40.0), Chroma(ChromaStrategy.GTE, 64.0)),
- a2 = TonalSpec(Hue(HueStrategy.ADD, 20.0), Chroma(ChromaStrategy.EQ, 24.0)),
- a3 = TonalSpec(Hue(HueStrategy.SUBTRACT, 80.0), Chroma(ChromaStrategy.GTE, 64.0)),
- n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
- n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 32.0))
+ a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 60.0), Chroma(ChromaStrategy.GTE, 64.0)),
+ a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 30.0), Chroma(ChromaStrategy.EQ, 24.0)),
+ a3 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
+ n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 12.0)),
+ n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
)),
RAINBOW(CoreSpec(
a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index 757ed76..b33c544 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -91,6 +91,9 @@
* areas, false otherwise
*/
static boolean isInAreas(ArrayList<Rect> areas, View view) {
+ if (areas.isEmpty()) {
+ return true;
+ }
for (Rect area : areas) {
if (isInArea(area, view)) {
return true;
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index cf69512..6352f81 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -1,16 +1,22 @@
# Preserve line number information for debugging stack traces.
-keepattributes SourceFile,LineNumberTable
+-keep class com.android.systemui.recents.OverviewProxyRecentsImpl
+-keep class com.android.systemui.statusbar.car.CarStatusBar
+-keep class com.android.systemui.statusbar.phone.StatusBar
+-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
-keep class com.android.systemui.SystemUIFactory
-keep class com.android.systemui.tv.TvSystemUIFactory
+-keep class * extends com.android.systemui.CoreStartable
+-keep class * implements com.android.systemui.CoreStartable$Injector
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keep class ** extends androidx.preference.PreferenceFragment
-
+-keep class com.android.systemui.tuner.*
-keep class com.android.systemui.plugins.** {
*;
}
@@ -19,6 +25,10 @@
}
-keep class androidx.core.app.CoreComponentFactory
+-keep public class * extends com.android.systemui.CoreStartable {
+ public <init>(android.content.Context);
+}
+
# Keep the wm shell lib
-keep class com.android.wm.shell.*
# Keep the protolog group methods that are called by the generated code
@@ -26,6 +36,11 @@
*;
}
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.GlobalRootComponent$SysUIComponentImpl { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.dagger.Dagger** { !synthetic *; }
+-keep,allowoptimization,allowaccessmodification class com.android.systemui.tv.Dagger** { !synthetic *; }
+
# Allows proguard to make private and protected methods and fields public as
# part of optimization. This lets proguard inline trivial getter/setter methods.
-allowaccessmodification
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index b7265b9..51211a0 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -86,6 +86,36 @@
</LinearLayout>
<LinearLayout
+ android:id="@+id/cast_app_section"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/dialog_side_padding"
+ android:layout_marginEnd="@dimen/dialog_side_padding"
+ android:layout_marginBottom="@dimen/dialog_bottom_padding"
+ android:orientation="vertical"
+ android:visibility="gone">
+ <TextView
+ android:id="@+id/launch_app_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorPrimary"
+ android:text="@string/media_output_dialog_launch_app_text"
+ android:maxLines="1"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textSize="16sp"/>
+
+ <Button
+ android:id="@+id/launch_app_button"
+ style="@style/Widget.Dialog.Button.BorderButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawablePadding="5dp"/>
+ </LinearLayout>
+
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 47ffb18..a08d824 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1121,6 +1121,7 @@
<dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
<dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
<dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
+ <dimen name="media_output_dialog_app_tier_icon_size">20dp</dimen>
<!-- Distance that the full shade transition takes in order for qs to fully transition to the
shade -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3b7e9d4..d4cc718 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2205,6 +2205,11 @@
<string name="media_output_dialog_connect_failed">Can\'t switch. Tap to try again.</string>
<!-- Title for pairing item [CHAR LIMIT=60] -->
<string name="media_output_dialog_pairing_new">Pair new device</string>
+ <!-- Title for launch app [CHAR LIMIT=60] -->
+ <string name="media_output_dialog_launch_app_text">To cast this session, please open the app.</string>
+ <!-- App name when can't get app name [CHAR LIMIT=60] -->
+ <string name="media_output_dialog_unknown_launch_app_name">Unknown app</string>
+
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_clip_data_label">Build number</string>
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b96c5ae..13067bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -42,6 +42,7 @@
import com.android.systemui.flags.FlagsModule;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.log.dagger.LogModule;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.BcSmartspaceDataPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -86,6 +87,7 @@
import com.android.systemui.wallet.dagger.WalletModule;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.DynamicOverride;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -214,4 +216,19 @@
groupManager, entryManager, notifCollection, notifPipeline, sysUiState,
notifPipelineFlags, dumpManager, sysuiMainExecutor));
}
+
+ @BindsOptionalOf
+ @DynamicOverride
+ abstract LowLightClockController optionalLowLightClockController();
+
+ @SysUISingleton
+ @Provides
+ static Optional<LowLightClockController> provideLowLightClockController(
+ @DynamicOverride Optional<LowLightClockController> optionalController) {
+ if (optionalController.isPresent() && optionalController.get().isLowLightClockEnabled()) {
+ return optionalController;
+ } else {
+ return Optional.empty();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 239109a..c8720e4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -288,7 +288,7 @@
for (TriggerSensor triggerSensor : mTriggerSensors) {
triggerSensor.setListening(false);
}
- mProximitySensor.pause();
+ mProximitySensor.destroy();
mDevicePostureController.removeCallback(mDevicePostureCallback);
mAuthController.removeCallback(mAuthControllerCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 68b74bd..8bff3ba 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -228,6 +228,7 @@
@Override
public void destroy() {
mDozeSensors.destroy();
+ mProxCheck.destroy();
}
private void onNotification(Runnable onPulseSuppressedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 4dacf65..338a8b2 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -132,6 +132,7 @@
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
+ mStateController.setShouldShowComplications(shouldShowComplications());
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index bc5a52a..fc71e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -16,6 +16,7 @@
package com.android.systemui.dreams;
+import android.service.dreams.DreamService;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -84,6 +85,8 @@
@Complication.ComplicationType
private int mAvailableComplicationTypes = Complication.COMPLICATION_TYPE_NONE;
+ private boolean mShouldShowComplications = DreamService.DEFAULT_SHOW_COMPLICATIONS;
+
private final Collection<Complication> mComplications = new HashSet();
@VisibleForTesting
@@ -131,7 +134,12 @@
.filter(complication -> {
@Complication.ComplicationType
final int requiredTypes = complication.getRequiredTypeAvailability();
- return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
+ // If it should show complications, show ones whose required types are
+ // available. Otherwise, only show ones that don't require types.
+ if (mShouldShowComplications) {
+ return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
+ }
+ return requiredTypes == Complication.COMPLICATION_TYPE_NONE;
})
.collect(Collectors.toCollection(HashSet::new))
: mComplications);
@@ -221,7 +229,24 @@
public void setAvailableComplicationTypes(@Complication.ComplicationType int types) {
mExecutor.execute(() -> {
mAvailableComplicationTypes = types;
- mCallbacks.forEach(callback -> callback.onAvailableComplicationTypesChanged());
+ mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
+ });
+ }
+
+ /**
+ * Returns whether the dream overlay should show complications.
+ */
+ public boolean getShouldShowComplications() {
+ return mShouldShowComplications;
+ }
+
+ /**
+ * Sets whether the dream overlay should show complications.
+ */
+ public void setShouldShowComplications(boolean shouldShowComplications) {
+ mExecutor.execute(() -> {
+ mShouldShowComplications = shouldShowComplications;
+ mCallbacks.forEach(Callback::onAvailableComplicationTypesChanged);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 55e48a7..dd36fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -111,7 +111,7 @@
public static final ResourceBooleanFlag QS_USER_DETAIL_SHORTCUT =
new ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut);
- public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, false);
+ public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, true);
public static final BooleanFlag NEW_HEADER = new BooleanFlag(505, false);
public static final ResourceBooleanFlag FULL_SCREEN_USER_SWITCHER =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index b96eee7..88555ed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -102,7 +102,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
new file mode 100644
index 0000000..0b15f4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
@@ -0,0 +1,48 @@
+/*
+ * 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.lowlightclock;
+
+import android.view.ViewGroup;
+
+/**
+ * A controller responsible for attaching and showing an optional low-light clock while dozing.
+ */
+public interface LowLightClockController {
+ /**
+ * Returns {@code true} if the low-light clock is enabled.
+ */
+ boolean isLowLightClockEnabled();
+
+ /**
+ * Attach the low light-clock to the given parent {@link ViewGroup}.
+ * @param parent The parent {@link ViewGroup} to which the low-light clock view should be
+ * attached.
+ */
+ void attachLowLightClockView(ViewGroup parent);
+
+ /**
+ * Show or hide the low-light clock.
+ * @param show Whether to show the low-light clock.
+ * @return {@code true} if the low-light clock was shown.
+ */
+ boolean showLowLightClock(boolean show);
+
+ /**
+ * An opportunity to perform burn-in prevention.
+ */
+ void dozeTimeTick();
+}
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 e55b25f..7bb5454 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -21,10 +21,15 @@
import android.app.WallpaperColors;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Bundle;
@@ -76,8 +81,10 @@
private ImageView mAppResourceIcon;
private RecyclerView mDevicesRecyclerView;
private LinearLayout mDeviceListLayout;
+ private LinearLayout mCastAppLayout;
private Button mDoneButton;
private Button mStopButton;
+ private Button mAppButton;
private int mListMaxHeight;
private WallpaperColors mWallpaperColors;
@@ -129,7 +136,9 @@
mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
mDoneButton = mDialogView.requireViewById(R.id.done);
mStopButton = mDialogView.requireViewById(R.id.stop);
+ mAppButton = mDialogView.requireViewById(R.id.launch_app_button);
mAppResourceIcon = mDialogView.requireViewById(R.id.app_source_icon);
+ mCastAppLayout = mDialogView.requireViewById(R.id.cast_app_section);
mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
mDeviceListLayoutListener);
@@ -144,6 +153,13 @@
mMediaOutputController.releaseSession();
dismiss();
});
+ mAppButton.setOnClickListener(v -> {
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ if (mMediaOutputController.getAppLaunchIntent() != null) {
+ mContext.startActivity(mMediaOutputController.getAppLaunchIntent());
+ }
+ dismiss();
+ });
}
@Override
@@ -169,8 +185,16 @@
final IconCompat iconCompat = getHeaderIcon();
final Drawable appSourceDrawable = getAppSourceIcon();
boolean colorSetUpdated = false;
+ mCastAppLayout.setVisibility(
+ mMediaOutputController.shouldShowLaunchSection()
+ ? View.VISIBLE : View.GONE);
if (appSourceDrawable != null) {
mAppResourceIcon.setImageDrawable(appSourceDrawable);
+ mAppButton.setCompoundDrawablesWithIntrinsicBounds(resizeDrawable(appSourceDrawable,
+ mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_app_tier_icon_size
+ )),
+ null, null, null);
} else {
mAppResourceIcon.setVisibility(View.GONE);
}
@@ -205,6 +229,7 @@
R.dimen.media_output_dialog_header_icon_padding);
mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
}
+ mAppButton.setText(mMediaOutputController.getAppSourceName());
// Update title and subtitle
mHeaderTitle.setText(getHeaderText());
final CharSequence subTitle = getHeaderSubtitle();
@@ -229,6 +254,22 @@
mStopButton.setVisibility(getStopButtonVisibility());
}
+ private Drawable resizeDrawable(Drawable drawable, int size) {
+ if (drawable == null) {
+ return null;
+ }
+ int width = drawable.getIntrinsicWidth();
+ int height = drawable.getIntrinsicHeight();
+ Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
+ : Bitmap.Config.RGB_565;
+ Bitmap bitmap = Bitmap.createBitmap(width, height, config);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, width, height);
+ drawable.draw(canvas);
+ return new BitmapDrawable(mContext.getResources(),
+ Bitmap.createScaledBitmap(bitmap, size, size, false));
+ }
+
abstract Drawable getAppSourceIcon();
abstract int getHeaderIconRes();
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 1c6b7dc..e141cccc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -22,6 +22,7 @@
import android.app.WallpaperColors;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
@@ -45,6 +46,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
+import androidx.mediarouter.media.MediaRouter;
+import androidx.mediarouter.media.MediaRouterParams;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.RestrictedLockUtilsInternal;
@@ -171,6 +174,12 @@
mLocalMediaManager.startScan();
}
+ boolean shouldShowLaunchSection() {
+ MediaRouterParams routerParams = MediaRouter.getInstance(mContext).getRouterParams();
+ Log.d(TAG, "try to get routerParams: " + routerParams);
+ return routerParams != null && !routerParams.isMediaTransferReceiverEnabled();
+ }
+
void stop() {
if (mMediaController != null) {
mMediaController.unregisterCallback(mCb);
@@ -220,6 +229,32 @@
}
}
+ String getAppSourceName() {
+ if (mPackageName.isEmpty()) {
+ return null;
+ }
+ final PackageManager packageManager = mContext.getPackageManager();
+ ApplicationInfo applicationInfo;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(mPackageName,
+ PackageManager.ApplicationInfoFlags.of(0));
+ } catch (PackageManager.NameNotFoundException e) {
+ applicationInfo = null;
+ }
+ final String applicationName =
+ (String) (applicationInfo != null ? packageManager.getApplicationLabel(
+ applicationInfo)
+ : mContext.getString(R.string.media_output_dialog_unknown_launch_app_name));
+ return applicationName;
+ }
+
+ Intent getAppLaunchIntent() {
+ if (mPackageName.isEmpty()) {
+ return null;
+ }
+ return mContext.getPackageManager().getLaunchIntentForPackage(mPackageName);
+ }
+
CharSequence getHeaderTitle() {
if (mMediaController != null) {
final MediaMetadata metadata = mMediaController.getMetadata();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 593b278c..6ea7aec 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -125,6 +125,7 @@
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
private int mNavBarMode;
+ private boolean mImeDrawsImeNavBar;
private final Region mTmpRegion = new Region();
private final int[] mTmpPosition = new int[2];
@@ -324,6 +325,7 @@
mIsVertical = false;
mLongClickableAccessibilityButton = false;
mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+ mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
mSysUiFlagContainer = Dependency.get(SysUiState.class);
// Set up the context group of buttons
@@ -773,7 +775,7 @@
updateRecentsIcon();
- boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode)
+ boolean isImeRenderingNavButtons = mImeDrawsImeNavBar
&& mImeCanRenderGesturalNavButtons
&& (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0;
@@ -966,6 +968,7 @@
@Override
public void onNavigationModeChanged(int mode) {
mNavBarMode = mode;
+ mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
mBarTransitions.onNavigationModeChanged(mNavBarMode);
mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
updateRotationButton();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 73a0c54..6920ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -156,6 +156,11 @@
mListeners.remove(listener);
}
+ public boolean getImeDrawsImeNavBar() {
+ return mCurrentUserContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_imeDrawsImeNavBar);
+ }
+
private int getCurrentInteractionMode(Context context) {
int mode = context.getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
index 6a6f572..e473dd2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
@@ -73,7 +74,7 @@
}
@Override
- protected void setDrawableTintList(ColorStateList tint) {
+ protected void setDrawableTintList(@Nullable ColorStateList tint) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
index 67cfc59..26399d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
@@ -27,6 +27,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.systemui.R;
import java.util.Objects;
@@ -48,6 +50,7 @@
private final TextView mSecondLine;
private final int mHorizontalPaddingPx;
+ @Nullable
private String mText;
public QSDualTileLabel(Context context) {
@@ -122,6 +125,7 @@
rescheduleUpdateText();
}
+ @Nullable
public String getText() {
return mText;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0c854df..5126fcb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -48,6 +48,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/** View that represents the quick settings tile panel (when expanded/pulled down). **/
public class QSPanel extends LinearLayout implements Tunable {
@@ -78,7 +79,7 @@
protected boolean mExpanded;
protected boolean mListening;
- protected QSTileHost mHost;
+ @Nullable protected QSTileHost mHost;
private final List<OnConfigurationChangedListener> mOnConfigurationChangedListeners =
new ArrayList<>();
@@ -92,14 +93,18 @@
@Nullable
private ViewGroup mHeaderContainer;
+ @Nullable
private PageIndicator mFooterPageIndicator;
private int mContentMarginStart;
private int mContentMarginEnd;
private boolean mUsingHorizontalLayout;
+ @Nullable
private LinearLayout mHorizontalLinearLayout;
+ @Nullable
protected LinearLayout mHorizontalContentContainer;
+ @Nullable
protected QSTileLayout mTileLayout;
private float mSquishinessFraction = 1f;
private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>();
@@ -284,7 +289,7 @@
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (move) {
- int top = mChildrenLayoutTop.get(child);
+ int top = Objects.requireNonNull(mChildrenLayoutTop.get(child));
child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset,
child.getRight(), top + tileHeightOffset + child.getHeight());
}
@@ -337,6 +342,7 @@
}
}
+ @Nullable
public QSTileHost getHost() {
return mHost;
}
@@ -501,7 +507,6 @@
mListening = listening;
}
-
protected void drawTile(QSPanelControllerBase.TileRecord r, QSTile.State state) {
r.tileView.onStateChanged(state);
}
@@ -548,6 +553,7 @@
return getMeasuredHeight();
}
+ @Nullable
QSTileLayout getTileLayout() {
return mTileLayout;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 0bff722..3172aa9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -76,6 +76,7 @@
private Consumer<Boolean> mMediaVisibilityChangedListener;
private int mLastOrientation;
private String mCachedSpecs = "";
+ @Nullable
private QSTileRevealController mQsTileRevealController;
private float mRevealExpansion;
@@ -185,6 +186,7 @@
mDumpManager.unregisterDumpable(mView.getDumpableTag());
}
+ @Nullable
protected QSTileRevealController createTileRevealController() {
return null;
}
@@ -250,6 +252,7 @@
return !mRecords.isEmpty();
}
+ @Nullable
QSTileView getTileView(QSTile tile) {
for (QSPanelControllerBase.TileRecord r : mRecords) {
if (r.tile == tile) {
@@ -411,6 +414,7 @@
mUsingHorizontalLayoutChangedListener = listener;
}
+ @Nullable
public View getBrightnessView() {
return mView.getBrightnessView();
}
@@ -425,6 +429,7 @@
public QSTile tile;
public com.android.systemui.plugins.qs.QSTileView tileView;
public boolean scanState;
+ @Nullable
public QSTile.Callback callback;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
index 4b705ad..6908e5a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrierGroupController.java
@@ -20,6 +20,7 @@
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
@@ -81,6 +82,7 @@
private final CarrierConfigTracker mCarrierConfigTracker;
private boolean mIsSingleCarrier;
+ @Nullable
private OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
private final SlotIndexResolver mSlotIndexResolver;
@@ -294,7 +296,8 @@
* This will get notified when the number of carriers changes between 1 and "not one".
* @param listener
*/
- public void setOnSingleCarrierChangedListener(OnSingleCarrierChangedListener listener) {
+ public void setOnSingleCarrierChangedListener(
+ @Nullable OnSingleCarrierChangedListener listener) {
mOnSingleCarrierChangedListener = listener;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 90cf92a..c1970b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -96,15 +96,20 @@
private int mFocusIndex;
private boolean mNeedsFocus;
+ @Nullable
private List<String> mCurrentSpecs;
+ @Nullable
private List<TileInfo> mOtherTiles;
+ @Nullable
private List<TileInfo> mAllTiles;
+ @Nullable
private Holder mCurrentDrag;
private int mAccessibilityAction = ACTION_NONE;
private int mAccessibilityFromIndex;
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
+ @Nullable
private RecyclerView mRecyclerView;
private int mNumColumns;
@@ -240,6 +245,7 @@
notifyDataSetChanged();
}
+ @Nullable
private TileInfo getAndRemoveOther(String s) {
for (int i = 0; i < mOtherTiles.size(); i++) {
if (mOtherTiles.get(i).spec.equals(s)) {
@@ -555,7 +561,7 @@
}
public class Holder extends ViewHolder {
- private QSTileViewImpl mTileView;
+ @Nullable private QSTileViewImpl mTileView;
public Holder(View itemView) {
super(itemView);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 106a1b6..7fb9ef3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -17,6 +17,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
@@ -49,6 +50,7 @@
private boolean mAnimationEnabled = true;
private int mState = -1;
private int mTint;
+ @Nullable
private QSTile.Icon mLastIcon;
public QSIconViewImpl(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e8d27ec..a70f534 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -316,5 +316,5 @@
public void onKeyguardShowingChanged() {
refreshState();
}
- };
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index f982790..4a9a1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -263,22 +263,29 @@
inoutInfo.touchableRegion.set(getTouchRegion(true));
}
- private Region getTouchRegion(boolean includeScrim) {
- Region touchRegion = new Region();
+ private Region getSwipeRegion() {
+ Region swipeRegion = new Region();
final Rect tmpRect = new Rect();
mScreenshotPreview.getBoundsOnScreen(tmpRect);
tmpRect.inset((int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
(int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP));
- touchRegion.op(tmpRect, Region.Op.UNION);
+ swipeRegion.op(tmpRect, Region.Op.UNION);
mActionsContainerBackground.getBoundsOnScreen(tmpRect);
tmpRect.inset((int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP),
(int) FloatingWindowUtil.dpToPx(mDisplayMetrics, -SWIPE_PADDING_DP));
- touchRegion.op(tmpRect, Region.Op.UNION);
+ swipeRegion.op(tmpRect, Region.Op.UNION);
mDismissButton.getBoundsOnScreen(tmpRect);
- touchRegion.op(tmpRect, Region.Op.UNION);
+ swipeRegion.op(tmpRect, Region.Op.UNION);
+
+ return swipeRegion;
+ }
+
+ private Region getTouchRegion(boolean includeScrim) {
+ Region touchRegion = getSwipeRegion();
if (includeScrim && mScrollingScrim.getVisibility() == View.VISIBLE) {
+ final Rect tmpRect = new Rect();
mScrollingScrim.getBoundsOnScreen(tmpRect);
touchRegion.op(tmpRect, Region.Op.UNION);
}
@@ -328,7 +335,7 @@
@Override // ViewGroup
public boolean onInterceptTouchEvent(MotionEvent ev) {
// scrolling scrim should not be swipeable; return early if we're on the scrim
- if (!getTouchRegion(false).contains((int) ev.getRawX(), (int) ev.getRawY())) {
+ if (!getSwipeRegion().contains((int) ev.getRawX(), (int) ev.getRawY())) {
return false;
}
// always pass through the down event so the swipe handler knows the initial state
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 72c4ce8..0fb6ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -427,15 +427,17 @@
typedValue, true);
float scaleFactor = typedValue.getFloat();
- // We downscale the loaded drawable to reasonable size to protect against applications
- // using too much memory. The size can be tweaked in config.xml. Drawables
- // that are already sized properly won't be touched.
- boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
- Resources res = sysuiContext.getResources();
- int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
- ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
- : com.android.internal.R.dimen.notification_small_icon_size);
- icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+ if (icon != null) {
+ // We downscale the loaded drawable to reasonable size to protect against applications
+ // using too much memory. The size can be tweaked in config.xml. Drawables that are
+ // already sized properly won't be touched.
+ boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+ Resources res = sysuiContext.getResources();
+ int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+ ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+ : com.android.internal.R.dimen.notification_small_icon_size);
+ icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+ }
// No need to scale the icon, so return it as is.
if (scaleFactor == 1.f) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 7811401..fcbe179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -507,6 +507,10 @@
pw.println(" mLeaveOpenOnKeyguardHide=" + mLeaveOpenOnKeyguardHide);
pw.println(" mKeyguardRequested=" + mKeyguardRequested);
pw.println(" mIsDozing=" + mIsDozing);
+ pw.println(" mListeners{" + mListeners.size() + "}=");
+ for (RankedListener rl : mListeners) {
+ pw.println(" " + rl.mListener);
+ }
pw.println(" Historical states:");
// Ignore records without a timestamp
int size = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
index d01fc93..10e90fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/ChargingRippleView.kt
@@ -55,7 +55,6 @@
rippleShader.progress = 0f
rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
ripplePaint.shader = rippleShader
- visibility = View.GONE
}
override fun onConfigurationChanged(newConfig: Configuration?) {
@@ -86,12 +85,10 @@
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
rippleInProgress = false
- visibility = View.GONE
onAnimationEnd?.run()
}
})
animator.start()
- visibility = View.VISIBLE
rippleInProgress = true
}
@@ -100,6 +97,11 @@
}
override fun onDraw(canvas: Canvas?) {
+ if (canvas == null || !canvas.isHardwareAccelerated) {
+ // Drawing with the ripple shader requires hardware acceleration, so skip
+ // if it's unsupported.
+ return
+ }
// To reduce overdraw, we mask the effect to a circle whose radius is big enough to cover
// the active effect area. Values here should be kept in sync with the
// animation implementation in the ripple shader.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
index 842be5b..48717e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/WiredChargingRippleController.kt
@@ -28,15 +28,15 @@
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.settingslib.Utils
+import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.leak.RotationUtils
-import com.android.systemui.R
-import com.android.systemui.flags.Flags
import com.android.systemui.util.time.SystemClock
import java.io.PrintWriter
import javax.inject.Inject
@@ -53,8 +53,8 @@
@SysUISingleton
class WiredChargingRippleController @Inject constructor(
commandRegistry: CommandRegistry,
- batteryController: BatteryController,
- configurationController: ConfigurationController,
+ private val batteryController: BatteryController,
+ private val configurationController: ConfigurationController,
featureFlags: FeatureFlags,
private val context: Context,
private val windowManager: WindowManager,
@@ -88,6 +88,11 @@
init {
pluggedIn = batteryController.isPluggedIn
+ commandRegistry.registerCommand("charging-ripple") { ChargingRippleCommand() }
+ updateRippleColor()
+ }
+
+ fun registerCallbacks() {
val batteryStateChangeCallback = object : BatteryController.BatteryStateChangeCallback {
override fun onBatteryLevelChanged(
level: Int,
@@ -123,9 +128,6 @@
}
}
configurationController.addCallback(configurationChangedListener)
-
- commandRegistry.registerCommand("charging-ripple") { ChargingRippleCommand() }
- updateRippleColor()
}
// Lazily debounce ripple to avoid triggering ripple constantly (e.g. from flaky chargers).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
index 6f8e5da..4ebf337 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
@@ -21,8 +21,9 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.util.ListenerSet
import com.android.systemui.util.concurrency.DelayableExecutor
+import dagger.Binds
import dagger.Module
-import dagger.Provides
+import javax.inject.Inject
/**
* Choreographs evaluation resulting from multiple asynchronous sources. Specifically, it exposes
@@ -46,22 +47,21 @@
fun removeOnEvalListener(onEvalListener: Runnable)
}
+@Module(includes = [PrivateModule::class])
+object NotifPipelineChoreographerModule
+
@Module
-object NotifPipelineChoreographerModule {
- @Provides
- @JvmStatic
- @SysUISingleton
- fun provideChoreographer(
- choreographer: Choreographer,
- @Main mainExecutor: DelayableExecutor
- ): NotifPipelineChoreographer = NotifPipelineChoreographerImpl(choreographer, mainExecutor)
+private interface PrivateModule {
+ @Binds
+ fun bindChoreographer(impl: NotifPipelineChoreographerImpl): NotifPipelineChoreographer
}
private const val TIMEOUT_MS: Long = 100
-private class NotifPipelineChoreographerImpl(
+@SysUISingleton
+private class NotifPipelineChoreographerImpl @Inject constructor(
private val viewChoreographer: Choreographer,
- private val executor: DelayableExecutor
+ @Main private val executor: DelayableExecutor
) : NotifPipelineChoreographer {
private val listeners = ListenerSet<Runnable>()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index 9c82cb6..72d0918 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -30,29 +30,24 @@
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
import com.android.systemui.statusbar.policy.KeyguardStateController
+import dagger.Binds
import dagger.Module
-import dagger.Provides
+import javax.inject.Inject
+
+@Module(includes = [PrivateModule::class])
+interface SensitiveContentCoordinatorModule
@Module
-object SensitiveContentCoordinatorModule {
- @Provides
- @JvmStatic
- @CoordinatorScope
- fun provideCoordinator(
- dynamicPrivacyController: DynamicPrivacyController,
- lockscreenUserManager: NotificationLockscreenUserManager,
- keyguardUpdateMonitor: KeyguardUpdateMonitor,
- statusBarStateController: StatusBarStateController,
- keyguardStateController: KeyguardStateController
- ): SensitiveContentCoordinator =
- SensitiveContentCoordinatorImpl(dynamicPrivacyController, lockscreenUserManager,
- keyguardUpdateMonitor, statusBarStateController, keyguardStateController)
+private interface PrivateModule {
+ @Binds
+ fun bindCoordinator(impl: SensitiveContentCoordinatorImpl): SensitiveContentCoordinator
}
/** Coordinates re-inflation and post-processing of sensitive notification content. */
interface SensitiveContentCoordinator : Coordinator
-private class SensitiveContentCoordinatorImpl(
+@CoordinatorScope
+private class SensitiveContentCoordinatorImpl @Inject constructor(
private val dynamicPrivacyController: DynamicPrivacyController,
private val lockscreenUserManager: NotificationLockscreenUserManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index b35e684..6d774838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -214,6 +214,7 @@
}
mStatusBarStateController.setIsDozing(dozing);
+ mNotificationShadeWindowViewController.setDozing(dozing);
}
@Override
@@ -294,6 +295,7 @@
public void dozeTimeTick() {
mNotificationPanel.dozeTimeTick();
mAuthController.dozeTimeTick();
+ mNotificationShadeWindowViewController.dozeTimeTick();
if (mAmbientIndicationContainer instanceof DozeReceiver) {
((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 4e2eb6a..396703b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -49,6 +50,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Optional;
import javax.inject.Inject;
@@ -84,6 +86,7 @@
private final DockManager mDockManager;
private final NotificationPanelViewController mNotificationPanelViewController;
private final PanelExpansionStateManager mPanelExpansionStateManager;
+ private final Optional<LowLightClockController> mLowLightClockController;
private boolean mIsTrackingBarGesture = false;
@@ -101,7 +104,8 @@
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
StatusBarWindowStateController statusBarWindowStateController,
- LockIconViewController lockIconViewController) {
+ LockIconViewController lockIconViewController,
+ Optional<LowLightClockController> lowLightClockController) {
mLockscreenShadeTransitionController = transitionController;
mFalsingCollector = falsingCollector;
mTunerService = tunerService;
@@ -115,6 +119,7 @@
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mStatusBarWindowStateController = statusBarWindowStateController;
mLockIconViewController = lockIconViewController;
+ mLowLightClockController = lowLightClockController;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -171,6 +176,8 @@
};
mGestureDetector = new GestureDetector(mView.getContext(), gestureListener);
+ mLowLightClockController.ifPresent(controller -> controller.attachLowLightClockView(mView));
+
mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
@Override
public Boolean handleDispatchTouchEvent(MotionEvent ev) {
@@ -450,6 +457,21 @@
mNotificationShadeWindowController = controller;
}
+ /**
+ * Tell the controller that dozing has begun or ended.
+ * @param dozing True if dozing has begun.
+ */
+ public void setDozing(boolean dozing) {
+ mLowLightClockController.ifPresent(controller -> controller.showLowLightClock(dozing));
+ }
+
+ /**
+ * Tell the controller to perform burn-in prevention.
+ */
+ public void dozeTimeTick() {
+ mLowLightClockController.ifPresent(LowLightClockController::dozeTimeTick);
+ }
+
@VisibleForTesting
void setDragDownHelper(DragDownHelper dragDownHelper) {
mDragDownHelper = dragDownHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index f13334e..8e4feb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -203,6 +203,7 @@
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -786,7 +787,8 @@
NotifPipelineFlags notifPipelineFlags,
InteractionJankMonitor jankMonitor,
DeviceStateManager deviceStateManager,
- DreamOverlayStateController dreamOverlayStateController) {
+ DreamOverlayStateController dreamOverlayStateController,
+ WiredChargingRippleController wiredChargingRippleController) {
super(context);
mNotificationsController = notificationsController;
mFragmentService = fragmentService;
@@ -912,6 +914,7 @@
deviceStateManager.registerCallback(mMainExecutor,
new FoldStateListener(mContext, this::onFoldedStateChanged));
+ wiredChargingRippleController.registerCallbacks();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 83bdd1b..c6b5b1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -233,7 +234,8 @@
NotifPipelineFlags notifPipelineFlags,
InteractionJankMonitor jankMonitor,
DeviceStateManager deviceStateManager,
- DreamOverlayStateController dreamOverlayStateController) {
+ DreamOverlayStateController dreamOverlayStateController,
+ WiredChargingRippleController wiredChargingRippleController) {
return new StatusBar(
context,
notificationsController,
@@ -330,7 +332,8 @@
notifPipelineFlags,
jankMonitor,
deviceStateManager,
- dreamOverlayStateController
+ dreamOverlayStateController,
+ wiredChargingRippleController
);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index 8471e0a..a32a5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -25,6 +25,7 @@
import com.android.internal.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.Assert;
import java.util.ArrayList;
import java.util.List;
@@ -70,6 +71,7 @@
}
deviceStateManager.registerCallback(executor, state -> {
+ Assert.isMainThread();
mCurrentDevicePosture =
mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
@@ -79,11 +81,13 @@
@Override
public void addCallback(@NonNull Callback listener) {
+ Assert.isMainThread();
mListeners.add(listener);
}
@Override
public void removeCallback(@NonNull Callback listener) {
+ Assert.isMainThread();
mListeners.remove(listener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 5e91a25..f52c6ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -272,7 +272,7 @@
}
boolean highPowerOp = areActiveHighPowerLocationRequests();
- mAreActiveLocationRequests = highPowerOp || shouldDisplay;
+ mAreActiveLocationRequests = shouldDisplay;
if (mAreActiveLocationRequests != hadActiveLocationRequests) {
mHandler.sendEmptyMessage(H.MSG_LOCATION_ACTIVE_CHANGED);
}
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 3205e09..48949f92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -118,7 +118,6 @@
private boolean mColorized;
private int mTint;
private boolean mResetting;
- private boolean mWasSpinning;
// TODO(b/193539698): move these to a Controller
private RemoteInputController mController;
@@ -440,10 +439,6 @@
mEditText.requestFocus();
}
}
- if (mWasSpinning) {
- mController.addSpinning(mEntry.getKey(), mToken);
- mWasSpinning = false;
- }
}
@Override
@@ -452,7 +447,6 @@
mEditText.removeTextChangedListener(mTextWatcher);
mEditText.setOnEditorActionListener(null);
mEditText.mRemoteInputView = null;
- mWasSpinning = mController.isSpinning(mEntry.getKey(), mToken);
if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) {
return;
}
@@ -539,8 +533,6 @@
if (isActive() && mWrapper != null) {
mWrapper.setRemoteInputVisible(true);
}
-
- mWasSpinning = false;
}
private void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserCreator.java b/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
index 3a270bb..0686071c 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
@@ -19,6 +19,7 @@
import android.app.Dialog;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.UserManager;
@@ -70,10 +71,12 @@
}
Drawable newUserIcon = userIcon;
+ Resources res = mContext.getResources();
if (newUserIcon == null) {
- newUserIcon = UserIcons.getDefaultUserIcon(mContext.getResources(), user.id, false);
+ newUserIcon = UserIcons.getDefaultUserIcon(res, user.id, false);
}
- mUserManager.setUserIcon(user.id, UserIcons.convertToBitmap(newUserIcon));
+ mUserManager.setUserIcon(
+ user.id, UserIcons.convertToBitmapAtUserIconSize(res, newUserIcon));
userCreationProgressDialog.dismiss();
successCallback.accept(user);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
index 40982bb..460b7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -37,6 +37,8 @@
private final ThresholdSensor[] mPostureToPrimaryProxSensorMap;
private final ThresholdSensor[] mPostureToSecondaryProxSensorMap;
+ private final DevicePostureController mDevicePostureController;
+
@Inject
PostureDependentProximitySensor(
@PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap,
@@ -53,15 +55,24 @@
);
mPostureToPrimaryProxSensorMap = postureToPrimaryProxSensorMap;
mPostureToSecondaryProxSensorMap = postureToSecondaryProxSensorMap;
- mDevicePosture = devicePostureController.getDevicePosture();
- devicePostureController.addCallback(mDevicePostureCallback);
+ mDevicePostureController = devicePostureController;
+
+ mDevicePosture = mDevicePostureController.getDevicePosture();
+ mDevicePostureController.addCallback(mDevicePostureCallback);
chooseSensors();
}
+
+ @Override
+ public void destroy() {
+ super.destroy();
+ mDevicePostureController.removeCallback(mDevicePostureCallback);
+ }
+
private void chooseSensors() {
if (mDevicePosture >= mPostureToPrimaryProxSensorMap.length
|| mDevicePosture >= mPostureToSecondaryProxSensorMap.length) {
- Log.e("PostureDependentProxSensor",
+ Log.e("PostureDependProxSensor",
"unsupported devicePosture=" + mDevicePosture);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
index a8a6341..c06a3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
@@ -73,6 +73,13 @@
}
}
+ /**
+ * Cleanup after no longer needed.
+ */
+ public void destroy() {
+ mSensor.destroy();
+ }
+
private void unregister() {
mSensor.unregister(mListener);
mRegistered.set(false);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index d3f1c93..7f64322 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -42,4 +42,10 @@
* of what is reported by the primary sensor.
*/
void setSecondarySafe(boolean safe);
+
+ /**
+ * Called when the proximity sensor is no longer needed. All listeners should
+ * be unregistered and cleaned up.
+ */
+ void destroy();
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
index 5568f64..8ab5bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -252,6 +252,11 @@
}
@Override
+ public void destroy() {
+ pause();
+ }
+
+ @Override
public String getName() {
return mPrimaryThresholdSensor.getName();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index f207b9e..0a1e45c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -175,6 +175,7 @@
public void testDestroy() {
mDozeSensors.destroy();
+ verify(mProximitySensor).destroy();
verify(mTriggerSensor).setListening(false);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 7fc354f..ae387e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -299,6 +299,12 @@
verify(mAuthController).onAodInterrupt(eq(screenX), eq(screenY), eq(major), eq(minor));
}
+ @Test
+ public void testDestroy() {
+ mTriggers.destroy();
+ verify(mProximityCheck).destroy();
+ }
+
private void waitForSensorManager() {
mExecutor.runAllReady();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
index 627da3c..515a1ac8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStateControllerTest.java
@@ -123,7 +123,7 @@
}
@Test
- public void testComplicationFiltering() {
+ public void testComplicationFilteringWhenShouldShowComplications() {
final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor);
@@ -160,4 +160,50 @@
}
}
+
+ @Test
+ public void testComplicationFilteringWhenShouldHideComplications() {
+ final DreamOverlayStateController stateController =
+ new DreamOverlayStateController(mExecutor);
+ stateController.setShouldShowComplications(true);
+
+ final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
+ final Complication weatherComplication = Mockito.mock(Complication.class);
+ when(alwaysAvailableComplication.getRequiredTypeAvailability())
+ .thenReturn(Complication.COMPLICATION_TYPE_NONE);
+ when(weatherComplication.getRequiredTypeAvailability())
+ .thenReturn(Complication.COMPLICATION_TYPE_WEATHER);
+
+ stateController.addComplication(alwaysAvailableComplication);
+ stateController.addComplication(weatherComplication);
+
+ final DreamOverlayStateController.Callback callback =
+ Mockito.mock(DreamOverlayStateController.Callback.class);
+
+ stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_WEATHER);
+ stateController.addCallback(callback);
+ mExecutor.runAllReady();
+
+ {
+ clearInvocations(callback);
+ stateController.setShouldShowComplications(true);
+ mExecutor.runAllReady();
+
+ verify(callback).onAvailableComplicationTypesChanged();
+ final Collection<Complication> complications = stateController.getComplications();
+ assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
+ assertThat(complications.contains(weatherComplication)).isTrue();
+ }
+
+ {
+ clearInvocations(callback);
+ stateController.setShouldShowComplications(false);
+ mExecutor.runAllReady();
+
+ verify(callback).onAvailableComplicationTypesChanged();
+ final Collection<Complication> complications = stateController.getComplications();
+ assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
+ assertThat(complications.contains(weatherComplication)).isFalse();
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
index 5a06048..6df56e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.java
@@ -19,6 +19,7 @@
import android.app.WallpaperColors;
import android.graphics.Color;
import android.testing.AndroidTestingRunner;
+import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -29,7 +30,11 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -108,7 +113,7 @@
Style.SPRITZ /* style */);
int primaryMid = colorScheme.getAccent1().get(colorScheme.getAccent1().size() / 2);
Cam cam = Cam.fromInt(primaryMid);
- Assert.assertEquals(cam.getChroma(), 4.0, 1.0);
+ Assert.assertEquals(cam.getChroma(), 12.0, 1.0);
}
@Test
@@ -128,6 +133,41 @@
Style.EXPRESSIVE /* style */);
int neutralMid = colorScheme.getNeutral1().get(colorScheme.getNeutral1().size() / 2);
Cam cam = Cam.fromInt(neutralMid);
- Assert.assertEquals(cam.getChroma(), 16.0, 1.0);
+ Assert.assertEquals(cam.getChroma(), 12.0, 1.0);
+ }
+
+ /**
+ * Generate xml for SystemPaletteTest#testThemeStyles().
+ */
+ @Test
+ public void generateThemeStyles() {
+ StringBuilder xml = new StringBuilder();
+ for (int hue = 0; hue < 360; hue += 60) {
+ final int sourceColor = Cam.getInt(hue, 50f, 50f);
+ final String sourceColorHex = Integer.toHexString(sourceColor);
+
+ xml.append(" <theme color=\"").append(sourceColorHex).append("\">\n");
+
+ for (Style style : Style.values()) {
+ String styleName = style.name().toLowerCase();
+ ColorScheme colorScheme = new ColorScheme(sourceColor, false, style);
+ xml.append(" <").append(styleName).append(">");
+
+ List<String> colors = new ArrayList<>();
+ for (Stream<Integer> stream: Arrays.asList(colorScheme.getAccent1().stream(),
+ colorScheme.getAccent2().stream(),
+ colorScheme.getAccent3().stream(),
+ colorScheme.getNeutral1().stream(),
+ colorScheme.getNeutral2().stream())) {
+ colors.add("ffffff");
+ colors.addAll(stream.map(Integer::toHexString).map(s -> s.substring(2)).collect(
+ Collectors.toList()));
+ }
+ xml.append(String.join(",", colors));
+ xml.append("</").append(styleName).append(">\n");
+ }
+ xml.append(" </theme>\n");
+ }
+ Log.d("ColorSchemeXml", xml.toString());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index d13451d..03c22b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -155,4 +155,19 @@
mIconView.getIcon(largeIcon);
// no crash? good
}
-}
\ No newline at end of file
+
+ @Test
+ public void testNullIcon() {
+ Icon mockIcon = mock(Icon.class);
+ when(mockIcon.loadDrawableAsUser(any(), anyInt())).thenReturn(null);
+ mStatusBarIcon.icon = mockIcon;
+ mIconView.set(mStatusBarIcon);
+
+ Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888);
+ Icon icon = Icon.createWithBitmap(bitmap);
+ StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+ icon, 0, 0, "");
+ mIconView.getIcon(largeIcon);
+ // No crash? good
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
index ecc2a1b..b4cae38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/charging/WiredChargingRippleControllerTest.kt
@@ -63,6 +63,7 @@
commandRegistry, batteryController, configurationController,
featureFlags, context, windowManager, systemClock, uiEventLogger)
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
+ controller.registerCallbacks()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
index 3820b98..3b908b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
@@ -20,10 +20,14 @@
import android.view.Choreographer
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.withArgCaptor
+import dagger.BindsInstance
+import dagger.Component
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@@ -41,8 +45,10 @@
whenever(it.executeDelayed(any(), anyLong())).thenReturn(timeoueSubscription)
}
- val pipelineChoreographer: NotifPipelineChoreographer = NotifPipelineChoreographerModule
- .provideChoreographer(viewChoreographer, executor)
+ val pipelineChoreographer: NotifPipelineChoreographer =
+ DaggerNotifPipelineChoreographerTestComponent.factory()
+ .create(viewChoreographer, executor)
+ .choreographer
@Test
fun scheduleThenEvalFrameCallback() {
@@ -97,4 +103,19 @@
verify(viewChoreographer).removeFrameCallback(frameCallback)
verify(timeoueSubscription).run()
}
+}
+
+@SysUISingleton
+@Component(modules = [NotifPipelineChoreographerModule::class])
+interface NotifPipelineChoreographerTestComponent {
+
+ val choreographer: NotifPipelineChoreographer
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance viewChoreographer: Choreographer,
+ @BindsInstance @Main executor: DelayableExecutor
+ ): NotifPipelineChoreographerTestComponent
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
index 3f84c16..a2d8e3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
@@ -28,13 +28,16 @@
import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Invalidator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.mockito.withArgCaptor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import dagger.BindsInstance
+import dagger.Component
import org.junit.Test
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@@ -50,9 +53,16 @@
val statusBarStateController: StatusBarStateController = mock()
val keyguardStateController: KeyguardStateController = mock()
- val coordinator: SensitiveContentCoordinator = SensitiveContentCoordinatorModule
- .provideCoordinator(dynamicPrivacyController, lockscreenUserManager,
- keyguardUpdateMonitor, statusBarStateController, keyguardStateController)
+ val coordinator: SensitiveContentCoordinator =
+ DaggerTestSensitiveContentCoordinatorComponent
+ .factory()
+ .create(
+ dynamicPrivacyController,
+ lockscreenUserManager,
+ keyguardUpdateMonitor,
+ statusBarStateController,
+ keyguardStateController)
+ .coordinator
@Test
fun onDynamicPrivacyChanged_invokeInvalidationListener() {
@@ -238,4 +248,21 @@
override fun getRepresentativeEntry(): NotificationEntry = mockEntry
}
}
+}
+
+@CoordinatorScope
+@Component(modules = [SensitiveContentCoordinatorModule::class])
+interface TestSensitiveContentCoordinatorComponent {
+ val coordinator: SensitiveContentCoordinator
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance dynamicPrivacyController: DynamicPrivacyController,
+ @BindsInstance lockscreenUserManager: NotificationLockscreenUserManager,
+ @BindsInstance keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ @BindsInstance statusBarStateController: StatusBarStateController,
+ @BindsInstance keyguardStateController: KeyguardStateController
+ ): TestSensitiveContentCoordinatorComponent
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
index 12e71af..34a5d4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollectorFake
import com.android.systemui.dock.DockManager
+import com.android.systemui.lowlightclock.LowLightClockController
import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.NotificationShadeDepthController
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -38,11 +39,13 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import java.util.Optional
import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidTestingRunner::class)
@@ -79,6 +82,8 @@
private lateinit var mLockIconViewController: LockIconViewController
@Mock
private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController
+ @Mock
+ private lateinit var mLowLightClockController: LowLightClockController
private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
private lateinit var mInteractionEventHandler: InteractionEventHandler
@@ -101,7 +106,8 @@
stackScrollLayoutController,
mStatusBarKeyguardViewManager,
mStatusBarWindowStateController,
- mLockIconViewController
+ mLockIconViewController,
+ Optional.of(mLowLightClockController)
)
mController.setupExpandedStatusBar()
mController.setService(mStatusBar, mNotificationShadeWindowController)
@@ -235,6 +241,31 @@
verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
assertThat(returnVal).isTrue()
}
+
+ @Test
+ fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
+ verify(mLowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+ }
+
+ @Test
+ fun testLowLightClockShownWhenDozing() {
+ mController.setDozing(true)
+ verify(mLowLightClockController).showLowLightClock(true)
+ }
+
+ @Test
+ fun testLowLightClockDozeTimeTickCalled() {
+ mController.dozeTimeTick()
+ verify(mLowLightClockController).dozeTimeTick()
+ }
+
+ @Test
+ fun testLowLightClockHiddenWhenNotDozing() {
+ mController.setDozing(true)
+ verify(mLowLightClockController).showLowLightClock(true)
+ mController.setDozing(false)
+ verify(mLowLightClockController).showLowLightClock(false)
+ }
}
private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index d885da8..6c33113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,6 +37,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -56,6 +57,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
@@ -79,6 +82,7 @@
@Mock private StatusBarWindowStateController mStatusBarWindowStateController;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Mock private LockIconViewController mLockIconViewController;
+ @Mock private LowLightClockController mLowLightClockController;
@Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
mInteractionEventHandlerCaptor;
@@ -110,7 +114,8 @@
mNotificationStackScrollLayoutController,
mStatusBarKeyguardViewManager,
mStatusBarWindowStateController,
- mLockIconViewController);
+ mLockIconViewController,
+ Optional.of(mLowLightClockController));
mController.setupExpandedStatusBar();
mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index a7809c2..c7db9e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -116,6 +116,7 @@
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.charging.WiredChargingRippleController;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -288,6 +289,7 @@
@Mock private InteractionJankMonitor mJankMonitor;
@Mock private DeviceStateManager mDeviceStateManager;
@Mock private DreamOverlayStateController mDreamOverlayStateController;
+ @Mock private WiredChargingRippleController mWiredChargingRippleController;
private ShadeController mShadeController;
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -479,7 +481,8 @@
mNotifPipelineFlags,
mJankMonitor,
mDeviceStateManager,
- mDreamOverlayStateController);
+ mDreamOverlayStateController,
+ mWiredChargingRippleController);
when(mKeyguardViewMediator.registerStatusBar(
any(StatusBar.class),
any(NotificationPanelViewController.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index f5554c5..9f9cb40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -205,6 +205,12 @@
mTestableLooper.processAllMessages();
verify(callback, times(1)).onLocationActiveChanged(false);
+
+ when(mAppOpsController.getActiveAppOps()).thenReturn(ImmutableList.of());
+ mLocationController.onActiveStateChanged(AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION, 0,
+ "com.google.android.googlequicksearchbox", true);
+ mTestableLooper.processAllMessages();
+ verify(callback, times(1)).onLocationActiveChanged(true);
}
@Test
diff --git a/services/Android.bp b/services/Android.bp
index e0ca8a6..2e4405f 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -54,7 +54,9 @@
SYSTEM_OPTIMIZE_JAVA: {
optimize: {
enabled: true,
- optimize: true,
+ // TODO(b/210510433): Enable optimizations after improving
+ // retracing infra.
+ optimize: false,
shrink: true,
proguard_flags_files: ["proguard.flags"],
},
diff --git a/services/autofill/OWNERS b/services/autofill/OWNERS
index c52751d..edfb211 100644
--- a/services/autofill/OWNERS
+++ b/services/autofill/OWNERS
@@ -1 +1 @@
-include /core/java/android/service/autofill/OWNERS
+include /core/java/android/view/autofill/OWNERS
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 76ee728..e0fa67f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -103,7 +103,6 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.KeyEvent;
-import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -367,8 +366,6 @@
@Nullable
private ClientSuggestionsSession mClientSuggestionsSession;
- private final AccessibilityManager mAccessibilityManager;
-
// TODO(b/216576510): Share one BroadcastReceiver between all Sessions instead of creating a
// new one per Session.
private final BroadcastReceiver mDelayedFillBroadcastReceiver =
@@ -518,10 +515,7 @@
return;
}
- // If a11y touch exploration is enabled, then we do not send an inline fill request
- // to the regular af service, because dropdown UI is easier to use.
- if (mPendingInlineSuggestionsRequest.isServiceSupported()
- && !mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (mPendingInlineSuggestionsRequest.isServiceSupported()) {
mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
mPendingFillRequest.getFillContexts(),
mPendingFillRequest.getClientState(),
@@ -1064,7 +1058,6 @@
mRemoteFillService = serviceComponentName == null ? null
: new RemoteFillService(context, serviceComponentName, userId, this,
bindInstantServiceAllowed);
- mAccessibilityManager = AccessibilityManager.getInstance(context);
mActivityToken = activityToken;
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index efa026b..e10151d 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -137,6 +137,8 @@
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
+import dalvik.annotation.optimization.NeverCompile;
+
import com.google.android.collect.Sets;
import java.io.BufferedInputStream;
@@ -4072,6 +4074,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
private void dumpInternal(PrintWriter pw) {
// Add prefix for only non-system users so that system user dumpsys is the same as before
String userPrefix = mUserId == UserHandle.USER_SYSTEM ? "" : "User " + mUserId + ":";
diff --git a/services/companion/java/com/android/server/companion/CompanionApplicationController.java b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
index be1bc79..c39b59a 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.os.Handler;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -120,6 +121,12 @@
mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
}
+ if (serviceConnectors.isEmpty()) {
+ Slog.e(TAG, "Can't find CompanionDeviceService implementer in package: "
+ + packageName + ". Please check if they are correctly declared.");
+ return;
+ }
+
// The first connector in the list is always the primary connector: set a listener to it.
serviceConnectors.get(0).setListener(this::onPrimaryServiceBindingDied);
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index a771e7b..b026990 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -21,6 +21,8 @@
import static android.bluetooth.BluetoothAdapter.ACTION_STATE_CHANGED;
import static android.bluetooth.BluetoothAdapter.EXTRA_PREVIOUS_STATE;
import static android.bluetooth.BluetoothAdapter.EXTRA_STATE;
+import static android.bluetooth.BluetoothAdapter.STATE_BLE_ON;
+import static android.bluetooth.BluetoothAdapter.STATE_ON;
import static android.bluetooth.BluetoothAdapter.nameForState;
import static android.bluetooth.le.ScanCallback.SCAN_FAILED_ALREADY_STARTED;
import static android.bluetooth.le.ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED;
@@ -232,8 +234,14 @@
return;
}
- mBleScanner.stopScan(mScanCallback);
mScanning = false;
+
+ if (mBtAdapter.getState() != STATE_ON && mBtAdapter.getState() != STATE_BLE_ON) {
+ Log.d(TAG, "BT Adapter is not turned ON");
+ return;
+ }
+
+ mBleScanner.stopScan(mScanCallback);
}
@MainThread
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 52a0aa7..d218af3 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -45,7 +45,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
@@ -369,13 +368,10 @@
// we are only interested in doing things at PHASE_BOOT_COMPLETED
if (phase == PHASE_BOOT_COMPLETED) {
+ // due to potentially long computation that holds up boot time, apex sha computations
+ // are deferred to first call
Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
getVBMetaDigestInformation();
-
- // due to potentially long computation that may hold up boot time, SHA256 computations
- // for APEXs and Modules will be executed via threads.
- Slog.i(TAG, "Executing APEX & Module digest computations");
- computeApexAndModuleDigests();
}
}
@@ -385,12 +381,6 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
}
- private void computeApexAndModuleDigests() {
- // using Executors will allow the computations to be done asynchronously, thus not holding
- // up boot time.
- Executors.defaultThreadFactory().newThread(() -> updateBinaryMeasurements()).start();
- }
-
@NonNull
private List<PackageInfo> getInstalledApexs() {
List<PackageInfo> results = new ArrayList<PackageInfo>();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8aab8f5..efbc4de 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -103,6 +103,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.am.BatteryStatsService;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -2879,6 +2881,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index c236a7f..569d480 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -43,6 +43,7 @@
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.UiModeManager;
+import android.app.UiModeManager.NightModeCustomReturnType;
import android.app.UiModeManager.NightModeCustomType;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -111,6 +112,9 @@
// Enable launching of applications when entering the dock.
private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
private static final String SYSTEM_PROPERTY_DEVICE_THEME = "persist.sys.theme";
+ @VisibleForTesting
+ public static final Set<Integer> SUPPORTED_NIGHT_MODE_CUSTOM_TYPES = new ArraySet(
+ new Integer[]{MODE_NIGHT_CUSTOM_TYPE_SCHEDULE, MODE_NIGHT_CUSTOM_TYPE_BEDTIME});
private final Injector mInjector;
private final Object mLock = new Object();
@@ -631,6 +635,8 @@
+ "permission ENTER_CAR_MODE_PRIORITIZED");
}
+ assertLegit(callingPackage);
+
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -671,6 +677,9 @@
// mode flag to be specified; this is so that the user can disable car mode at all
// priorities using the persistent notification.
boolean isSystemCaller = mInjector.getCallingUid() == Process.SYSTEM_UID;
+ if (!isSystemCaller) {
+ assertLegit(callingPackage);
+ }
final int carModeFlags =
isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
@@ -728,8 +737,13 @@
case UiModeManager.MODE_NIGHT_NO:
case UiModeManager.MODE_NIGHT_YES:
case MODE_NIGHT_AUTO:
- case MODE_NIGHT_CUSTOM:
break;
+ case MODE_NIGHT_CUSTOM:
+ if (SUPPORTED_NIGHT_MODE_CUSTOM_TYPES.contains(customModeType)) {
+ break;
+ }
+ throw new IllegalArgumentException(
+ "Can't set the custom type to " + customModeType);
default:
throw new IllegalArgumentException("Unknown mode: " + mode);
}
@@ -783,7 +797,7 @@
}
@Override
- public int getNightModeCustomType() {
+ public @NightModeCustomReturnType int getNightModeCustomType() {
if (getContext().checkCallingOrSelfPermission(
android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index e2e53cb..5fe8719 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -46,6 +46,8 @@
import com.android.internal.annotations.GuardedBy;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
@@ -1430,6 +1432,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
void dump(PrintWriter pw) {
pw.println("ACTIVITY MANAGER SETTINGS (dumpsys activity settings) "
+ Settings.Global.ACTIVITY_MANAGER_CONSTANTS + ":");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e56098c..6c39a11 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -188,6 +188,7 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.PendingIntentStats;
import android.app.ProcessMemoryState;
import android.app.ProfilerInfo;
import android.app.SyncNotedAppOp;
@@ -414,6 +415,7 @@
import com.android.server.wm.WindowManagerService;
import com.android.server.wm.WindowProcessController;
+import dalvik.annotation.optimization.NeverCompile;
import dalvik.system.VMRuntime;
import libcore.util.EmptyArray;
@@ -5614,15 +5616,29 @@
synchronized (mProcLock) {
synchronized (mPidsSelfLocked) {
+ int newestTimeIndex = -1;
+ long newestTime = Long.MIN_VALUE;
for (int i = 0; i < pids.length; i++) {
ProcessRecord pr = mPidsSelfLocked.get(pids[i]);
if (pr != null) {
- final boolean isPendingTop =
- mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]);
- states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.mState.getCurProcState();
- if (scores != null) {
- scores[i] = isPendingTop
- ? (ProcessList.FOREGROUND_APP_ADJ - 1) : pr.mState.getCurAdj();
+ final long pendingTopTime =
+ mPendingStartActivityUids.getPendingTopPidTime(pr.uid, pids[i]);
+ if (pendingTopTime != PendingStartActivityUids.INVALID_TIME) {
+ // The uid in mPendingStartActivityUids gets the TOP process state.
+ states[i] = PROCESS_STATE_TOP;
+ if (scores != null) {
+ // The uid in mPendingStartActivityUids gets a better score.
+ scores[i] = ProcessList.FOREGROUND_APP_ADJ - 1;
+ }
+ if (pendingTopTime > newestTime) {
+ newestTimeIndex = i;
+ newestTime = pendingTopTime;
+ }
+ } else {
+ states[i] = pr.mState.getCurProcState();
+ if (scores != null) {
+ scores[i] = pr.mState.getCurAdj();
+ }
}
} else {
states[i] = PROCESS_STATE_NONEXISTENT;
@@ -5631,6 +5647,13 @@
}
}
}
+ // The uid with the newest timestamp in mPendingStartActivityUids gets the best
+ // score.
+ if (newestTimeIndex != -1) {
+ if (scores != null) {
+ scores[newestTimeIndex] = ProcessList.FOREGROUND_APP_ADJ - 2;
+ }
+ }
}
}
}
@@ -6658,6 +6681,7 @@
reportCurWakefulnessUsageEvent();
mActivityTaskManager.onScreenAwakeChanged(isAwake);
mOomAdjProfiler.onWakefulnessChanged(wakefulness);
+ mOomAdjuster.onWakefulnessChanged(wakefulness);
}
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
}
@@ -9153,6 +9177,7 @@
/**
* Wrapper function to print out debug data filtered by specified arguments.
*/
+ @NeverCompile // Avoid size overhead of debugging code.
private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -9687,6 +9712,7 @@
return needSep;
}
+ @NeverCompile // Avoid size overhead of debugging code.
@GuardedBy({"this", "mProcLock"})
void dumpOtherProcessesInfoLSP(FileDescriptor fd, PrintWriter pw,
boolean dumpAll, String dumpPackage, int dumpAppId, int numPers, boolean needSep) {
@@ -10808,6 +10834,7 @@
boolean dumpProto;
}
+ @NeverCompile // Avoid size overhead of debugging code.
final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
String[] args, boolean brief, PrintWriter categoryPw, boolean asProto) {
MemoryUsageDumpOptions opts = new MemoryUsageDumpOptions();
@@ -10890,6 +10917,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
private final void dumpApplicationMemoryUsage(FileDescriptor fd, PrintWriter pw, String prefix,
MemoryUsageDumpOptions opts, final String[] innerArgs, boolean brief,
ArrayList<ProcessRecord> procs, PrintWriter categoryPw) {
@@ -11539,6 +11567,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
private final void dumpApplicationMemoryUsage(FileDescriptor fd,
MemoryUsageDumpOptions opts, final String[] innerArgs, boolean brief,
ArrayList<ProcessRecord> procs) {
@@ -15952,6 +15981,11 @@
implements ActivityManagerLocal {
@Override
+ public List<PendingIntentStats> getPendingIntentStats() {
+ return mPendingIntentController.dumpPendingIntentStatsForStatsd();
+ }
+
+ @Override
public Pair<String, String> getAppProfileStatsForDebugging(long time, int lines) {
return mAppProfiler.getAppProfileStatsForDebugging(time, lines);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 08508b2..bcde343 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -107,6 +107,8 @@
import com.android.server.compat.PlatformCompat;
import com.android.server.utils.Slogf;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@@ -3309,6 +3311,7 @@
dumpHelp(pw, mDumping);
}
+ @NeverCompile // Avoid size overhead of debugging code.
static void dumpHelp(PrintWriter pw, boolean dumping) {
if (dumping) {
pw.println("Activity manager dump options:");
diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index 34d9a60..1e1024e 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -60,6 +60,10 @@
*/
private long mLastAnrTimeMs = 0L;
+ /** The pid which is running appNotResponding(). */
+ @GuardedBy("mAnrRecords")
+ private int mProcessingPid = -1;
+
AnrHelper(final ActivityManagerService service) {
mService = service;
}
@@ -73,7 +77,18 @@
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
+ final int incomingPid = anrProcess.mPid;
synchronized (mAnrRecords) {
+ if (mProcessingPid == incomingPid) {
+ Slog.i(TAG, "Skip duplicated ANR, pid=" + incomingPid + " " + annotation);
+ return;
+ }
+ for (int i = mAnrRecords.size() - 1; i >= 0; i--) {
+ if (mAnrRecords.get(i).mPid == incomingPid) {
+ Slog.i(TAG, "Skip queued ANR, pid=" + incomingPid + " " + annotation);
+ return;
+ }
+ }
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
}
@@ -87,8 +102,8 @@
}
/**
- * The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
- * records are handled.
+ * The thread to execute {@link ProcessErrorStateRecord#appNotResponding}. It will terminate if
+ * all records are handled.
*/
private class AnrConsumerThread extends Thread {
AnrConsumerThread() {
@@ -97,7 +112,12 @@
private AnrRecord next() {
synchronized (mAnrRecords) {
- return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
+ if (mAnrRecords.isEmpty()) {
+ return null;
+ }
+ final AnrRecord record = mAnrRecords.remove(0);
+ mProcessingPid = record.mPid;
+ return record;
}
}
@@ -106,6 +126,13 @@
AnrRecord r;
while ((r = next()) != null) {
scheduleBinderHeavyHitterAutoSamplerIfNecessary();
+ final int currentPid = r.mApp.mPid;
+ if (currentPid != r.mPid) {
+ // The process may have restarted or died.
+ Slog.i(TAG, "Skip ANR with mismatched pid=" + r.mPid + ", current pid="
+ + currentPid);
+ continue;
+ }
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
@@ -120,6 +147,7 @@
mRunning.set(false);
synchronized (mAnrRecords) {
+ mProcessingPid = -1;
// The race should be unlikely to happen. Just to make sure we don't miss.
if (!mAnrRecords.isEmpty()) {
startAnrConsumerIfNeeded();
@@ -139,6 +167,7 @@
private static class AnrRecord {
final ProcessRecord mApp;
+ final int mPid;
final String mActivityShortComponentName;
final String mParentShortComponentName;
final String mAnnotation;
@@ -151,6 +180,7 @@
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
mApp = anrProcess;
+ mPid = anrProcess.mPid;
mActivityShortComponentName = activityShortComponentName;
mParentShortComponentName = parentShortComponentName;
mAnnotation = annotation;
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 6c1a00d..97dd323 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -1018,6 +1018,7 @@
Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
0,
mService.mUserController.getCurrentUserId()) != 0;
+ final String packageName = proc.info.packageName;
final boolean crashSilenced = mAppsNotReportingCrashes != null
&& mAppsNotReportingCrashes.contains(proc.info.packageName);
final long now = SystemClock.uptimeMillis();
@@ -1026,6 +1027,7 @@
if ((mService.mAtmInternal.canShowErrorDialogs() || showBackground)
&& !crashSilenced && !shouldThottle
&& (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
+ Slog.i(TAG, "Showing crash dialog for package " + packageName + " u" + userId);
errState.getDialogController().showCrashDialogs(data);
if (!proc.isolated) {
mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 5ac5a70..075402f 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -560,20 +560,22 @@
int changes = serviceTypes ^ mForegroundServiceTypes;
for (int serviceType = Integer.highestOneBit(changes); serviceType != 0;) {
final int i = foregroundServiceTypeToIndex(serviceType);
- if ((serviceTypes & serviceType) != 0) {
- // Start this type.
- if (mEvents[i] == null) {
- mEvents[i] = new LinkedList<>();
- }
- if (!isActive(i)) {
- mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
- }
- } else {
- // Stop this type.
- if (mEvents[i] != null && isActive(i)) {
- mEvents[i].add(new BaseTimeEvent(now));
- notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+ if (i < mEvents.length) {
+ if ((serviceTypes & serviceType) != 0) {
+ // Start this type.
+ if (mEvents[i] == null) {
+ mEvents[i] = new LinkedList<>();
+ }
+ if (!isActive(i)) {
+ mEvents[i].add(new BaseTimeEvent(now));
+ notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
+ }
+ } else {
+ // Stop this type.
+ if (mEvents[i] != null && isActive(i)) {
+ mEvents[i].add(new BaseTimeEvent(now));
+ notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+ }
}
}
changes &= ~serviceType;
diff --git a/services/core/java/com/android/server/am/AppPermissionTracker.java b/services/core/java/com/android/server/am/AppPermissionTracker.java
index 7f48d52..69f70ca 100644
--- a/services/core/java/com/android/server/am/AppPermissionTracker.java
+++ b/services/core/java/com/android/server/am/AppPermissionTracker.java
@@ -64,6 +64,8 @@
@GuardedBy("mLock")
private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
+ private volatile boolean mLockedBootCompleted = false;
+
AppPermissionTracker(Context context, AppRestrictionController controller) {
this(context, controller, null, null);
}
@@ -85,20 +87,20 @@
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
+ final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
for (int userId : allUsers) {
final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
if (apps == null) {
continue;
}
- synchronized (mLock) {
- final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
- final long now = SystemClock.elapsedRealtime();
- for (int i = 0, size = apps.size(); i < size; i++) {
- final ApplicationInfo ai = apps.get(i);
- for (String permission : permissions) {
- if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
- continue;
- }
+ final long now = SystemClock.elapsedRealtime();
+ for (int i = 0, size = apps.size(); i < size; i++) {
+ final ApplicationInfo ai = apps.get(i);
+ for (String permission : permissions) {
+ if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
+ continue;
+ }
+ synchronized (mLock) {
ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
if (grantedPermissions == null) {
grantedPermissions = new ArraySet<String>();
@@ -132,25 +134,30 @@
private void handlePermissionsChanged(int uid) {
final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
if (permissions != null && permissions.length > 0) {
+ final PermissionManagerServiceInternal pm =
+ mInjector.getPermissionManagerServiceInternal();
+ final boolean[] states = new boolean[permissions.length];
+ for (int i = 0; i < permissions.length; i++) {
+ states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
+ if (DEBUG_PERMISSION_TRACKER) {
+ Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
+ }
+ }
synchronized (mLock) {
- handlePermissionsChangedLocked(uid);
+ handlePermissionsChangedLocked(uid, permissions, states);
}
}
}
@GuardedBy("mLock")
- private void handlePermissionsChangedLocked(int uid) {
- final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
+ private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
ArraySet<String> grantedPermissions = index >= 0
? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
- final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
final long now = SystemClock.elapsedRealtime();
- for (String permission: permissions) {
- boolean granted = pm.checkUidPermission(uid, permission) == PERMISSION_GRANTED;
- if (DEBUG_PERMISSION_TRACKER) {
- Slog.i(TAG, UserHandle.formatUid(uid) + " " + permission + "=" + granted);
- }
+ for (int i = 0; i < permissions.length; i++) {
+ final String permission = permissions[i];
+ final boolean granted = states[i];
boolean changed = false;
if (granted) {
if (grantedPermissions == null) {
@@ -200,6 +207,10 @@
}
private void onPermissionTrackerEnabled(boolean enabled) {
+ if (!mLockedBootCompleted) {
+ // Not ready, bail out.
+ return;
+ }
final PermissionManager pm = mInjector.getPermissionManager();
if (enabled) {
pm.addOnPermissionsChangeListener(this);
@@ -211,6 +222,12 @@
}
@Override
+ void onLockedBootCompleted() {
+ mLockedBootCompleted = true;
+ onPermissionTrackerEnabled(mInjector.getPolicy().isEnabled());
+ }
+
+ @Override
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
pw.println("APP PERMISSIONS TRACKER:");
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 1129c19..2ffd487 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -71,6 +71,7 @@
import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
import static android.os.PowerExemptionManager.reasonCodeToString;
import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.internal.notification.SystemNotificationChannels.ABUSIVE_BACKGROUND_APPS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -792,7 +793,7 @@
mInjector = injector;
mContext = injector.getContext();
mActivityManagerService = service;
- mBgHandlerThread = new HandlerThread("bgres-controller");
+ mBgHandlerThread = new HandlerThread("bgres-controller", THREAD_PRIORITY_BACKGROUND);
mBgHandlerThread.start();
mBgHandler = new BgHandler(mBgHandlerThread.getLooper(), injector);
mBgExecutor = new HandlerExecutor(mBgHandler);
@@ -816,9 +817,11 @@
mInjector.getAppStandbyInternal().addListener(mAppIdleStateChangeListener);
mInjector.getRoleManager().addOnRoleHoldersChangedListenerAsUser(mBgExecutor,
mRoleHolderChangedListener, UserHandle.ALL);
- for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
- mAppStateTrackers.get(i).onSystemReady();
- }
+ mInjector.scheduleInitTrackers(mBgHandler, () -> {
+ for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+ mAppStateTrackers.get(i).onSystemReady();
+ }
+ });
}
@VisibleForTesting
@@ -2137,6 +2140,10 @@
}
return null;
}
+
+ void scheduleInitTrackers(Handler handler, Runnable initializers) {
+ handler.post(initializers);
+ }
}
private void registerForSystemBroadcasts() {
@@ -2221,6 +2228,21 @@
userFilter.addAction(Intent.ACTION_USER_REMOVED);
userFilter.addAction(Intent.ACTION_UID_REMOVED);
mContext.registerReceiverForAllUsers(broadcastReceiver, userFilter, null, mBgHandler);
+ final BroadcastReceiver bootReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ switch (intent.getAction()) {
+ case Intent.ACTION_LOCKED_BOOT_COMPLETED: {
+ onLockedBootCompleted();
+ } break;
+ }
+ }
+ };
+ final IntentFilter bootFilter = new IntentFilter();
+ bootFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
+ mContext.registerReceiverAsUser(bootReceiver, UserHandle.SYSTEM,
+ bootFilter, null, mBgHandler);
}
void forEachTracker(Consumer<BaseAppStateTracker> sink) {
@@ -2275,6 +2297,12 @@
mRestrictionSettings.removeUid(uid);
}
+ private void onLockedBootCompleted() {
+ for (int i = 0, size = mAppStateTrackers.size(); i < size; i++) {
+ mAppStateTrackers.get(i).onLockedBootCompleted();
+ }
+ }
+
boolean isBgAutoRestrictedBucketFeatureFlagEnabled() {
return mConstantsObserver.mBgAutoRestrictedBucket;
}
diff --git a/services/core/java/com/android/server/am/BaseAppStateTracker.java b/services/core/java/com/android/server/am/BaseAppStateTracker.java
index 482d697..0fada53 100644
--- a/services/core/java/com/android/server/am/BaseAppStateTracker.java
+++ b/services/core/java/com/android/server/am/BaseAppStateTracker.java
@@ -204,6 +204,12 @@
}
/**
+ * Called when the system sends LOCKED_BOOT_COMPLETED.
+ */
+ void onLockedBootCompleted() {
+ }
+
+ /**
* Called when a device config property in the activity manager namespace
* has changed.
*/
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 7af73eb..86ca699 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -28,6 +28,7 @@
import android.os.Debug;
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
@@ -1051,6 +1052,15 @@
}
}
+ void onWakefulnessChanged(int wakefulness) {
+ if(wakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ // Remove any pending compaction we may have scheduled to happen while screen was off
+ Slog.e(TAG_AM, "Cancel pending or running compactions as system is awake");
+ mPendingCompactionProcesses.clear();
+ cancelCompaction();
+ }
+ }
+
@GuardedBy({"mService", "mProcLock"})
void onOomAdjustChanged(int oldAdj, int newAdj, ProcessRecord app) {
// Cancel any currently executing compactions
@@ -1105,6 +1115,9 @@
int lastOomAdj = msg.arg1;
int procState = msg.arg2;
synchronized (mProcLock) {
+ if(mPendingCompactionProcesses.isEmpty()) {
+ return;
+ }
proc = mPendingCompactionProcesses.remove(0);
opt = proc.mOptRecord;
diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
index f0910dc..4c96078 100644
--- a/services/core/java/com/android/server/am/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -73,7 +73,8 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
- mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
+ mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler,
+ Context.RECEIVER_NOT_EXPORTED);
}
@Override
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 6c9187a..8d77eda 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -2470,6 +2470,10 @@
}
}
+ void onWakefulnessChanged(int wakefulness) {
+ mCachedAppOptimizer.onWakefulnessChanged(wakefulness);
+ }
+
/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
@GuardedBy({"mService", "mProcLock"})
private boolean applyOomAdjLSP(ProcessRecord app, boolean doingAll, long now,
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index c49e696..7ee96aa 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -28,6 +28,7 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.PendingIntent;
+import android.app.PendingIntentStats;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
@@ -60,6 +61,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
/**
* Helper class for {@link ActivityManagerService} responsible for managing pending intents.
@@ -422,6 +424,55 @@
}
/**
+ * Provides some stats tracking of the current state of the PendingIntent queue.
+ *
+ * Data about the pending intent queue is intended to be used for memory impact tracking.
+ * Returned data (one per uid) will consist of instances of PendingIntentStats containing
+ * (I) number of PendingIntents and (II) total size of all bundled extras in the PIs.
+ *
+ * @hide
+ */
+ public List<PendingIntentStats> dumpPendingIntentStatsForStatsd() {
+ List<PendingIntentStats> pendingIntentStats = new ArrayList<>();
+
+ synchronized (mLock) {
+ if (mIntentSenderRecords.size() > 0) {
+ // First, aggregate PendingIntent data by package uid.
+ final SparseIntArray countsByUid = new SparseIntArray();
+ final SparseIntArray bundleSizesByUid = new SparseIntArray();
+
+ for (WeakReference<PendingIntentRecord> reference : mIntentSenderRecords.values()) {
+ if (reference == null || reference.get() == null) {
+ continue;
+ }
+ PendingIntentRecord record = reference.get();
+ int index = countsByUid.indexOfKey(record.uid);
+
+ if (index < 0) { // ie. the key was not found
+ countsByUid.put(record.uid, 1);
+ bundleSizesByUid.put(record.uid,
+ record.key.requestIntent.getExtrasTotalSize());
+ } else {
+ countsByUid.put(record.uid, countsByUid.valueAt(index) + 1);
+ bundleSizesByUid.put(record.uid,
+ bundleSizesByUid.valueAt(index)
+ + record.key.requestIntent.getExtrasTotalSize());
+ }
+ }
+
+ // Now generate the output.
+ for (int i = 0, size = countsByUid.size(); i < size; i++) {
+ pendingIntentStats.add(new PendingIntentStats(
+ countsByUid.keyAt(i),
+ countsByUid.valueAt(i),
+ /* NB: int conversion here */ bundleSizesByUid.valueAt(i) / 1024));
+ }
+ }
+ }
+ return pendingIntentStats;
+ }
+
+ /**
* Increment the number of the PendingIntentRecord for the given uid, log a warning
* if there are too many for this uid already.
*/
diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java
index 6bf9d4e..802ea00 100644
--- a/services/core/java/com/android/server/am/PendingStartActivityUids.java
+++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java
@@ -35,6 +35,8 @@
final class PendingStartActivityUids {
static final String TAG = ActivityManagerService.TAG;
+ public static final long INVALID_TIME = 0;
+
// Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the
// uid is added.
private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray();
@@ -63,13 +65,20 @@
}
}
- synchronized boolean isPendingTopPid(int uid, int pid) {
+ /**
+ * Return the elapsedRealtime when the uid is added to the mPendingUids map.
+ * @param uid
+ * @param pid
+ * @return elapsedRealtime if the uid is in the mPendingUids map;
+ * INVALID_TIME if the uid is not in the mPendingUids map.
+ */
+ synchronized long getPendingTopPidTime(int uid, int pid) {
+ long ret = INVALID_TIME;
final Pair<Integer, Long> pendingPid = mPendingUids.get(uid);
- if (pendingPid != null) {
- return pendingPid.first == pid;
- } else {
- return false;
+ if (pendingPid != null && pendingPid.first == pid) {
+ ret = pendingPid.second;
}
+ return ret;
}
synchronized boolean isPendingTopUid(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c4163e6..763bbee 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1718,17 +1718,18 @@
return Zygote.MEMORY_TAG_LEVEL_NONE;
}
- // Check to see that the compat feature for TBI is enabled.
- if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
- return Zygote.MEMORY_TAG_LEVEL_TBI;
- }
-
String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
if ("sync".equals(defaultLevel)) {
return Zygote.MEMORY_TAG_LEVEL_SYNC;
} else if ("async".equals(defaultLevel)) {
return Zygote.MEMORY_TAG_LEVEL_ASYNC;
}
+
+ // Check to see that the compat feature for TBI is enabled.
+ if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
+ return Zygote.MEMORY_TAG_LEVEL_TBI;
+ }
+
return Zygote.MEMORY_TAG_LEVEL_NONE;
}
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 84d2b1f..7371d07 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -44,6 +44,8 @@
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -932,6 +934,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
private void dumpInner(PrintWriter pw, String[] args) {
final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index cebcc64f..e2d00f7 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -179,6 +179,8 @@
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import dalvik.annotation.optimization.NeverCompile;
+
import libcore.util.EmptyArray;
import org.json.JSONException;
@@ -5902,6 +5904,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3e5e435..0b9fb1a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -36,6 +36,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -87,6 +88,7 @@
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -108,6 +110,7 @@
import android.media.MediaRecorder.AudioSource;
import android.media.PlayerBase;
import android.media.Spatializer;
+import android.media.VolumeInfo;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
@@ -3327,6 +3330,13 @@
}
}
+ private void enforceAccessUltrasoundPermission() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Missing ACCESS_ULTRASOUND permission");
+ }
+ }
+
private void enforceQueryStatePermission() {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.QUERY_AUDIO_STATE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -3459,6 +3469,12 @@
attributionTag, Binder.getCallingUid(), callingOrSelfHasAudioSettingsPermission());
}
+ /** @see AudioManager#isUltrasoundSupported() */
+ public boolean isUltrasoundSupported() {
+ enforceAccessUltrasoundPermission();
+ return AudioSystem.isUltrasoundSupported();
+ }
+
private boolean canChangeAccessibilityVolume() {
synchronized (mAccessibilityServiceUidsLock) {
if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
@@ -4246,6 +4262,24 @@
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
}
+ /**
+ * Default VolumeInfo returned by {@link VolumeInfo#getDefaultVolumeInfo()}
+ * Lazily initialized in {@link #getDefaultVolumeInfo()}
+ */
+ static VolumeInfo sDefaultVolumeInfo;
+
+ /** @see VolumeInfo#getDefaultVolumeInfo() */
+ public VolumeInfo getDefaultVolumeInfo() {
+ if (sDefaultVolumeInfo == null) {
+ sDefaultVolumeInfo = new VolumeInfo.Builder(AudioSystem.STREAM_MUSIC)
+ .setMinVolumeIndex(getStreamMinVolume(AudioSystem.STREAM_MUSIC))
+ .setMaxVolumeIndex(getStreamMaxVolume(AudioSystem.STREAM_MUSIC))
+ .setMuted(false)
+ .build();
+ }
+ return sDefaultVolumeInfo;
+ }
+
/** @see AudioManager#getUiSoundsStreamType()
* TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
* UI Sounds identification.
@@ -6310,6 +6344,37 @@
}
/**
+ * @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior
+ * @param cb
+ * @param attr
+ * @param volumes
+ */
+ @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+ android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+ public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+ IAudioDeviceVolumeDispatcher cb, String packageName,
+ AudioDeviceAttributes device, List<VolumeInfo> volumes) {
+ // verify permissions
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Missing MODIFY_AUDIO_ROUTING or BLUETOOTH_PRIVILEGED permissions");
+ }
+ // verify arguments
+ Objects.requireNonNull(device);
+ Objects.requireNonNull(volumes);
+
+ // current implementation maps this call to existing abs volume API of AudioManager
+ // TODO implement the volume/device listener through IAudioDeviceVolumeDispatcher
+ final int volumeBehavior = volumes.size() == 1
+ ? AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+ : AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
+ setDeviceVolumeBehavior(device, volumeBehavior, packageName);
+ }
+
+ /**
* @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
* @param device the audio device to be affected
* @param deviceVolumeBehavior one of the device behaviors
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f4aa88f..73afa60 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -116,6 +116,8 @@
import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
import com.android.server.job.JobSchedulerInternal;
+import dalvik.annotation.optimization.NeverCompile;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -2169,6 +2171,7 @@
return true;
}
+ @NeverCompile // Avoid size overhead of debugging code.
protected void dumpSyncState(PrintWriter pw, SyncAdapterStateFetcher buckets) {
final StringBuilder sb = new StringBuilder();
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 2c2a2bf..17215e5 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -131,6 +131,7 @@
private static final int MSG_STOP_SENSOR_LISTENER = 2;
private static final int MSG_START_SENSOR_LISTENER = 3;
private static final int MSG_BRIGHTNESS_CONFIG_CHANGED = 4;
+ private static final int MSG_SENSOR_CHANGED = 5;
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
@@ -158,6 +159,7 @@
// These members should only be accessed on the mBgHandler thread.
private BroadcastReceiver mBroadcastReceiver;
private SensorListener mSensorListener;
+ private Sensor mLightSensor;
private SettingsObserver mSettingsObserver;
private DisplayListener mDisplayListener;
private boolean mSensorRegistered;
@@ -327,6 +329,14 @@
m.sendToTarget();
}
+ /**
+ * Updates the light sensor to use.
+ */
+ public void setLightSensor(Sensor lightSensor) {
+ mBgHandler.obtainMessage(MSG_SENSOR_CHANGED, 0 /*unused*/, 0/*unused*/, lightSensor)
+ .sendToTarget();
+ }
+
private void handleBrightnessChanged(float brightness, boolean userInitiated,
float powerBrightnessFactor, boolean isUserSetBrightness,
boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId) {
@@ -428,13 +438,28 @@
}
}
+ private void handleSensorChanged(Sensor lightSensor) {
+ if (mLightSensor != lightSensor) {
+ mLightSensor = lightSensor;
+ stopSensorListener();
+ synchronized (mDataCollectionLock) {
+ mLastSensorReadings.clear();
+ }
+ // Attempt to restart the sensor listener. It will check to see if it should be running
+ // so there is no need to also check here.
+ startSensorListener();
+ }
+ }
+
private void startSensorListener() {
if (!mSensorRegistered
+ && mLightSensor != null
+ && mAmbientBrightnessStatsTracker != null
&& mInjector.isInteractive(mContext)
&& mInjector.isBrightnessModeAutomatic(mContentResolver)) {
mAmbientBrightnessStatsTracker.start();
mSensorRegistered = true;
- mInjector.registerSensorListener(mContext, mSensorListener,
+ mInjector.registerSensorListener(mContext, mSensorListener, mLightSensor,
mInjector.getBackgroundHandler());
}
}
@@ -736,6 +761,7 @@
pw.println("BrightnessTracker state:");
synchronized (mDataCollectionLock) {
pw.println(" mStarted=" + mStarted);
+ pw.println(" mLightSensor=" + mLightSensor);
pw.println(" mLastBatteryLevel=" + mLastBatteryLevel);
pw.println(" mLastBrightness=" + mLastBrightness);
pw.println(" mLastSensorReadings.size=" + mLastSensorReadings.size());
@@ -1017,6 +1043,9 @@
disableColorSampling();
}
break;
+ case MSG_SENSOR_CHANGED:
+ handleSensorChanged((Sensor) msg.obj);
+ break;
}
}
@@ -1045,9 +1074,8 @@
@VisibleForTesting
static class Injector {
public void registerSensorListener(Context context,
- SensorEventListener sensorListener, Handler handler) {
+ SensorEventListener sensorListener, Sensor lightSensor, Handler handler) {
SensorManager sensorManager = context.getSystemService(SensorManager.class);
- Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
sensorManager.registerListener(sensorListener,
lightSensor, SensorManager.SENSOR_DELAY_NORMAL, handler);
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 6866137..064e307 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -42,7 +42,6 @@
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
-import com.android.server.display.config.Interpolation;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
@@ -1254,19 +1253,17 @@
}
}
- private int convertInterpolationType(Interpolation value) {
- if (value == null) {
+ private int convertInterpolationType(String value) {
+ if (TextUtils.isEmpty(value)) {
return INTERPOLATION_DEFAULT;
}
- switch (value) {
- case _default:
- return INTERPOLATION_DEFAULT;
- case linear:
- return INTERPOLATION_LINEAR;
- default:
- Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
- return INTERPOLATION_DEFAULT;
+
+ if ("linear".equals(value)) {
+ return INTERPOLATION_LINEAR;
}
+
+ Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
+ return INTERPOLATION_DEFAULT;
}
private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 418e91d..9067f2e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -826,7 +826,6 @@
private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info) {
// All properties that depend on the associated DisplayDevice and the DDC must be
// updated here.
- loadAmbientLightSensor();
loadBrightnessRampRates();
loadProximitySensor();
loadNitsRange(mContext.getResources());
@@ -972,6 +971,9 @@
}
loadAmbientLightSensor();
+ if (mBrightnessTracker != null) {
+ mBrightnessTracker.setLightSensor(mLightSensor);
+ }
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.stop();
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 940c25c..c15242a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,6 +41,9 @@
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.graphics.PointF;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors;
+import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayViewport;
import android.hardware.input.IInputDevicesChangedListener;
@@ -550,6 +553,19 @@
}
}
+ // Set the HW mic toggle switch state
+ final int micMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+ SW_MUTE_DEVICE);
+ if (micMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+ setSensorPrivacy(Sensors.MICROPHONE, micMuteState != InputManager.SWITCH_STATE_OFF);
+ }
+ // Set the HW camera toggle switch state
+ final int cameraMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+ SW_CAMERA_LENS_COVER);
+ if (cameraMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+ setSensorPrivacy(Sensors.CAMERA, cameraMuteState != InputManager.SWITCH_STATE_OFF);
+ }
+
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -2816,6 +2832,8 @@
if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
+ // Use SW_CAMERA_LENS_COVER code for camera privacy toggles
+ setSensorPrivacy(Sensors.CAMERA, lensCovered);
}
if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
@@ -2836,9 +2854,20 @@
final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
AudioManager audioManager = mContext.getSystemService(AudioManager.class);
audioManager.setMicrophoneMuteFromSwitch(micMute);
+
+ setSensorPrivacy(Sensors.MICROPHONE, micMute);
}
}
+ // Set the sensor privacy state based on the hardware toggles switch states
+ private void setSensorPrivacy(@SensorPrivacyManager.Sensors.Sensor int sensor,
+ boolean enablePrivacy) {
+ final SensorPrivacyManagerInternal sensorPrivacyManagerInternal =
+ LocalServices.getService(SensorPrivacyManagerInternal.class);
+ sensorPrivacyManagerInternal.setPhysicalToggleSensorPrivacy(UserHandle.USER_CURRENT, sensor,
+ enablePrivacy);
+ }
+
// Native callback.
@SuppressWarnings("unused")
private void notifyInputChannelBroken(IBinder token) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 7068ed1..0b7e391 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -130,6 +130,7 @@
import android.view.WindowManager.DisplayImePolicy;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
+import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
@@ -287,6 +288,9 @@
private final InputMethodMenuController mMenuController;
private final InputMethodBindingController mBindingController;
+ // TODO(b/219056452): Use AccessibilityManagerInternal instead.
+ private final AccessibilityManager mAccessibilityManager;
+
/**
* Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
*
@@ -1627,6 +1631,7 @@
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
mPlatformCompat = IPlatformCompat.Stub.asInterface(
@@ -1995,12 +2000,13 @@
@GuardedBy("ImfLock.class")
private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
- InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback) {
+ InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
+ boolean touchExplorationEnabled) {
final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
try {
IInputMethodInvoker curMethod = getCurMethodLocked();
- if (userId == mSettings.getCurrentUserId() && imi != null
- && imi.isInlineSuggestionsEnabled() && curMethod != null) {
+ if (userId == mSettings.getCurrentUserId() && curMethod != null
+ && imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
final IInlineSuggestionsRequestCallback callbackImpl =
new InlineSuggestionsRequestCallbackDecorator(callback,
imi.getPackageName(), mCurTokenDisplayId, getCurTokenLocked(),
@@ -2014,6 +2020,13 @@
}
}
+ private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi,
+ boolean touchExplorationEnabled) {
+ return imi.isInlineSuggestionsEnabled()
+ && (!touchExplorationEnabled
+ || imi.supportsInlineSuggestionsWithTouchExploration());
+ }
+
/**
* The decorator which validates the host package name in the
* {@link InlineSuggestionsRequest} argument to make sure it matches the IME package name.
@@ -5197,8 +5210,12 @@
@Override
public void onCreateInlineSuggestionsRequest(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback cb) {
+ // Get the device global touch exploration state before lock to avoid deadlock.
+ boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
+
synchronized (ImfLock.class) {
- onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb);
+ onCreateInlineSuggestionsRequestLocked(userId, requestInfo, cb,
+ touchExplorationEnabled);
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 8d05415..0052df3 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -257,6 +257,8 @@
import com.android.server.usage.AppStandbyInternal;
import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
+import dalvik.annotation.optimization.NeverCompile;
+
import libcore.io.IoUtils;
import java.io.File;
@@ -3748,6 +3750,7 @@
return 0;
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d34976..16b5fb1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -682,7 +682,14 @@
return mBuffer.descendingIterator();
}
- public StatusBarNotification[] getArray(int count, boolean includeSnoozed) {
+ public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
+ ArrayList<Integer> currentUsers = new ArrayList<>();
+ currentUsers.add(UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() -> {
+ for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+ currentUsers.add(user);
+ }
+ });
synchronized (mBufferLock) {
if (count == 0) count = mBufferSize;
List<StatusBarNotification> a = new ArrayList();
@@ -691,8 +698,10 @@
while (iter.hasNext() && i < count) {
Pair<StatusBarNotification, Integer> pair = iter.next();
if (pair.second != REASON_SNOOZED || includeSnoozed) {
- i++;
- a.add(pair.first);
+ if (currentUsers.contains(pair.first.getUserId())) {
+ i++;
+ a.add(pair.first);
+ }
}
}
return a.toArray(new StatusBarNotification[a.size()]);
@@ -4200,22 +4209,32 @@
android.Manifest.permission.ACCESS_NOTIFICATIONS,
"NotificationManagerService.getActiveNotifications");
- StatusBarNotification[] tmp = null;
+ ArrayList<StatusBarNotification> tmp = new ArrayList<>();
int uid = Binder.getCallingUid();
+ ArrayList<Integer> currentUsers = new ArrayList<>();
+ currentUsers.add(UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() -> {
+ for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+ currentUsers.add(user);
+ }
+ });
+
// noteOp will check to make sure the callingPkg matches the uid
if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
callingAttributionTag, null)
== MODE_ALLOWED) {
synchronized (mNotificationLock) {
- tmp = new StatusBarNotification[mNotificationList.size()];
final int N = mNotificationList.size();
- for (int i=0; i<N; i++) {
- tmp[i] = mNotificationList.get(i).getSbn();
+ for (int i = 0; i < N; i++) {
+ final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
+ if (currentUsers.contains(sbn.getUserId())) {
+ tmp.add(sbn);
+ }
}
}
}
- return tmp;
+ return tmp.toArray(new StatusBarNotification[tmp.size()]);
}
/**
@@ -4324,7 +4343,7 @@
callingAttributionTag, null)
== MODE_ALLOWED) {
synchronized (mArchive) {
- tmp = mArchive.getArray(count, includeSnoozed);
+ tmp = mArchive.getArray(mUm, count, includeSnoozed);
}
}
return tmp;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 70e968f..66c7c50 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -69,6 +69,8 @@
import com.android.server.LocalServices;
import com.android.server.uri.UriGrantsManagerInternal;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
@@ -467,6 +469,7 @@
rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
}
+ @NeverCompile // Avoid size overhead of debugging code.
void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
final Notification notification = getSbn().getNotification();
pw.println(prefix + this);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 39ee0f4..9b10058 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -40,6 +40,7 @@
import android.os.ServiceManager;
import android.os.Trace;
import android.sysprop.ApexProperties;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.PrintWriterPrinter;
@@ -608,18 +609,21 @@
continue;
}
- String name = service.getName();
- for (ApexSystemServiceInfo info : mApexSystemServices) {
- if (info.getName().equals(name)) {
- throw new IllegalStateException(String.format(
- "Duplicate apex-system-service %s from %s, %s",
- name, info.mJarPath, service.getJarPath()));
+ if (ai.isActive) {
+ String name = service.getName();
+ for (int j = 0; j < mApexSystemServices.size(); j++) {
+ ApexSystemServiceInfo info = mApexSystemServices.get(j);
+ if (info.getName().equals(name)) {
+ throw new IllegalStateException(TextUtils.formatSimple(
+ "Duplicate apex-system-service %s from %s, %s", name,
+ info.mJarPath, service.getJarPath()));
+ }
}
+ ApexSystemServiceInfo info = new ApexSystemServiceInfo(
+ service.getName(), service.getJarPath(),
+ service.getInitOrder());
+ mApexSystemServices.add(info);
}
-
- ApexSystemServiceInfo info = new ApexSystemServiceInfo(
- service.getName(), service.getJarPath(), service.getInitOrder());
- mApexSystemServices.add(info);
}
Collections.sort(mApexSystemServices);
mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index d745a23..0b0d1458 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -377,6 +377,12 @@
+ Integer.toHexString(flags) + " migrateAppData=" + migrateAppData);
List<String> result = onlyCoreApps ? new ArrayList<>() : null;
+ try {
+ mInstaller.cleanupInvalidPackageDirs(volumeUuid, userId, flags);
+ } catch (Installer.InstallerException e) {
+ logCriticalInfo(Log.WARN, "Failed to cleanup deleted dirs: " + e);
+ }
+
final File ceDir = Environment.getDataUserCeDirectory(volumeUuid, userId);
final File deDir = Environment.getDataUserDeDirectory(volumeUuid, userId);
diff --git a/services/core/java/com/android/server/pm/DumpHelper.java b/services/core/java/com/android/server/pm/DumpHelper.java
index 5ab0c4c..d5a882b 100644
--- a/services/core/java/com/android/server/pm/DumpHelper.java
+++ b/services/core/java/com/android/server/pm/DumpHelper.java
@@ -37,6 +37,8 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.BiConsumer;
@@ -51,6 +53,7 @@
mPm = pm;
}
+ @NeverCompile // Avoid size overhead of debugging code.
public void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
DumpState dumpState = new DumpState();
ArraySet<String> permissionNames = null;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c4389a7..742cc02 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -357,6 +357,20 @@
}
}
+ /**
+ * Remove all invalid dirs under app data folder.
+ * All dirs are supposed to be valid file and package names.
+ */
+ public void cleanupInvalidPackageDirs(String uuid, int userId, int flags)
+ throws InstallerException {
+ if (!checkBeforeRemote()) return;
+ try {
+ mInstalld.cleanupInvalidPackageDirs(uuid, userId, flags);
+ } catch (Exception e) {
+ throw InstallerException.from(e);
+ }
+ }
+
public void moveCompleteApp(String fromUuid, String toUuid, String packageName,
int appId, String seInfo, int targetSdkVersion,
String fromCodePath) throws InstallerException {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d230004..ced1c7d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -469,16 +469,16 @@
@Nullable
final StagedSession mStagedSession;
+ /**
+ * The callback to run when pre-reboot verification has ended. Used by {@link #abandon()}
+ * to delay session clean-up until it is safe to do so.
+ */
+ @GuardedBy("mLock")
+ @Nullable
+ private Runnable mPendingAbandonCallback;
+
@VisibleForTesting
public class StagedSession implements StagingManager.StagedSession {
- /**
- * The callback to run when pre-reboot verification has ended. Used by {@link #abandon()}
- * to delay session clean-up until it is safe to do so.
- */
- @GuardedBy("mLock")
- @Nullable
- private Runnable mPendingAbandonCallback;
-
@Override
public List<StagingManager.StagedSession> getChildSessions() {
if (!params.isMultiPackage) {
@@ -575,9 +575,7 @@
@Override
public boolean isInTerminalState() {
- synchronized (mLock) {
- return mSessionApplied || mSessionFailed;
- }
+ return PackageInstallerSession.this.isInTerminalState();
}
@Override
@@ -612,48 +610,7 @@
@Override
public void abandon() {
- final Runnable r;
- synchronized (mLock) {
- assertNotChild("StagedSession#abandon");
- assertCallerIsOwnerOrRootOrSystem();
- if (isInTerminalState()) {
- // We keep the session in the database if it's in a finalized state. It will be
- // removed by PackageInstallerService when the last update time is old enough.
- // Also, in such cases cleanStageDir() has already been executed so no need to
- // do it now.
- return;
- }
- mDestroyed = true;
- r = () -> {
- assertNotLocked("abandonStaged");
- if (mCommitted.get()) {
- mStagingManager.abortCommittedSession(this);
- }
- destroy();
- dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
- maybeFinishChildSessions(INSTALL_FAILED_ABORTED,
- "Session was abandoned because the parent session is abandoned");
- };
- if (mStageDirInUse) {
- // Pre-reboot verification is ongoing, not safe to clean up the session yet.
- mPendingAbandonCallback = r;
- mCallback.onSessionChanged(PackageInstallerSession.this);
- return;
- }
- }
- r.run();
- }
-
- /**
- * Called when pre-reboot verification has ended.
- * Now it is safe to clean up the session if {@link #abandon()} has been called previously.
- */
- private void notifyEndPreRebootVerification() {
- synchronized (mLock) {
- Preconditions.checkState(mStageDirInUse);
- mStageDirInUse = false;
- }
- dispatchPendingAbandonCallback();
+ PackageInstallerSession.this.abandon();
}
/**
@@ -669,17 +626,6 @@
Preconditions.checkArgument(!isInTerminalState());
verify();
}
-
- private void dispatchPendingAbandonCallback() {
- final Runnable callback;
- synchronized (mLock) {
- callback = mPendingAbandonCallback;
- mPendingAbandonCallback = null;
- }
- if (callback != null) {
- callback.run();
- }
- }
}
/**
@@ -1138,9 +1084,15 @@
}
}
+ private boolean isInTerminalState() {
+ synchronized (mLock) {
+ return mSessionApplied || mSessionFailed;
+ }
+ }
+
/** Returns true if a staged session has reached a final state and can be forgotten about */
public boolean isStagedAndInTerminalState() {
- return params.isStaged && mStagedSession.isInTerminalState();
+ return params.isStaged && isInTerminalState();
}
private void assertNotLocked(String cookie) {
@@ -1968,9 +1920,6 @@
private void onSessionVerificationFailure(int error, String msg) {
Slog.e(TAG, "Failed to verify session " + sessionId);
- if (isStaged()) {
- mStagedSession.notifyEndPreRebootVerification();
- }
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, msg, null);
maybeFinishChildSessions(error, msg);
@@ -2279,6 +2228,17 @@
}
}
+ @GuardedBy("mLock")
+ private void markStageDirInUseLocked() throws PackageManagerException {
+ if (mDestroyed) {
+ throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+ "Session destroyed");
+ }
+ // Set this flag to prevent abandon() from deleting staging files when verification or
+ // installation is about to start.
+ mStageDirInUse = true;
+ }
+
private void parseApkAndExtractNativeLibraries() throws PackageManagerException {
synchronized (mLock) {
if (mStageDirInUse) {
@@ -2324,19 +2284,14 @@
private void verifyNonStaged()
throws PackageManagerException {
synchronized (mLock) {
- if (mDestroyed) {
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Session destroyed");
- }
- // Set this flag to prevent abandon() from deleting staging files while verification is
- // in progress. For staged sessions, we will reset this flag when verification is done
- // so abandon() can take effect. For non-staged sessions, the staging files will be
- // deleted when install is completed (no matter success or not). No need to reset
- // the flag.
- mStageDirInUse = true;
+ markStageDirInUseLocked();
}
mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> {
mHandler.post(() -> {
+ if (dispatchPendingAbandonCallback()) {
+ // No need to continue if abandoned
+ return;
+ }
if (error == INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
@@ -2426,7 +2381,6 @@
@WorkerThread
private void onVerificationComplete() {
if (isStaged()) {
- mStagedSession.notifyEndPreRebootVerification();
mStagingManager.commitSession(mStagedSession);
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
return;
@@ -2444,14 +2398,11 @@
private InstallParams makeInstallParams(CompletableFuture<Void> future)
throws PackageManagerException {
synchronized (mLock) {
- if (mDestroyed) {
- throw new PackageManagerException(
- INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
- }
if (!mSealed) {
throw new PackageManagerException(
INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
}
+ markStageDirInUseLocked();
}
if (isMultiPackage()) {
@@ -3523,22 +3474,6 @@
}
}
- private void abandonNonStaged() {
- synchronized (mLock) {
- assertNotChild("abandonNonStaged");
- assertCallerIsOwnerOrRootOrSystem();
- if (mStageDirInUse) {
- if (LOGD) Slog.d(TAG, "Ignoring abandon for staging files are in use");
- return;
- }
- mDestroyed = true;
- }
- destroy();
- dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
- maybeFinishChildSessions(INSTALL_FAILED_ABORTED,
- "Session was abandoned because the parent session is abandoned");
- }
-
private void assertNotChild(String cookie) {
if (hasParentSessionId()) {
throw new IllegalStateException(cookie + " can't be called on a child session, id="
@@ -3546,13 +3481,56 @@
}
}
+ /**
+ * Called when verification has completed. Now it is safe to clean up the session
+ * if {@link #abandon()} has been called previously.
+ *
+ * @return True if this session has been abandoned.
+ */
+ private boolean dispatchPendingAbandonCallback() {
+ final Runnable callback;
+ synchronized (mLock) {
+ Preconditions.checkState(mStageDirInUse);
+ mStageDirInUse = false;
+ callback = mPendingAbandonCallback;
+ mPendingAbandonCallback = null;
+ }
+ if (callback != null) {
+ callback.run();
+ return true;
+ }
+ return false;
+ }
+
@Override
public void abandon() {
- if (params.isStaged) {
- mStagedSession.abandon();
- } else {
- abandonNonStaged();
+ final Runnable r;
+ synchronized (mLock) {
+ assertNotChild("abandon");
+ assertCallerIsOwnerOrRootOrSystem();
+ if (isInTerminalState()) {
+ // Finalized sessions have been properly cleaned up. No need to abandon them.
+ return;
+ }
+ mDestroyed = true;
+ r = () -> {
+ assertNotLocked("abandonStaged");
+ if (isStaged() && mCommitted.get()) {
+ mStagingManager.abortCommittedSession(mStagedSession);
+ }
+ destroy();
+ dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null);
+ maybeFinishChildSessions(INSTALL_FAILED_ABORTED,
+ "Session was abandoned because the parent session is abandoned");
+ };
+ if (mStageDirInUse) {
+ // Verification is ongoing, not safe to clean up the session yet.
+ mPendingAbandonCallback = r;
+ mCallback.onSessionChanged(this);
+ return;
+ }
}
+ r.run();
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8f4cef9..725e92a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6255,6 +6255,13 @@
}
});
+ if (wasNotLaunched) {
+ final String installerPackageName = wasNotLaunchedAndInstallerPackageName.second;
+ if (installerPackageName != null) {
+ notifyFirstLaunch(packageName, installerPackageName, userId);
+ }
+ }
+
scheduleWritePackageRestrictions(userId);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c19e758..4d7da1b 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -24,6 +24,7 @@
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
import static android.content.pm.PackageManager.UNINSTALL_REASON_USER_TYPE;
+import static android.os.Process.INVALID_UID;
import static android.os.Process.PACKAGE_INFO_GID;
import static android.os.Process.SYSTEM_UID;
@@ -136,6 +137,8 @@
import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
+import dalvik.annotation.optimization.NeverCompile;
+
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -1117,6 +1120,9 @@
"Updating application package " + pkgName + " failed");
}
pkgSetting.setSharedUserAppId(sharedUser.mAppId);
+ } else {
+ // migrating off shared user
+ pkgSetting.setSharedUserAppId(INVALID_UID);
}
if (!pkgSetting.getPath().equals(codePath)) {
@@ -4514,6 +4520,7 @@
pw.decreaseIndent();
}
+ @NeverCompile // Avoid size overhead of debugging code.
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
ArraySet<String> permissionNames, PackageSetting ps,
LegacyPermissionState permissionsState, SimpleDateFormat sdf, Date date,
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f87063a..9c74dd7 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -71,6 +71,14 @@
"include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
}
]
+ },
+ {
+ "name": "CtsSharedUserMigrationTestCases",
+ "options": [
+ {
+ "include-filter": "android.uidmigration.cts"
+ }
+ ]
}
],
"presubmit-large": [
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 60d2fc1..49553f4 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -740,7 +740,7 @@
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm,
DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE, userId),
- userId, CONTACTS_PERMISSIONS);
+ userId, CONTACTS_PERMISSIONS, NOTIFICATION_PERMISSIONS);
// Maps
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
@@ -775,7 +775,7 @@
grantPermissionsToSystemPackage(pm, voiceInteractPackageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NEARBY_DEVICES_PERMISSIONS);
+ NEARBY_DEVICES_PERMISSIONS, NOTIFICATION_PERMISSIONS);
}
}
@@ -784,7 +784,8 @@
grantPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
- userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS);
+ userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
+ NOTIFICATION_PERMISSIONS);
}
// Voice recognition
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index f199841..91d2010 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -887,7 +887,9 @@
| flag(pkg.hasRequestForegroundServiceExemption(),
ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
| flag(pkg.areAttributionsUserVisible(),
- ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE);
+ ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+ | flag(pkg.isOnBackInvokedCallbackEnabled(),
+ ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK);
// @formatter:on
return privateFlagsExt;
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 1754877..cdc2b12 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -387,6 +387,8 @@
*/
ParsingPackage setKnownActivityEmbeddingCerts(Set<String> knownActivityEmbeddingCerts);
+ ParsingPackage setOnBackInvokedCallbackEnabled(boolean enableOnBackInvokedCallback);
+
// TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
// for moving to the next step
@CallSuper
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index c4b1275..177eaca 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -548,6 +548,7 @@
private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
private static final long SDK_LIBRARY = 1L << 49;
private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
+ private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2397,6 +2398,11 @@
}
@Override
+ public boolean isOnBackInvokedCallbackEnabled() {
+ return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2995,4 +3001,10 @@
mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
return this;
}
+
+ @Override
+ public ParsingPackage setOnBackInvokedCallbackEnabled(boolean value) {
+ setBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK, value);
+ return this;
+ }
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 4b659a14..428374f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -355,4 +355,9 @@
* @see R.styleable#AndroidManifest_inheritKeyStoreKeys
*/
boolean shouldInheritKeyStoreKeys();
+
+ /**
+ * @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+ */
+ boolean isOnBackInvokedCallbackEnabled();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index a891980..f30daa9 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2202,8 +2202,9 @@
.setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
.setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
.setResetEnabledSettingsOnAppDataCleared(bool(false,
- R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
- sa))
+ R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
+ sa))
+ .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
// targetSdkVersion gated
.setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
.setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4b61970..4387249 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3547,6 +3547,10 @@
if (mCameraLensCoverState == lensCoverState) {
return;
}
+ if (!mContext.getResources().getBoolean(
+ R.bool.config_launchCameraOnCameraLensCoverToggle)) {
+ return;
+ }
if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
lensCoverState == CAMERA_LENS_UNCOVERED) {
Intent intent;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index e523153..70a030d 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -128,6 +128,8 @@
import com.android.server.power.batterysaver.BatterySaverStateMachine;
import com.android.server.power.batterysaver.BatterySavingStats;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -2682,8 +2684,8 @@
@GuardedBy("mLock")
private void updateUserActivitySummaryLocked(long now, int dirty) {
// Update the status of the user activity timeout timer.
- if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS
- | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) == 0) {
+ if ((dirty & (DIRTY_DISPLAY_GROUP_WAKEFULNESS | DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
+ | DIRTY_WAKEFULNESS | DIRTY_SETTINGS | DIRTY_ATTENTIVE)) == 0) {
return;
}
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
@@ -2770,6 +2772,11 @@
screenDimDuration);
}
+ if (isAttentiveTimeoutExpired(powerGroup, now)) {
+ groupUserActivitySummary = 0;
+ groupNextTimeout = -1;
+ }
+
hasUserActivitySummary |= groupUserActivitySummary != 0;
if (nextTimeout == -1) {
@@ -3125,7 +3132,7 @@
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.arg1 = powerGroup.getGroupId();
msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
}
}
@@ -4340,6 +4347,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
private void dumpInternal(PrintWriter pw) {
pw.println("POWER MANAGER (dumpsys power)\n");
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1856786..fd64c75 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,16 +16,11 @@
package com.android.server.rollback;
-import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
-
import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
@@ -240,64 +235,6 @@
return null;
}
- @WorkerThread
- private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
- int rollbackId, @Nullable VersionedPackage logPackage) {
- assertInWorkerThread();
- BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- handleStagedSessionChange(rollbackManager,
- rollbackId, this /* BroadcastReceiver */, logPackage);
- }
- };
- IntentFilter sessionUpdatedFilter =
- new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
- mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter, null, mHandler);
- return sessionUpdatedReceiver;
- }
-
- @WorkerThread
- private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
- BroadcastReceiver listener, @Nullable VersionedPackage logPackage) {
- assertInWorkerThread();
- PackageInstaller packageInstaller =
- mContext.getPackageManager().getPackageInstaller();
- List<RollbackInfo> recentRollbacks =
- rollbackManager.getRecentlyCommittedRollbacks();
- for (int i = 0; i < recentRollbacks.size(); i++) {
- RollbackInfo recentRollback = recentRollbacks.get(i);
- int sessionId = recentRollback.getCommittedSessionId();
- if ((rollbackId == recentRollback.getRollbackId())
- && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
- PackageInstaller.SessionInfo sessionInfo =
- packageInstaller.getSessionInfo(sessionId);
- if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) {
- mContext.unregisterReceiver(listener);
- saveStagedRollbackId(rollbackId, logPackage);
- WatchdogRollbackLogger.logEvent(logPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
- "");
- } else if (sessionInfo.isStagedSessionFailed()
- && markStagedSessionHandled(rollbackId)) {
- WatchdogRollbackLogger.logEvent(logPackage,
- FrameworkStatsLog
- .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
- WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
- "");
- mContext.unregisterReceiver(listener);
- }
- }
- }
-
- // Wait for all pending staged sessions to get handled before rebooting.
- if (isPendingStagedSessionsEmpty()) {
- mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
- }
- }
-
/**
* Returns {@code true} if staged session associated with {@code rollbackId} was marked
* as handled, {@code false} if already handled.
@@ -447,12 +384,12 @@
if (status == RollbackManager.STATUS_SUCCESS) {
if (rollback.isStaged()) {
int rollbackId = rollback.getRollbackId();
- mPendingStagedRollbackIds.add(rollbackId);
- BroadcastReceiver listener =
- listenForStagedSessionReady(rollbackManager, rollbackId,
- logPackage);
- handleStagedSessionChange(rollbackManager, rollbackId, listener,
- logPackage);
+ saveStagedRollbackId(rollbackId, logPackage);
+ WatchdogRollbackLogger.logEvent(logPackage,
+ FrameworkStatsLog
+ .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
+ reasonToLog, failedPackageToLog);
+
} else {
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
@@ -460,14 +397,18 @@
reasonToLog, failedPackageToLog);
}
} else {
- if (rollback.isStaged()) {
- markStagedSessionHandled(rollback.getRollbackId());
- }
WatchdogRollbackLogger.logEvent(logPackage,
FrameworkStatsLog
.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
reasonToLog, failedPackageToLog);
}
+ if (rollback.isStaged()) {
+ markStagedSessionHandled(rollback.getRollbackId());
+ // Wait for all pending staged sessions to get handled before rebooting.
+ if (isPendingStagedSessionsEmpty()) {
+ mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+ }
+ }
};
final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
diff --git a/services/core/java/com/android/server/sensorprivacy/PersistedState.java b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
index ce9fff5..06f5fc0 100644
--- a/services/core/java/com/android/server/sensorprivacy/PersistedState.java
+++ b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
@@ -295,6 +295,11 @@
TypeUserSensor userSensor = states.keyAt(i);
SensorState sensorState = states.valueAt(i);
+ // Do not persist hardware toggle states. Will be restored on reboot
+ if (userSensor.mType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
+ continue;
+ }
+
serializer.startTag(null, XML_TAG_SENSOR_STATE);
serializer.attributeInt(null, XML_ATTRIBUTE_TOGGLE_TYPE,
userSensor.mType);
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 19c8cd2..358f69e 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -39,6 +39,8 @@
import static android.hardware.SensorPrivacyManager.Sources.QS_TILE;
import static android.hardware.SensorPrivacyManager.Sources.SETTINGS;
import static android.hardware.SensorPrivacyManager.Sources.SHELL;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.HARDWARE;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.SOFTWARE;
import static android.os.UserHandle.USER_NULL;
import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
@@ -108,7 +110,6 @@
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
-import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
@@ -127,6 +128,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
@@ -139,7 +141,7 @@
private static final boolean DEBUG_LOGGING = false;
private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE;
- private static final String ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY =
+ private static final String ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY =
SensorPrivacyService.class.getName() + ".action.disable_sensor_privacy";
public static final int REMINDER_DIALOG_DELAY_MILLIS = 500;
@@ -273,12 +275,12 @@
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- setIndividualSensorPrivacy(
+ setToggleSensorPrivacy(
((UserHandle) intent.getParcelableExtra(
Intent.EXTRA_USER)).getIdentifier(), OTHER,
intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
}
- }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY),
+ }, new IntentFilter(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY),
MANAGE_SENSOR_PRIVACY, null, Context.RECEIVER_EXPORTED);
mContext.registerReceiver(new BroadcastReceiver() {
@@ -299,7 +301,7 @@
mSensorPrivacyStateController.setSensorPrivacyListener(
mHandler,
(toggleType, userId, sensor, state) -> mHandler.handleSensorPrivacyChanged(
- userId, sensor, state.isEnabled()));
+ userId, toggleType, sensor, state.isEnabled()));
}
@Override
@@ -308,11 +310,11 @@
// Reset sensor privacy when restriction is added
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) {
- setIndividualSensorPrivacyUnchecked(userId, OTHER, CAMERA, false);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, CAMERA, false);
}
if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)
&& newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) {
- setIndividualSensorPrivacyUnchecked(userId, OTHER, MICROPHONE, false);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, MICROPHONE, false);
}
}
@@ -352,15 +354,15 @@
}
/**
- * Called when a sensor protected by individual sensor privacy is attempting to get used.
+ * Called when a sensor protected by toggle sensor privacy is attempting to get used.
*
* @param uid The uid of the app using the sensor
* @param packageName The package name of the app using the sensor
* @param sensor The sensor that is attempting to be used
*/
private void onSensorUseStarted(int uid, String packageName, int sensor) {
- UserHandle user = UserHandle.getUserHandleForUid(uid);
- if (!isIndividualSensorPrivacyEnabled(user.getIdentifier(), sensor)) {
+ UserHandle user = UserHandle.of(mCurrentUser);
+ if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
return;
}
@@ -371,12 +373,10 @@
}
synchronized (mLock) {
- UserHandle parentUser = UserHandle.of(mUserManagerInternal
- .getProfileParentId(user.getIdentifier()));
- if (mSuppressReminders.containsKey(new Pair<>(sensor, parentUser))) {
+ if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
Log.d(TAG,
"Suppressed sensor privacy reminder for " + packageName + "/"
- + parentUser);
+ + user);
return;
}
}
@@ -406,8 +406,8 @@
}
tasksOfPackageUsingSensor.add(task);
- } else if (task.topActivity.flattenToString().equals(mContext.getResources()
- .getString(R.string.config_sensorUseStartedActivity))
+ } else if (task.topActivity.flattenToString().equals(
+ getSensorUseActivityName(new ArraySet<>(Arrays.asList(sensor))))
&& task.isFocused) {
enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName,
sensor);
@@ -442,7 +442,7 @@
String inputMethodComponent = Settings.Secure.getStringForUser(
mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
- mCurrentUser);
+ user.getIdentifier());
String inputMethodPackageName = null;
if (inputMethodComponent != null) {
inputMethodPackageName = ComponentName.unflattenFromString(
@@ -534,9 +534,8 @@
return;
}
Intent dialogIntent = new Intent();
- dialogIntent.setComponent(ComponentName.unflattenFromString(
- mContext.getResources().getString(
- R.string.config_sensorUseStartedActivity)));
+ dialogIntent.setComponent(
+ ComponentName.unflattenFromString(getSensorUseActivityName(sensors)));
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchTaskId(info.mTaskId);
@@ -560,6 +559,21 @@
}
/**
+ * Get the activity component based on which privacy toggles are enabled.
+ * @param sensors
+ * @return component name to launch
+ */
+ private String getSensorUseActivityName(ArraySet<Integer> sensors) {
+ for (Integer sensor : sensors) {
+ if (isToggleSensorPrivacyEnabled(HARDWARE, sensor)) {
+ return mContext.getResources().getString(
+ R.string.config_sensorUseStartedActivity_hwToggle);
+ }
+ }
+ return mContext.getResources().getString(R.string.config_sensorUseStartedActivity);
+ }
+
+ /**
* Show a notification that informs the user that a sensor use or a blocked sensor started.
* The user can then react to this event.
*
@@ -619,7 +633,7 @@
String actionTitle = getUiContext().getString(
R.string.sensor_privacy_start_use_dialog_turn_on_button);
PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, sensor,
- new Intent(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY)
+ new Intent(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY)
.setPackage(mContext.getPackageName())
.putExtra(EXTRA_SENSOR, sensor)
.putExtra(Intent.EXTRA_USER, user),
@@ -657,12 +671,12 @@
}
@Override
- public void setIndividualSensorPrivacy(@UserIdInt int userId,
+ public void setToggleSensorPrivacy(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
if (DEBUG) {
Log.d(TAG, "callingUid=" + Binder.getCallingUid()
+ " callingPid=" + Binder.getCallingPid()
- + " setIndividualSensorPrivacy("
+ + " setToggleSensorPrivacy("
+ "userId=" + userId
+ " source=" + source
+ " sensor=" + sensor
@@ -673,22 +687,22 @@
if (userId == UserHandle.USER_CURRENT) {
userId = mCurrentUser;
}
- if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
+ if (!canChangeToggleSensorPrivacy(userId, sensor)) {
return;
}
- setIndividualSensorPrivacyUnchecked(userId, source, sensor, enable);
+ setToggleSensorPrivacyUnchecked(SOFTWARE, userId, source, sensor, enable);
}
- private void setIndividualSensorPrivacyUnchecked(int userId, int source, int sensor,
- boolean enable) {
+ private void setToggleSensorPrivacyUnchecked(int toggleType, int userId, int source,
+ int sensor, boolean enable) {
final long[] lastChange = new long[1];
mSensorPrivacyStateController.atomic(() -> {
SensorState sensorState = mSensorPrivacyStateController
- .getState(SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor);
+ .getState(toggleType, userId, sensor);
lastChange[0] = sensorState.getLastChange();
mSensorPrivacyStateController.setState(
- SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor, enable, mHandler,
+ toggleType, userId, sensor, enable, mHandler,
changeSuccessful -> {
if (changeSuccessful) {
if (userId == mUserManagerInternal.getProfileParentId(userId)) {
@@ -701,7 +715,7 @@
});
}
- private boolean canChangeIndividualSensorPrivacy(@UserIdInt int userId, int sensor) {
+ private boolean canChangeToggleSensorPrivacy(@UserIdInt int userId, int sensor) {
if (sensor == MICROPHONE && mCallStateHelper.isInEmergencyCall()) {
// During emergency call the microphone toggle managed automatically
Log.i(TAG, "Can't change mic toggle during an emergency call");
@@ -784,7 +798,7 @@
}
@Override
- public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
+ public void setToggleSensorPrivacyForProfileGroup(@UserIdInt int userId,
@SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
enforceManageSensorPrivacyPermission();
if (userId == UserHandle.USER_CURRENT) {
@@ -793,7 +807,7 @@
int parentId = mUserManagerInternal.getProfileParentId(userId);
forAllUsers(userId2 -> {
if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
- setIndividualSensorPrivacy(userId2, source, sensor, enable);
+ setToggleSensorPrivacy(userId2, source, sensor, enable);
}
});
}
@@ -835,31 +849,55 @@
}
@Override
- public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+ public boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor) {
if (DEBUG) {
Log.d(TAG, "callingUid=" + Binder.getCallingUid()
+ " callingPid=" + Binder.getCallingPid()
- + " isIndividualSensorPrivacyEnabled("
- + "userId=" + userId
+ + " isToggleSensorPrivacyEnabled("
+ + "toggleType=" + toggleType
+ " sensor=" + sensor
+ ")");
}
enforceObserveSensorPrivacyPermission();
- if (userId == UserHandle.USER_CURRENT) {
- userId = mCurrentUser;
- }
- return mSensorPrivacyStateController.getState(SensorPrivacyManager.ToggleTypes.SOFTWARE,
+
+ return mSensorPrivacyStateController.getState(toggleType, mCurrentUser, sensor)
+ .isEnabled();
+ }
+
+ @Override
+ public boolean isCombinedToggleSensorPrivacyEnabled(int sensor) {
+ return isToggleSensorPrivacyEnabled(SOFTWARE, sensor) || isToggleSensorPrivacyEnabled(
+ HARDWARE, sensor);
+ }
+
+ private boolean isToggleSensorPrivacyEnabledInternal(int userId, int toggleType,
+ int sensor) {
+
+ return mSensorPrivacyStateController.getState(toggleType,
userId, sensor).isEnabled();
}
@Override
- public boolean supportsSensorToggle(int sensor) {
- if (sensor == MICROPHONE) {
- return mContext.getResources().getBoolean(R.bool.config_supportsMicToggle);
- } else if (sensor == CAMERA) {
- return mContext.getResources().getBoolean(R.bool.config_supportsCamToggle);
+ public boolean supportsSensorToggle(int toggleType, int sensor) {
+ if (toggleType == SOFTWARE) {
+ if (sensor == MICROPHONE) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsMicToggle);
+ } else if (sensor == CAMERA) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsCamToggle);
+ }
+ } else if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
+ if (sensor == MICROPHONE) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsHardwareMicToggle);
+ } else if (sensor == CAMERA) {
+ return mContext.getResources()
+ .getBoolean(R.bool.config_supportsHardwareCamToggle);
+ }
}
- throw new IllegalArgumentException("Unable to find value " + sensor);
+ throw new IllegalArgumentException("Invalid arguments. "
+ + "toggleType=" + toggleType + " sensor=" + sensor);
}
/**
@@ -878,29 +916,13 @@
* Registers a listener to be notified when the sensor privacy state changes.
*/
@Override
- public void addIndividualSensorPrivacyListener(int userId, int sensor,
- ISensorPrivacyListener listener) {
+ public void addToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
+ Log.d("evan", "trying to add from " + Binder.getCallingUid());
enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mHandler.addListener(userId, sensor, listener);
- }
-
-
- /**
- * Registers a listener to be notified when the sensor privacy state changes. The callback
- * can be called if the user changes and the setting is different between the transitioning
- * users.
- */
- @Override
- public void addUserGlobalIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
- enforceObserveSensorPrivacyPermission();
- if (listener == null) {
- throw new IllegalArgumentException("listener cannot be null");
- }
- mHandler.addUserGlobalListener(sensor, listener);
+ mHandler.addToggleListener(listener);
}
/**
@@ -919,27 +941,16 @@
* Unregisters a listener from sensor privacy state change notifications.
*/
@Override
- public void removeIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
+ public void removeToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
enforceObserveSensorPrivacyPermission();
if (listener == null) {
throw new IllegalArgumentException("listener cannot be null");
}
- mHandler.removeListener(sensor, listener);
+ mHandler.removeToggleListener(listener);
}
@Override
- public void removeUserGlobalIndividualSensorPrivacyListener(int sensor,
- ISensorPrivacyListener listener) {
- enforceObserveSensorPrivacyPermission();
- if (listener == null) {
- throw new IllegalArgumentException("listener cannot be null");
- }
- mHandler.removeUserGlobalListener(sensor, listener);
- }
-
- @Override
- public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
+ public void suppressToggleSensorPrivacyReminders(int userId, int sensor,
IBinder token, boolean suppress) {
enforceManageSensorPrivacyPermission();
if (userId == UserHandle.USER_CURRENT) {
@@ -976,7 +987,7 @@
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Can only be called by the system uid");
}
- if (!isIndividualSensorPrivacyEnabled(mCurrentUser, sensor)) {
+ if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
return;
}
enqueueSensorUseReminderDialogAsync(
@@ -984,23 +995,46 @@
}
private void userSwitching(int from, int to) {
- final boolean[] micState = new boolean[1];
- final boolean[] camState = new boolean[1];
- final boolean[] prevMicState = new boolean[1];
- final boolean[] prevCamState = new boolean[1];
+ final boolean[] micState = new boolean[2];
+ final boolean[] camState = new boolean[2];
+ final boolean[] prevMicState = new boolean[2];
+ final boolean[] prevCamState = new boolean[2];
+ final int swToggleIdx = 0;
+ final int hwToggleIdx = 1;
+ // Get SW toggles state
mSensorPrivacyStateController.atomic(() -> {
- prevMicState[0] = isIndividualSensorPrivacyEnabled(from, MICROPHONE);
- prevCamState[0] = isIndividualSensorPrivacyEnabled(from, CAMERA);
- micState[0] = isIndividualSensorPrivacyEnabled(to, MICROPHONE);
- camState[0] = isIndividualSensorPrivacyEnabled(to, CAMERA);
+ prevMicState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+ MICROPHONE);
+ prevCamState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+ CAMERA);
+ micState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE,
+ MICROPHONE);
+ camState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE, CAMERA);
});
- if (from == USER_NULL || prevMicState[0] != micState[0]) {
- mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState[0]);
- setGlobalRestriction(MICROPHONE, micState[0]);
+ // Get HW toggles state
+ mSensorPrivacyStateController.atomic(() -> {
+ prevMicState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+ MICROPHONE);
+ prevCamState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+ CAMERA);
+ micState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE,
+ MICROPHONE);
+ camState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE, CAMERA);
+ });
+
+ if (from == USER_NULL || prevMicState[swToggleIdx] != micState[swToggleIdx]
+ || prevMicState[hwToggleIdx] != micState[hwToggleIdx]) {
+ mHandler.handleSensorPrivacyChanged(to, SOFTWARE, MICROPHONE,
+ micState[swToggleIdx]);
+ mHandler.handleSensorPrivacyChanged(to, HARDWARE, MICROPHONE,
+ micState[hwToggleIdx]);
+ setGlobalRestriction(MICROPHONE, micState[swToggleIdx] || micState[hwToggleIdx]);
}
- if (from == USER_NULL || prevCamState[0] != camState[0]) {
- mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState[0]);
- setGlobalRestriction(CAMERA, camState[0]);
+ if (from == USER_NULL || prevCamState[swToggleIdx] != camState[swToggleIdx]
+ || prevCamState[hwToggleIdx] != camState[hwToggleIdx]) {
+ mHandler.handleSensorPrivacyChanged(to, SOFTWARE, CAMERA, camState[swToggleIdx]);
+ mHandler.handleSensorPrivacyChanged(to, HARDWARE, CAMERA, camState[hwToggleIdx]);
+ setGlobalRestriction(CAMERA, camState[swToggleIdx] || camState[hwToggleIdx]);
}
}
@@ -1153,7 +1187,7 @@
return -1;
}
- setIndividualSensorPrivacy(userId, SHELL, sensor, true);
+ setToggleSensorPrivacy(userId, SHELL, sensor, true);
}
break;
case "disable" : {
@@ -1163,7 +1197,7 @@
return -1;
}
- setIndividualSensorPrivacy(userId, SHELL, sensor, false);
+ setToggleSensorPrivacy(userId, SHELL, sensor, false);
}
break;
default:
@@ -1205,11 +1239,8 @@
private final RemoteCallbackList<ISensorPrivacyListener> mListeners =
new RemoteCallbackList<>();
@GuardedBy("mListenerLock")
- private final SparseArray<SparseArray<RemoteCallbackList<ISensorPrivacyListener>>>
- mIndividualSensorListeners = new SparseArray<>();
- @GuardedBy("mListenerLock")
- private final SparseArray<RemoteCallbackList<ISensorPrivacyListener>>
- mUserGlobalIndividualSensorListeners = new SparseArray<>();
+ private final RemoteCallbackList<ISensorPrivacyListener>
+ mToggleSensorListeners = new RemoteCallbackList<>();
@GuardedBy("mListenerLock")
private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>>
mDeathRecipients;
@@ -1221,12 +1252,6 @@
mContext = context;
}
- public void onUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
- sendMessage(PooledLambda.obtainMessage(
- SensorPrivacyHandler::handleUserGlobalSensorPrivacyChanged,
- this, sensor, enabled));
- }
-
public void addListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
if (mListeners.register(listener)) {
@@ -1235,34 +1260,9 @@
}
}
- public void addListener(int userId, int sensor, ISensorPrivacyListener listener) {
+ public void addToggleListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
- mIndividualSensorListeners.get(userId);
- if (listenersForUser == null) {
- listenersForUser = new SparseArray<>();
- mIndividualSensorListeners.put(userId, listenersForUser);
- }
- RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
- if (listeners == null) {
- listeners = new RemoteCallbackList<>();
- listenersForUser.put(sensor, listeners);
- }
- if (listeners.register(listener)) {
- addDeathRecipient(listener);
- }
- }
- }
-
- public void addUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
- synchronized (mListenerLock) {
- RemoteCallbackList<ISensorPrivacyListener> listeners =
- mUserGlobalIndividualSensorListeners.get(sensor);
- if (listeners == null) {
- listeners = new RemoteCallbackList<>();
- mUserGlobalIndividualSensorListeners.put(sensor, listeners);
- }
- if (listeners.register(listener)) {
+ if (mToggleSensorListeners.register(listener)) {
addDeathRecipient(listener);
}
}
@@ -1276,28 +1276,10 @@
}
}
- public void removeListener(int sensor, ISensorPrivacyListener listener) {
+ public void removeToggleListener(ISensorPrivacyListener listener) {
synchronized (mListenerLock) {
- for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
- RemoteCallbackList callbacks =
- mIndividualSensorListeners.valueAt(i).get(sensor);
- if (callbacks != null) {
- if (callbacks.unregister(listener)) {
- removeDeathRecipient(listener);
- }
- }
- }
- }
- }
-
- public void removeUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
- synchronized (mListenerLock) {
- RemoteCallbackList callbacks =
- mUserGlobalIndividualSensorListeners.get(sensor);
- if (callbacks != null) {
- if (callbacks.unregister(listener)) {
- removeDeathRecipient(listener);
- }
+ if (mToggleSensorListeners.unregister(listener)) {
+ removeDeathRecipient(listener);
}
}
}
@@ -1307,7 +1289,7 @@
for (int i = 0; i < count; i++) {
ISensorPrivacyListener listener = mListeners.getBroadcastItem(i);
try {
- listener.onSensorPrivacyChanged(enabled);
+ listener.onSensorPrivacyChanged(-1, -1, enabled);
} catch (RemoteException e) {
Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
}
@@ -1315,62 +1297,34 @@
mListeners.finishBroadcast();
}
- public void handleSensorPrivacyChanged(int userId, int sensor, boolean enabled) {
- // TODO handle hardware
+ public void handleSensorPrivacyChanged(int userId, int toggleType, int sensor,
+ boolean enabled) {
mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled);
- SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
- mIndividualSensorListeners.get(userId);
if (userId == mCurrentUser) {
- mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, enabled);
+ mSensorPrivacyServiceImpl.setGlobalRestriction(sensor,
+ mSensorPrivacyServiceImpl.isCombinedToggleSensorPrivacyEnabled(sensor));
}
- if (userId == mCurrentUser) {
- onUserGlobalSensorPrivacyChanged(sensor, enabled);
- }
-
- if (listenersForUser == null) {
+ if (userId != mCurrentUser) {
return;
}
- RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
- if (listeners == null) {
- return;
- }
- try {
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+ synchronized (mListenerLock) {
+ try {
+ final int count = mToggleSensorListeners.beginBroadcast();
+ for (int i = 0; i < count; i++) {
+ ISensorPrivacyListener listener = mToggleSensorListeners.getBroadcastItem(
+ i);
+ try {
+ listener.onSensorPrivacyChanged(toggleType, sensor, enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Caught an exception notifying listener " + listener + ": ",
+ e);
+ }
}
+ } finally {
+ mToggleSensorListeners.finishBroadcast();
}
- } finally {
- listeners.finishBroadcast();
- }
- }
-
- public void handleUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
- RemoteCallbackList<ISensorPrivacyListener> listeners =
- mUserGlobalIndividualSensorListeners.get(sensor);
-
- if (listeners == null) {
- return;
- }
-
- try {
- final int count = listeners.beginBroadcast();
- for (int i = 0; i < count; i++) {
- ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
- try {
- listener.onSensorPrivacyChanged(enabled);
- } catch (RemoteException e) {
- Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
- }
- }
- } finally {
- listeners.finishBroadcast();
}
}
@@ -1482,7 +1436,8 @@
@Override
public boolean isSensorPrivacyEnabled(int userId, int sensor) {
return SensorPrivacyService.this
- .mSensorPrivacyServiceImpl.isIndividualSensorPrivacyEnabled(userId, sensor);
+ .mSensorPrivacyServiceImpl.isToggleSensorPrivacyEnabledInternal(userId,
+ SOFTWARE, sensor);
}
@Override
@@ -1521,6 +1476,23 @@
sensorListeners.add(listener);
}
}
+
+ @Override
+ public void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable) {
+ final SensorPrivacyServiceImpl sps =
+ SensorPrivacyService.this.mSensorPrivacyServiceImpl;
+
+ // Convert userId to actual user Id. mCurrentUser is USER_NULL if toggle state is set
+ // before onUserStarting.
+ userId = (userId == UserHandle.USER_CURRENT ? mCurrentUser : userId);
+ final int realUserId = (userId == UserHandle.USER_NULL ? mContext.getUserId() : userId);
+
+ sps.setToggleSensorPrivacyUnchecked(HARDWARE, realUserId, OTHER, sensor, enable);
+ // Also disable the SW toggle when disabling the HW toggle
+ if (!enable) {
+ sps.setToggleSensorPrivacyUnchecked(SOFTWARE, realUserId, OTHER, sensor, enable);
+ }
+ }
}
private class CallStateHelper {
@@ -1574,9 +1546,9 @@
if (!mIsInEmergencyCall) {
mIsInEmergencyCall = true;
if (mSensorPrivacyServiceImpl
- .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
- mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- mCurrentUser, OTHER, MICROPHONE, false);
+ .isToggleSensorPrivacyEnabled(SOFTWARE, MICROPHONE)) {
+ mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+ SOFTWARE, mCurrentUser, OTHER, MICROPHONE, false);
mMicUnmutedForEmergencyCall = true;
} else {
mMicUnmutedForEmergencyCall = false;
@@ -1601,8 +1573,8 @@
if (mIsInEmergencyCall) {
mIsInEmergencyCall = false;
if (mMicUnmutedForEmergencyCall) {
- mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
- mCurrentUser, OTHER, MICROPHONE, true);
+ mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+ SOFTWARE, mCurrentUser, OTHER, MICROPHONE, true);
mMicUnmutedForEmergencyCall = false;
}
}
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
index d1ea8e9..3dcb4cf 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
@@ -16,7 +16,6 @@
package com.android.server.sensorprivacy;
-import android.hardware.SensorPrivacyManager;
import android.os.Handler;
import com.android.internal.util.dump.DualDumpOutputStream;
@@ -49,10 +48,6 @@
@Override
SensorState getStateLocked(int toggleType, int userId, int sensor) {
- if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
- // Device doesn't support hardware state
- return getDefaultSensorState();
- }
SensorState sensorState = mPersistedState.getState(toggleType, userId, sensor);
if (sensorState != null) {
return new SensorState(sensorState);
@@ -67,12 +62,6 @@
@Override
void setStateLocked(int toggleType, int userId, int sensor, boolean enabled,
Handler callbackHandler, SetStateResultCallback callback) {
- if (toggleType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
- // Implementation only supports software switch
- callbackHandler.sendMessage(PooledLambda.obtainMessage(
- SetStateResultCallback::callback, callback, false));
- return;
- }
// Changing the SensorState's mEnabled updates the timestamp of its last change.
// A nonexistent state -> unmuted should not set the timestamp.
SensorState lastState = mPersistedState.getState(toggleType, userId, sensor);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index adee325..8ec0556 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -15,7 +15,6 @@
*/
package com.android.server.stats.pull;
-
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@@ -74,6 +73,7 @@
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
import android.app.INotificationManager;
+import android.app.PendingIntentStats;
import android.app.ProcessMemoryState;
import android.app.RuntimeAppOpAccessMessage;
import android.app.StatsManager;
@@ -727,6 +727,8 @@
return pullAccessibilityFloatingMenuStatsLocked(atomTag, data);
case FrameworkStatsLog.MEDIA_CAPABILITIES:
return pullMediaCapabilitiesStats(atomTag, data);
+ case FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE:
+ return pullPendingIntentsPerPackage(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -923,6 +925,7 @@
registerAccessibilityShortcutStats();
registerAccessibilityFloatingMenuStats();
registerMediaCapabilitiesStats();
+ registerPendingIntentsPerPackagePuller();
}
private void initAndRegisterNetworkStatsPullers() {
@@ -1072,7 +1075,7 @@
private void registerWifiBytesTransfer() {
int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1085,12 +1088,12 @@
@NonNull
private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) {
List<NetworkStatsExt> ret = new ArrayList<>();
- switch(atomTag) {
+ switch (atomTag) {
case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
}
break;
}
@@ -1098,7 +1101,7 @@
final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
+ new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
}
break;
}
@@ -1107,7 +1110,7 @@
getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
}
break;
}
@@ -1116,7 +1119,7 @@
getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
}
break;
}
@@ -1125,11 +1128,11 @@
new NetworkTemplate.Builder(MATCH_WIFI).build(), /*includeTags=*/true);
final NetworkStats cellularStats = getUidNetworkStatsSnapshotForTemplate(
new NetworkTemplate.Builder(MATCH_MOBILE)
- .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
+ .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
if (wifiStats != null && cellularStats != null) {
final NetworkStats stats = wifiStats.add(cellularStats);
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
- new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+ new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
/*slicedByFgbg=*/false, /*slicedByTag=*/true,
/*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
/*subInfo=*/null, OEM_MANAGED_ALL));
@@ -1196,7 +1199,8 @@
return StatsManager.PULL_SUCCESS;
}
- @NonNull private static NetworkStats removeEmptyEntries(NetworkStats stats) {
+ @NonNull
+ private static NetworkStats removeEmptyEntries(NetworkStats stats) {
NetworkStats ret = new NetworkStats(0, 1);
for (NetworkStats.Entry e : stats) {
if (e.getRxBytes() != 0 || e.getRxPackets() != 0 || e.getTxBytes() != 0
@@ -1278,13 +1282,14 @@
}
}
- @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
+ @NonNull
+ private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
final List<Pair<Integer, Integer>> matchRulesAndTransports = List.of(
new Pair(MATCH_ETHERNET, TRANSPORT_ETHERNET),
new Pair(MATCH_MOBILE, TRANSPORT_CELLULAR),
new Pair(MATCH_WIFI, TRANSPORT_WIFI)
);
- final int[] oemManagedTypes = new int[] {OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
+ final int[] oemManagedTypes = new int[]{OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
OEM_MANAGED_PAID, OEM_MANAGED_PRIVATE};
final List<NetworkStatsExt> ret = new ArrayList<>();
@@ -1301,7 +1306,7 @@
final Integer transport = ruleAndTransport.second;
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
- new int[] {transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+ new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
/*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
/*subInfo=*/null, oemManaged));
}
@@ -1314,7 +1319,8 @@
/**
* Create a snapshot of NetworkStats for a given transport.
*/
- @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
+ @Nullable
+ private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
NetworkTemplate template = null;
switch (transport) {
case TRANSPORT_CELLULAR:
@@ -1336,7 +1342,8 @@
* Note that this should be only used to calculate diff since the snapshot might contains
* some traffic before boot.
*/
- @Nullable private NetworkStats getUidNetworkStatsSnapshotForTemplate(
+ @Nullable
+ private NetworkStats getUidNetworkStatsSnapshotForTemplate(
@NonNull NetworkTemplate template, boolean includeTags) {
final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
@@ -1354,8 +1361,8 @@
final android.app.usage.NetworkStats queryNonTaggedStats =
mNetworkStatsManager.querySummary(
- template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+ currentTimeInMillis);
final NetworkStats nonTaggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
@@ -1363,27 +1370,28 @@
final android.app.usage.NetworkStats queryTaggedStats =
mNetworkStatsManager.queryTaggedSummary(template,
- currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
- currentTimeInMillis);
+ currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+ currentTimeInMillis);
final NetworkStats taggedStats =
NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
return nonTaggedStats.add(taggedStats);
}
- @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
+ @NonNull
+ private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
@NonNull SubInfo subInfo) {
final List<NetworkStatsExt> ret = new ArrayList<>();
for (final int ratType : getAllCollapsedRatTypes()) {
final NetworkTemplate template =
new NetworkTemplate.Builder(MATCH_MOBILE)
- .setSubscriberIds(Set.of(subInfo.subscriberId))
- .setRatType(ratType)
- .setMeteredness(METERED_YES).build();
+ .setSubscriberIds(Set.of(subInfo.subscriberId))
+ .setRatType(ratType)
+ .setMeteredness(METERED_YES).build();
final NetworkStats stats =
getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
if (stats != null) {
ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
- new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
+ new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
/*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
OEM_MANAGED_ALL));
}
@@ -1412,51 +1420,55 @@
return com.android.net.module.util.CollectionUtils.toIntArray(collapsedRatTypes);
}
- @NonNull private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
- entry.getSet(), NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
+ entry.getSet(), NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- entry.getSet(), NetworkStats.TAG_NONE,
- NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ entry.getSet(), NetworkStats.TAG_NONE,
+ NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
- @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
+ @NonNull
+ private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
return sliceNetworkStats(stats,
(entry) -> {
- return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
- NetworkStats.SET_ALL, entry.getTag(),
- entry.getMetered(), NetworkStats.ROAMING_ALL,
- NetworkStats.DEFAULT_NETWORK_ALL,
- entry.getRxBytes(), entry.getRxPackets(),
- entry.getTxBytes(), entry.getTxPackets(), 0);
+ return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+ NetworkStats.SET_ALL, entry.getTag(),
+ entry.getMetered(), NetworkStats.ROAMING_ALL,
+ NetworkStats.DEFAULT_NETWORK_ALL,
+ entry.getRxBytes(), entry.getRxPackets(),
+ entry.getTxBytes(), entry.getTxPackets(), 0);
});
}
@@ -1472,17 +1484,18 @@
* get the state from entry to replace the default value.
* This is useful for slicing by particular dimensions. For example, if we wished
* to slice by uid and tag, we could write the following lambda:
- * (entry) -> {
- * return new NetworkStats.Entry(null, entry.getUid(),
- * NetworkStats.SET_ALL, entry.getTag(),
- * NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
- * NetworkStats.DEFAULT_NETWORK_ALL,
- * entry.getRxBytes(), entry.getRxPackets(),
- * entry.getTxBytes(), entry.getTxPackets(), 0);
- * }
+ * (entry) -> {
+ * return new NetworkStats.Entry(null, entry.getUid(),
+ * NetworkStats.SET_ALL, entry.getTag(),
+ * NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+ * NetworkStats.DEFAULT_NETWORK_ALL,
+ * entry.getRxBytes(), entry.getRxPackets(),
+ * entry.getTxBytes(), entry.getTxPackets(), 0);
+ * }
* @return new NeworkStats object appropriately sliced
*/
- @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
+ @NonNull
+ private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
@NonNull Function<NetworkStats.Entry, NetworkStats.Entry> slicer) {
NetworkStats ret = new NetworkStats(0, 1);
for (NetworkStats.Entry e : stats) {
@@ -1494,7 +1507,7 @@
private void registerWifiBytesTransferBackground() {
int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5, 6})
+ .setAdditiveFields(new int[]{3, 4, 5, 6})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1507,7 +1520,7 @@
private void registerMobileBytesTransfer() {
int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1520,7 +1533,7 @@
private void registerMobileBytesTransferBackground() {
int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5, 6})
+ .setAdditiveFields(new int[]{3, 4, 5, 6})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1533,7 +1546,7 @@
private void registerBytesTransferByTagAndMetered() {
int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 7})
+ .setAdditiveFields(new int[]{4, 5, 6, 7})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1546,7 +1559,7 @@
private void registerDataUsageBytesTransfer() {
int tagId = FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5})
+ .setAdditiveFields(new int[]{2, 3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1559,7 +1572,7 @@
private void registerOemManagedBytesTransfer() {
int tagId = FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {5, 6, 7, 8})
+ .setAdditiveFields(new int[]{5, 6, 7, 8})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1572,7 +1585,7 @@
private void registerBluetoothBytesTransfer() {
int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3})
+ .setAdditiveFields(new int[]{2, 3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1661,7 +1674,7 @@
if (KernelCpuBpfTracking.isSupported()) {
int tagId = FrameworkStatsLog.CPU_TIME_PER_CLUSTER_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1691,7 +1704,7 @@
private void registerCpuTimePerUid() {
int tagId = FrameworkStatsLog.CPU_TIME_PER_UID;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3})
+ .setAdditiveFields(new int[]{2, 3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1716,7 +1729,7 @@
if (KernelCpuBpfTracking.isSupported() || KernelCpuBpfTracking.getClusters() > 0) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_UID_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4, 5})
+ .setAdditiveFields(new int[]{3, 4, 5})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1801,7 +1814,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_TIME_PER_UID_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1855,7 +1868,7 @@
if (KernelCpuBpfTracking.isSupported()) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3, 4})
+ .setAdditiveFields(new int[]{3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1918,7 +1931,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_ACTIVE_TIME;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2})
+ .setAdditiveFields(new int[]{2})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -1940,7 +1953,7 @@
// frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
int tagId = FrameworkStatsLog.CPU_CLUSTER_TIME;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {3})
+ .setAdditiveFields(new int[]{3})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2127,7 +2140,7 @@
private void registerProcessMemoryState() {
int tagId = FrameworkStatsLog.PROCESS_MEMORY_STATE;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
+ .setAdditiveFields(new int[]{4, 5, 6, 7, 8})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2485,7 +2498,7 @@
private void registerBinderCallsStats() {
int tagId = FrameworkStatsLog.BINDER_CALLS;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
+ .setAdditiveFields(new int[]{4, 5, 6, 8, 12})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2547,7 +2560,7 @@
private void registerLooperStats() {
int tagId = FrameworkStatsLog.LOOPER_STATS;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {5, 6, 7, 8, 9})
+ .setAdditiveFields(new int[]{5, 6, 7, 8, 9})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -2922,7 +2935,7 @@
private void registerDiskIO() {
int tagId = FrameworkStatsLog.DISK_IO;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
+ .setAdditiveFields(new int[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
.setCoolDownMillis(3 * MILLIS_PER_SEC)
.build();
mStatsManager.setPullAtomCallback(
@@ -2994,7 +3007,7 @@
private void registerCpuTimePerThreadFreq() {
int tagId = FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
+ .setAdditiveFields(new int[]{7, 9, 11, 13, 15, 17, 19, 21})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3092,7 +3105,7 @@
private void registerDebugElapsedClock() {
int tagId = FrameworkStatsLog.DEBUG_ELAPSED_CLOCK;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {1, 2, 3, 4})
+ .setAdditiveFields(new int[]{1, 2, 3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3127,7 +3140,7 @@
private void registerDebugFailingElapsedClock() {
int tagId = FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
- .setAdditiveFields(new int[] {1, 2, 3, 4})
+ .setAdditiveFields(new int[]{1, 2, 3, 4})
.build();
mStatsManager.setPullAtomCallback(
tagId,
@@ -3559,23 +3572,23 @@
int userId = users.get(userNum).getUserHandle().getIdentifier();
int unlockKeyguardEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
int unlockDismissesKeyguard = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
int unlockAttentionRequired = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
int unlockAppEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
int unlockAlwaysRequireConfirmation = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
int unlockDiversityRequired = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
+ mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
unlockKeyguardEnabled != 0, unlockDismissesKeyguard != 0,
@@ -4481,7 +4494,7 @@
opacity));
}
}
- } catch (RuntimeException e) {
+ } catch (RuntimeException e) {
Slog.e(TAG, "pulling accessibility floating menu stats failed at getUsers", e);
return StatsManager.PULL_SKIP;
} finally {
@@ -4505,7 +4518,7 @@
byte[] sinkSurroundEncodings = toBytes(audioManager.getReportedSurroundFormats());
List<Integer> disabledSurroundEncodingsList = new ArrayList<>();
List<Integer> enabledSurroundEncodingsList = new ArrayList<>();
- for (int surroundEncoding: surroundEncodingsMap.keySet()) {
+ for (int surroundEncoding : surroundEncodingsMap.keySet()) {
if (!surroundEncodingsMap.get(surroundEncoding)) {
disabledSurroundEncodingsList.add(surroundEncoding);
} else {
@@ -4574,6 +4587,26 @@
return StatsManager.PULL_SUCCESS;
}
+ private void registerPendingIntentsPerPackagePuller() {
+ int tagId = FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE;
+ mStatsManager.setPullAtomCallback(
+ tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR,
+ mStatsCallbackImpl
+ );
+ }
+
+ private int pullPendingIntentsPerPackage(int atomTag, List<StatsEvent> pulledData) {
+ List<PendingIntentStats> pendingIntentStats =
+ LocalServices.getService(ActivityManagerInternal.class).getPendingIntentStats();
+ for (PendingIntentStats stats : pendingIntentStats) {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, stats.uid, stats.count, stats.sizeKb));
+ }
+ return StatsManager.PULL_SUCCESS;
+ }
+
private byte[] toBytes(List<Integer> audioEncodings) {
ProtoOutputStream protoOutputStream = new ProtoOutputStream();
for (int audioEncoding : audioEncodings) {
@@ -4655,8 +4688,8 @@
* string list.
*
* @param semicolonList colon-separated string, it should be
- * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
- * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
+ * {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
+ * {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
* @return The number of accessibility services
*/
private int countAccessibilityServices(String semicolonList) {
@@ -4778,5 +4811,4 @@
}
}
}
-
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e02fabd..b95d372 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -102,6 +102,8 @@
import com.android.server.IoThread;
import com.android.server.SystemService;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -2639,6 +2641,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
@SuppressWarnings("resource")
protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) {
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index a17e792..30e2617 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -146,7 +146,7 @@
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
- mContext.registerReceiver(this, filter, null, mHandler);
+ mContext.registerReceiver(this, filter, null, mHandler, Context.RECEIVER_NOT_EXPORTED);
mSubscriptionManager.addOnSubscriptionsChangedListener(
executor, mSubscriptionChangedListener);
mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 76e1c43..a4a200d 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -756,6 +756,19 @@
}
}
+ @Override
+ public void setPreferDockBigOverlays(IBinder token, boolean preferDockBigOverlays) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ r.setPreferDockBigOverlays(preferDockBigOverlays);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
/**
* Splash screen view is attached to activity.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dc53cc6..87ba859 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -348,6 +348,8 @@
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.utils.InsetUtils;
+import dalvik.annotation.optimization.NeverCompile;
+
import com.google.android.collect.Sets;
import org.xmlpull.v1.XmlPullParserException;
@@ -530,6 +532,7 @@
// activity can enter picture in picture while pausing (only when switching to another task)
PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build();
// The PiP params used when deferring the entering of picture-in-picture.
+ boolean preferDockBigOverlays;
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last launch of this activity
ComponentName requestedVrComponent; // the requested component for handling VR mode.
@@ -942,6 +945,7 @@
}
};
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
final long now = SystemClock.uptimeMillis();
@@ -1956,6 +1960,8 @@
mLetterboxUiController = new LetterboxUiController(mWmService, this);
mCameraCompatControlEnabled = mWmService.mContext.getResources()
.getBoolean(R.bool.config_isCameraCompatControlForStretchedIssuesEnabled);
+ preferDockBigOverlays = mWmService.mContext.getResources()
+ .getBoolean(R.bool.config_dockBigOverlayWindows);
if (_createTime > 0) {
createTime = _createTime;
@@ -9430,6 +9436,11 @@
getTask().getRootTask().onPictureInPictureParamsChanged();
}
+ void setPreferDockBigOverlays(boolean preferDockBigOverlays) {
+ this.preferDockBigOverlays = preferDockBigOverlays;
+ getTask().getRootTask().onPreferDockBigOverlaysChanged();
+ }
+
@Override
boolean isSyncFinished() {
if (!super.isSyncFinished()) return false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d99f07..1741d0f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1468,7 +1468,7 @@
a.packageName = process.mInfo.packageName;
a.applicationInfo = process.mInfo;
- a.processName = process.mInfo.processName;
+ a.processName = process.mName;
a.uiOptions = process.mInfo.uiOptions;
a.taskAffinity = "android:" + a.packageName + "/dream";
@@ -6099,7 +6099,8 @@
public boolean onForceStopPackage(String packageName, boolean doit, boolean evenPersistent,
int userId) {
synchronized (mGlobalLock) {
-
+ // In case if setWindowManager hasn't been called yet when booting.
+ if (mRootWindowContainer == null) return false;
return mRootWindowContainer.finishDisabledPackageActivities(packageName,
null /* filterByClasses */, doit, evenPersistent, userId,
// Only remove the activities without process because the activities with
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e26748c..9893f68 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -53,7 +53,11 @@
* Returns true if the back predictability feature is enabled
*/
static boolean isEnabled() {
- return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+ return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
+ }
+
+ static boolean isScreenshotEnabled() {
+ return false;
}
/**
@@ -101,6 +105,7 @@
synchronized (task.mWmService.mGlobalLock) {
activityRecord = task.topRunningActivity();
+
removedWindowContainer = activityRecord;
taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
WindowState window = task.getWindow(WindowState::isFocused);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e845034..2a06d8b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6441,6 +6441,8 @@
@Override
public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
+ // It is only needed when freezing display in legacy transition.
+ if (mTransitionController.isShellTransitionsEnabled()) return;
continueUpdateOrientationForDiffOrienLaunchingApp();
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f7c5b26..58cf4bb 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3397,6 +3397,7 @@
info.positionInParent = getRelativePosition();
info.pictureInPictureParams = getPictureInPictureParams(top);
+ info.preferDockBigOverlays = getPreferDockBigOverlays();
info.displayCutoutInsets = top != null ? top.getDisplayCutoutInsets() : null;
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
@@ -3443,6 +3444,11 @@
? null : new PictureInPictureParams(topMostActivity.pictureInPictureArgs);
}
+ private boolean getPreferDockBigOverlays() {
+ final ActivityRecord topMostActivity = getTopMostActivity();
+ return topMostActivity != null && topMostActivity.preferDockBigOverlays;
+ }
+
Rect getDisplayCutoutInsets() {
if (mDisplayContent == null || getDisplayInfo().displayCutout == null) return null;
final WindowState w = getTopVisibleAppMainWindow();
@@ -4336,6 +4342,10 @@
}
}
+ void onPreferDockBigOverlaysChanged() {
+ dispatchTaskInfoChangedIfNeeded(true /* force */);
+ }
+
/** Called when the top activity in the Root Task enters or exits size compat mode. */
void onSizeCompatActivityChanged() {
// Trigger TaskInfoChanged to update the size compat restart button.
diff --git a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
index d9dc9aa..c099628 100644
--- a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -19,51 +19,51 @@
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
import java.util.HashMap;
final class TaskFpsCallbackController {
private final Context mContext;
- private final HashMap<IOnFpsCallbackListener, Long> mTaskFpsCallbackListeners;
- private final HashMap<IOnFpsCallbackListener, IBinder.DeathRecipient> mDeathRecipients;
+ private final HashMap<ITaskFpsCallback, Long> mTaskFpsCallbacks;
+ private final HashMap<ITaskFpsCallback, IBinder.DeathRecipient> mDeathRecipients;
TaskFpsCallbackController(Context context) {
mContext = context;
- mTaskFpsCallbackListeners = new HashMap<>();
+ mTaskFpsCallbacks = new HashMap<>();
mDeathRecipients = new HashMap<>();
}
- void registerCallback(int taskId, IOnFpsCallbackListener listener) {
- if (mTaskFpsCallbackListeners.containsKey(listener)) {
+ void registerListener(int taskId, ITaskFpsCallback callback) {
+ if (mTaskFpsCallbacks.containsKey(callback)) {
return;
}
- final long nativeListener = nativeRegister(listener, taskId);
- mTaskFpsCallbackListeners.put(listener, nativeListener);
+ final long nativeListener = nativeRegister(callback, taskId);
+ mTaskFpsCallbacks.put(callback, nativeListener);
- final IBinder.DeathRecipient deathRecipient = () -> unregisterCallback(listener);
+ final IBinder.DeathRecipient deathRecipient = () -> unregisterListener(callback);
try {
- listener.asBinder().linkToDeath(deathRecipient, 0);
- mDeathRecipients.put(listener, deathRecipient);
+ callback.asBinder().linkToDeath(deathRecipient, 0);
+ mDeathRecipients.put(callback, deathRecipient);
} catch (RemoteException e) {
// ignore
}
}
- void unregisterCallback(IOnFpsCallbackListener listener) {
- if (!mTaskFpsCallbackListeners.containsKey(listener)) {
+ void unregisterListener(ITaskFpsCallback callback) {
+ if (!mTaskFpsCallbacks.containsKey(callback)) {
return;
}
- listener.asBinder().unlinkToDeath(mDeathRecipients.get(listener), 0);
- mDeathRecipients.remove(listener);
+ callback.asBinder().unlinkToDeath(mDeathRecipients.get(callback), 0);
+ mDeathRecipients.remove(callback);
- nativeUnregister(mTaskFpsCallbackListeners.get(listener));
- mTaskFpsCallbackListeners.remove(listener);
+ nativeUnregister(mTaskFpsCallbacks.get(callback));
+ mTaskFpsCallbacks.remove(callback);
}
- private static native long nativeRegister(IOnFpsCallbackListener listener, int taskId);
+ private static native long nativeRegister(ITaskFpsCallback callback, int taskId);
private static native void nativeUnregister(long ptr);
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index c880aba..dd1f29e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -876,11 +876,17 @@
if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
// The z-order of this TaskFragment is in middle of two adjacent TaskFragments
// and it cannot be visible if the TaskFragment on top is not translucent and
- // is fully occluding this one.
+ // is occluding this one.
+ mTmpRect.set(getBounds());
for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
final TaskFragment taskFragment = adjacentTaskFragments.get(j);
- if (!taskFragment.isTranslucent(starting)
- && taskFragment.getBounds().contains(this.getBounds())) {
+ final TaskFragment adjacentTaskFragment =
+ taskFragment.mAdjacentTaskFragment;
+ if (adjacentTaskFragment == this) {
+ continue;
+ }
+ if (mTmpRect.intersect(taskFragment.getBounds())
+ || mTmpRect.intersect(adjacentTaskFragment.getBounds())) {
return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
}
}
@@ -1695,7 +1701,7 @@
if (isAddingActivity && task != null) {
// TODO(b/207481538): temporary per-activity screenshoting
- if (r != null && BackNavigationController.isEnabled()) {
+ if (r != null && BackNavigationController.isScreenshotEnabled()) {
ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
r.mActivityComponent.flattenToString());
Rect outBounds = r.getBounds();
@@ -2298,7 +2304,7 @@
void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
super.removeChild(child);
- if (BackNavigationController.isEnabled()) {
+ if (BackNavigationController.isScreenshotEnabled()) {
//TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
// implemented
ActivityRecord r = child.asActivityRecord();
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 9f2188b..cbef60c 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -550,10 +550,10 @@
throw new IllegalStateException("Too late to abort.");
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Aborting Transition: %d", mSyncId);
- mController.dispatchLegacyAppTransitionCancelled();
mState = STATE_ABORT;
// Syncengine abort will call through to onTransactionReady()
mSyncEngine.abort(mSyncId);
+ mController.dispatchLegacyAppTransitionCancelled();
}
void setRemoteTransition(RemoteTransition remoteTransition) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index af12c0b..4ff2b6a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -281,7 +281,7 @@
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import android.window.ClientWindowFrames;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
import android.window.TaskSnapshot;
import com.android.internal.R;
@@ -310,6 +310,8 @@
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
@@ -419,7 +421,7 @@
"persist.wm.enable_remote_keyguard_animation";
private static final int sEnableRemoteKeyguardAnimation =
- SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 2);
+ SystemProperties.getInt(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, 1);
/**
* @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
@@ -6617,6 +6619,7 @@
PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
+ @NeverCompile // Avoid size overhead of debugging code.
private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
boolean dumpAll = false;
@@ -8870,7 +8873,7 @@
@Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
- IOnFpsCallbackListener listener) {
+ ITaskFpsCallback callback) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
!= PackageManager.PERMISSION_GRANTED) {
final int pid = Binder.getCallingPid();
@@ -8882,12 +8885,12 @@
throw new IllegalArgumentException("no task with taskId: " + taskId);
}
- mTaskFpsCallbackController.registerCallback(taskId, listener);
+ mTaskFpsCallbackController.registerListener(taskId, callback);
}
@Override
@RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
- public void unregisterTaskFpsCallback(IOnFpsCallbackListener listener) {
+ public void unregisterTaskFpsCallback(ITaskFpsCallback callback) {
if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
!= PackageManager.PERMISSION_GRANTED) {
final int pid = Binder.getCallingPid();
@@ -8895,7 +8898,7 @@
+ ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
}
- mTaskFpsCallbackController.unregisterCallback(listener);
+ mTaskFpsCallbackController.unregisterListener(callback);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e84a747..49f742c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -257,6 +257,8 @@
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.SurfaceAnimator.AnimationType;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -4178,6 +4180,7 @@
proto.end(token);
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
pw.print(prefix + "mDisplayId=" + getDisplayId());
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index f398034..ccaa03a 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -615,6 +616,12 @@
getResolvedOverrideConfiguration().updateFrom(
mFixedRotationTransformState.mRotatedOverrideConfiguration);
}
+ if (getTaskDisplayArea() == null) {
+ // We only defined behaviors of system windows in fullscreen mode, i.e. windows not
+ // contained in a task display area.
+ getResolvedOverrideConfiguration().windowConfiguration.setWindowingMode(
+ WINDOWING_MODE_FULLSCREEN);
+ }
}
@Override
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 94bc22a..636ca41 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -57,6 +57,19 @@
#define ASYNC_RECEIVED_WHILE_FROZEN (2)
#define TXNS_PENDING_WHILE_FROZEN (4)
+#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)
+
+// Defines the maximum amount of VMAs we can send per process_madvise syscall.
+// Currently this is set to UIO_MAXIOV which is the maximum segments allowed by
+// iovec implementation used by process_madvise syscall
+#define MAX_VMAS_PER_COMPACTION UIO_MAXIOV
+
+// Maximum bytes that we can send per process_madvise syscall once this limit
+// is reached we split the remaining VMAs into another syscall. The MAX_RW_COUNT
+// limit is imposed by iovec implementation. However, if you want to use a smaller
+// limit, it has to be a page aligned value, otherwise, compaction would fail.
+#define MAX_BYTES_PER_COMPACTION MAX_RW_COUNT
+
namespace android {
static bool cancelRunningCompaction;
@@ -70,12 +83,12 @@
}
// Compacts a set of VMAs for pid using an madviseType accepted by process_madvise syscall
-// On success returns the total bytes that where compacted. On failure it returns
-// a negative error code from the standard linux error codes.
+// Returns the total bytes that where madvised.
+//
+// If any VMA fails compaction due to -EINVAL it will be skipped and continue.
+// However, if it fails for any other reason, it will bail out and forward the error
static int64_t compactMemory(const std::vector<Vma>& vmas, int pid, int madviseType) {
- // UIO_MAXIOV is currently a small value and we might have more addresses
- // we do multiple syscalls if we exceed its maximum
- static struct iovec vmasToKernel[UIO_MAXIOV];
+ static struct iovec vmasToKernel[MAX_VMAS_PER_COMPACTION];
if (vmas.empty()) {
return 0;
@@ -89,33 +102,72 @@
compactionInProgress = true;
cancelRunningCompaction = false;
- int64_t totalBytesCompacted = 0;
- for (int iBase = 0; iBase < vmas.size(); iBase += UIO_MAXIOV) {
- if (CC_UNLIKELY(cancelRunningCompaction)) {
- // There could be a significant delay betweenwhen a compaction
- // is requested and when it is handled during this time
- // our OOM adjust could have improved.
+ int64_t totalBytesProcessed = 0;
+
+ int64_t vmaOffset = 0;
+ for (int iVma = 0; iVma < vmas.size();) {
+ uint64_t bytesSentToCompact = 0;
+ int iVec = 0;
+ while (iVec < MAX_VMAS_PER_COMPACTION && iVma < vmas.size()) {
+ if (CC_UNLIKELY(cancelRunningCompaction)) {
+ // There could be a significant delay between when a compaction
+ // is requested and when it is handled during this time our
+ // OOM adjust could have improved.
+ LOG(DEBUG) << "Cancelled running compaction for " << pid;
+ break;
+ }
+
+ uint64_t vmaStart = vmas[iVma].start + vmaOffset;
+ uint64_t vmaSize = vmas[iVma].end - vmaStart;
+ if (vmaSize == 0) {
+ goto next_vma;
+ }
+ vmasToKernel[iVec].iov_base = (void*)vmaStart;
+ if (vmaSize > MAX_BYTES_PER_COMPACTION - bytesSentToCompact) {
+ // Exceeded the max bytes that could be sent, so clamp
+ // the end to avoid exceeding limit and issue compaction
+ vmaSize = MAX_BYTES_PER_COMPACTION - bytesSentToCompact;
+ }
+
+ vmasToKernel[iVec].iov_len = vmaSize;
+ bytesSentToCompact += vmaSize;
+ ++iVec;
+ if (bytesSentToCompact >= MAX_BYTES_PER_COMPACTION) {
+ // Ran out of bytes within iovec, dispatch compaction.
+ vmaOffset += vmaSize;
+ break;
+ }
+
+ next_vma:
+ // Finished current VMA, and have more bytes remaining
+ vmaOffset = 0;
+ ++iVma;
+ }
+
+ if (cancelRunningCompaction) {
cancelRunningCompaction = false;
break;
}
- int totalVmasToKernel = std::min(UIO_MAXIOV, (int)(vmas.size() - iBase));
- for (int iVec = 0, iVma = iBase; iVec < totalVmasToKernel; ++iVec, ++iVma) {
- vmasToKernel[iVec].iov_base = (void*)vmas[iVma].start;
- vmasToKernel[iVec].iov_len = vmas[iVma].end - vmas[iVma].start;
+
+ auto bytesProcessed = process_madvise(pidfd, vmasToKernel, iVec, madviseType, 0);
+
+ if (CC_UNLIKELY(bytesProcessed == -1)) {
+ if (errno == EINVAL) {
+ // This error is somewhat common due to an unevictable VMA if this is
+ // the case silently skip the bad VMA and continue compacting the rest.
+ continue;
+ } else {
+ // Forward irrecoverable errors and bail out compaction
+ compactionInProgress = false;
+ return -errno;
+ }
}
- auto bytesCompacted =
- process_madvise(pidfd, vmasToKernel, totalVmasToKernel, madviseType, 0);
- if (CC_UNLIKELY(bytesCompacted == -1)) {
- compactionInProgress = false;
- return -errno;
- }
-
- totalBytesCompacted += bytesCompacted;
+ totalBytesProcessed += bytesProcessed;
}
compactionInProgress = false;
- return totalBytesCompacted;
+ return totalBytesProcessed;
}
static int getFilePageAdvice(const Vma& vma) {
@@ -138,7 +190,12 @@
}
// Perform a full process compaction using process_madvise syscall
-// reading all filtering VMAs and filtering pages as specified by pageFilter
+// using the madvise behavior defined by vmaToAdviseFunc per VMA.
+//
+// Currently supported behaviors are MADV_COLD and MADV_PAGEOUT.
+//
+// Returns the total number of bytes compacted or forwards an
+// process_madvise error.
static int64_t compactProcess(int pid, VmaToAdviseFunc vmaToAdviseFunc) {
ProcMemInfo meminfo(pid);
std::vector<Vma> pageoutVmas, coldVmas;
diff --git a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
index 0202306..0a60e0d 100644
--- a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
+++ b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
@@ -99,7 +99,7 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"nativeRegister", "(Landroid/window/IOnFpsCallbackListener;I)J", (void*)nativeRegister},
+ {"nativeRegister", "(Landroid/window/ITaskFpsCallback;I)J", (void*)nativeRegister},
{"nativeUnregister", "(J)V", (void*)nativeUnregister}};
} // namespace
@@ -113,7 +113,7 @@
gCallbackClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
gCallbackClassInfo.mDispatchOnFpsReported =
env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
- "(Landroid/window/IOnFpsCallbackListener;F)V");
+ "(Landroid/window/ITaskFpsCallback;F)V");
return 0;
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index be0ddc1..5b4febd 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -170,14 +170,6 @@
</xs:restriction>
</xs:simpleType>
- <!-- Maps to DisplayDeviceConfig.INTERPOLATION_* values. -->
- <xs:simpleType name="interpolation">
- <xs:restriction base="xs:string">
- <xs:enumeration value="default"/>
- <xs:enumeration value="linear"/>
- </xs:restriction>
- </xs:simpleType>
-
<xs:complexType name="thermalThrottling">
<xs:complexType>
<xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap">
@@ -216,7 +208,8 @@
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
- <xs:attribute name="interpolation" type="interpolation" use="optional"/>
+ <!-- valid value of interpolation if specified: linear -->
+ <xs:attribute name="interpolation" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="point">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 2890d68..ba83c9f 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -108,17 +108,11 @@
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
- public enum Interpolation {
- method public String getRawName();
- enum_constant public static final com.android.server.display.config.Interpolation _default;
- enum_constant public static final com.android.server.display.config.Interpolation linear;
- }
-
public class NitsMap {
ctor public NitsMap();
- method public com.android.server.display.config.Interpolation getInterpolation();
+ method public String getInterpolation();
method @NonNull public final java.util.List<com.android.server.display.config.Point> getPoint();
- method public void setInterpolation(com.android.server.display.config.Interpolation);
+ method public void setInterpolation(String);
}
public class Point {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5c3721d..2e801ab 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -417,6 +417,8 @@
private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
private static final String SAFETY_CENTER_SERVICE_CLASS =
"com.android.safetycenter.SafetyCenterService";
+ private static final String BLUETOOTH_SERVICE_CLASS =
+ "com.android.server.bluetooth.BluetoothService";
private static final String SUPPLEMENTALPROCESS_SERVICE_CLASS =
"com.android.server.supplementalprocess.SupplementalProcessManagerService$Lifecycle";
@@ -1624,7 +1626,7 @@
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else {
t.traceBegin("StartBluetoothService");
- mSystemServiceManager.startService(BluetoothService.class);
+ mSystemServiceManager.startService(BLUETOOTH_SERVICE_CLASS);
t.traceEnd();
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 11300ce..cd2d0fc 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -509,7 +509,12 @@
ParsingPackage::setInheritKeyStoreKeys,
true
),
- getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
+ getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
+ getSetByValue(
+ AndroidPackage::isOnBackInvokedCallbackEnabled,
+ ParsingPackage::setOnBackInvokedCallbackEnabled,
+ true
+ )
)
override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index 936940f..e6bb0ce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -2648,6 +2648,11 @@
AppPermissionTracker getAppPermissionTracker() {
return mAppPermissionTracker;
}
+
+ @Override
+ void scheduleInitTrackers(Handler handler, Runnable initializers) {
+ initializers.run();
+ }
}
private class TestBaseTrackerInjector<T extends BaseAppStatePolicy>
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index 877538c..782d519 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -20,7 +20,12 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -42,6 +47,7 @@
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
@@ -51,6 +57,7 @@
@SmallTest
@Presubmit
public class AnrHelperTest {
+ private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
private AnrHelper mAnrHelper;
private ProcessRecord mAnrApp;
@@ -106,8 +113,42 @@
mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation);
- verify(mAnrApp.mErrorState, timeout(TimeUnit.SECONDS.toMillis(5))).appNotResponding(
+ verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
eq(parentProcess), eq(aboveSystem), eq(annotation), eq(false) /* onlyDumpSelf */);
}
+
+ @Test
+ public void testSkipDuplicatedAnr() {
+ final CountDownLatch consumerLatch = new CountDownLatch(1);
+ final CountDownLatch processingLatch = new CountDownLatch(1);
+ doAnswer(invocation -> {
+ consumerLatch.countDown();
+ // Simulate that it is dumping to block the consumer thread.
+ processingLatch.await();
+ return null;
+ }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
+ anyBoolean(), anyString(), anyBoolean());
+ final ApplicationInfo appInfo = new ApplicationInfo();
+ mAnrApp.mPid = 12345;
+ final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
+ "activityShortComponentName", appInfo, "parentShortComponentName",
+ null /* parentProcess */, false /* aboveSystem */, "annotation");
+ reportAnr.run();
+ // This should be skipped because the pid is pending in queue.
+ reportAnr.run();
+ // The first reported ANR must be processed.
+ try {
+ assertTrue(consumerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException ignored) {
+ }
+ // This should be skipped because the pid is under processing.
+ reportAnr.run();
+
+ // Assume that the first one finishes after all incoming ANRs.
+ processingLatch.countDown();
+ // There is only one ANR reported.
+ verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
+ anyString(), any(), any(), any(), anyBoolean(), anyString(), anyBoolean());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index bdf94f3..356600d 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -33,6 +33,7 @@
import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
import android.database.ContentObserver;
+import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.display.AmbientBrightnessDayStats;
@@ -42,6 +43,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.hardware.input.InputSensorInfo;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.HandlerThread;
@@ -63,6 +65,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -84,8 +88,11 @@
private static final String DEFAULT_DISPLAY_ID = "123";
private static final float FLOAT_DELTA = 0.01f;
+ @Mock private InputSensorInfo mInputSensorInfoMock;
+
private BrightnessTracker mTracker;
private TestInjector mInjector;
+ private Sensor mLightSensorFake;
private static Object sHandlerLock = new Object();
private static Handler sHandler;
@@ -108,9 +115,12 @@
@Before
public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
mInjector = new TestInjector(ensureHandler());
+ mLightSensorFake = new Sensor(mInputSensorInfoMock);
mTracker = new BrightnessTracker(InstrumentationRegistry.getContext(), mInjector);
+ mTracker.setLightSensor(mLightSensorFake);
mDefaultNightModeColorTemperature =
InstrumentationRegistry.getContext().getResources().getInteger(
R.integer.config_nightDisplayColorTemperatureDefault);
@@ -834,6 +844,47 @@
mTracker.stop();
}
+ @Test
+ public void testLightSensorChange() {
+ // verify the tracker started correctly and a listener registered
+ startTracker(mTracker);
+ assertNotNull(mInjector.mSensorListener);
+ assertEquals(mInjector.mLightSensor, mLightSensorFake);
+
+ // Setting the sensor to null should stop the registered listener.
+ mTracker.setLightSensor(null);
+ mInjector.waitForHandler();
+ assertNull(mInjector.mSensorListener);
+ assertNull(mInjector.mLightSensor);
+
+ // Resetting sensor should start listener again
+ mTracker.setLightSensor(mLightSensorFake);
+ mInjector.waitForHandler();
+ assertNotNull(mInjector.mSensorListener);
+ assertEquals(mInjector.mLightSensor, mLightSensorFake);
+
+ Sensor secondSensor = new Sensor(mInputSensorInfoMock);
+ // Setting a different listener should keep things working
+ mTracker.setLightSensor(secondSensor);
+ mInjector.waitForHandler();
+ assertNotNull(mInjector.mSensorListener);
+ assertEquals(mInjector.mLightSensor, secondSensor);
+ }
+
+ @Test
+ public void testSetLightSensorDoesntStartListener() {
+ mTracker.setLightSensor(mLightSensorFake);
+ assertNull(mInjector.mSensorListener);
+ }
+
+ @Test
+ public void testNullLightSensorWontRegister() {
+ mTracker.setLightSensor(null);
+ startTracker(mTracker);
+ assertNull(mInjector.mSensorListener);
+ assertNull(mInjector.mLightSensor);
+ }
+
private InputStream getInputStream(String data) {
return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
}
@@ -924,6 +975,7 @@
private class TestInjector extends BrightnessTracker.Injector {
SensorEventListener mSensorListener;
+ Sensor mLightSensor;
BroadcastReceiver mBroadcastReceiver;
DisplayManager.DisplayListener mDisplayListener;
Map<String, Integer> mSecureIntSettings = new HashMap<>();
@@ -974,14 +1026,16 @@
@Override
public void registerSensorListener(Context context,
- SensorEventListener sensorListener, Handler handler) {
+ SensorEventListener sensorListener, Sensor lightSensor, Handler handler) {
mSensorListener = sensorListener;
+ mLightSensor = lightSensor;
}
@Override
public void unregisterSensorListener(Context context,
SensorEventListener sensorListener) {
mSensorListener = null;
+ mLightSensor = null;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 2f5993d1..5d3da43 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -132,7 +132,12 @@
@Test
public void testGetApexSystemServices() throws RemoteException {
- when(mApexService.getAllPackages()).thenReturn(createApexInfoForTestPkg(true, false));
+ when(mApexService.getAllPackages()).thenReturn(new ApexInfo[] {
+ createApexInfoForTestPkg(false, true, 1),
+ // only active apex reports apex-system-service
+ createApexInfoForTestPkg(true, false, 2),
+ });
+
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
@@ -484,17 +489,20 @@
assertThat(e).hasMessageThat().contains("Failed to collect certificates from ");
}
- private ApexInfo[] createApexInfoForTestPkg(boolean isActive, boolean isFactory) {
+ private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
ApexInfo apexInfo = new ApexInfo();
apexInfo.isActive = isActive;
apexInfo.isFactory = isFactory;
apexInfo.moduleName = TEST_APEX_PKG;
apexInfo.modulePath = apexFile.getPath();
- apexInfo.versionCode = 191000070;
+ apexInfo.versionCode = version;
apexInfo.preinstalledModulePath = apexFile.getPath();
+ return apexInfo;
+ }
- return new ApexInfo[]{apexInfo};
+ private ApexInfo[] createApexInfoForTestPkg(boolean isActive, boolean isFactory) {
+ return new ApexInfo[]{createApexInfoForTestPkg(isActive, isFactory, 191000070)};
}
private ApexInfo createApexInfo(String moduleName, int versionCode, boolean isActive,
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index c94168c..ed7aac7 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -1058,6 +1058,23 @@
assertThat(mService.getGlobalWakefulnessLocked()).isNotEqualTo(WAKEFULNESS_ASLEEP);
}
+
+ @SuppressWarnings("GuardedBy")
+ @Test
+ public void testInattentiveSleep_goesToSleepFromDream() throws Exception {
+ setAttentiveTimeout(20000);
+ createService();
+ startSystem();
+ setPluggedIn(true);
+ forceAwake();
+ forceDream();
+ when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+
+ advanceTime(20500);
+ assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
+ }
+
@Test
public void testWakeLock_affectsProperDisplayGroup() {
final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index a12bc3b..de81d6b 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -28,6 +28,8 @@
import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
+import static com.android.server.UiModeManagerService.SUPPORTED_NIGHT_MODE_CUSTOM_TYPES;
+
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.TestCase.assertFalse;
@@ -295,6 +297,24 @@
}
@Test
+ public void setNightModeCustomType_customTypeUnknown_shouldThrow() throws RemoteException {
+ assertThrows(IllegalArgumentException.class,
+ () -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN));
+ }
+
+ @Test
+ public void setNightModeCustomType_customTypeUnsupported_shouldThrow() throws RemoteException {
+ assertThrows(IllegalArgumentException.class,
+ () -> {
+ int maxSupportedCustomType = 0;
+ for (Integer supportedType : SUPPORTED_NIGHT_MODE_CUSTOM_TYPES) {
+ maxSupportedCustomType = Math.max(maxSupportedCustomType, supportedType);
+ }
+ mService.setNightModeCustomType(maxSupportedCustomType + 1);
+ });
+ }
+
+ @Test
public void setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()
throws RemoteException {
try {
@@ -777,7 +797,6 @@
}
-
@Test
public void customTime_darkThemeOn_beforeStartEnd() throws RemoteException {
LocalTime now = LocalTime.now();
@@ -1220,6 +1239,35 @@
verify(listener, never()).onProjectionStateChanged(anyInt(), any());
}
+ @Test
+ public void enableCarMode_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class, () -> mService.enableCarMode(0, 0, PACKAGE_NAME));
+ assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ }
+
+ @Test
+ public void disableCarMode_failsForBogusPackageName() throws Exception {
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
+ mService.enableCarMode(0, 0, PACKAGE_NAME);
+ assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID + 1);
+
+ assertThrows(SecurityException.class,
+ () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME));
+ assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+
+ // Clean up
+ when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(TestInjector.CALLING_UID);
+ mService.disableCarModeByCallingPackage(0, PACKAGE_NAME);
+ assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+ }
+
private void requestAllPossibleProjectionTypes() throws RemoteException {
for (int i = 0; i < Integer.SIZE; ++i) {
mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 1126e1e..4b6183d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -15,16 +15,22 @@
*/
package com.android.server.notification;
+import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_CURRENT;
+import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
import android.app.Notification;
import android.os.UserHandle;
+import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -35,6 +41,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -51,6 +58,8 @@
private static final int SIZE = 5;
private NotificationManagerService.Archive mArchive;
+ @Mock
+ private UserManager mUm;
@Before
public void setUp() {
@@ -59,6 +68,9 @@
mArchive = new NotificationManagerService.Archive(SIZE);
mArchive.updateHistoryEnabled(USER_SYSTEM, true);
mArchive.updateHistoryEnabled(USER_CURRENT, true);
+
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(
+ new int[] {USER_CURRENT, USER_SYSTEM});
}
private StatusBarNotification getNotification(String pkg, int id, UserHandle user) {
@@ -70,7 +82,6 @@
pkg, pkg, id, null, 0, 0, n, user, null, System.currentTimeMillis());
}
-
@Test
public void testRecordAndRead() {
List<String> expected = new ArrayList<>();
@@ -81,7 +92,7 @@
mArchive.record(sbn, REASON_CANCEL);
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -89,6 +100,22 @@
}
@Test
+ public void testCrossUser() {
+ mArchive.record(getNotification("pkg", 1, UserHandle.of(USER_SYSTEM)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 2, UserHandle.of(USER_CURRENT)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 3, UserHandle.of(USER_ALL)), REASON_CANCEL);
+ mArchive.record(getNotification("pkg", 4, UserHandle.of(USER_NULL)), REASON_CANCEL);
+
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
+ assertThat(actual).hasSize(3);
+ for (StatusBarNotification sbn : actual) {
+ if (sbn.getUserId() == USER_NULL) {
+ fail("leaked notification from wrong user");
+ }
+ }
+ }
+
+ @Test
public void testRecordAndRead_overLimit() {
List<String> expected = new ArrayList<>();
for (int i = 0; i < (SIZE * 2); i++) {
@@ -99,7 +126,8 @@
}
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray((SIZE * 2), true));
+ List<StatusBarNotification> actual = Arrays.asList(
+ mArchive.getArray(mUm, (SIZE * 2), true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -119,7 +147,7 @@
}
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -140,7 +168,7 @@
}
mArchive.updateHistoryEnabled(USER_CURRENT, false);
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -165,7 +193,7 @@
}
mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0");
mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2));
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
@@ -215,7 +243,7 @@
fail("Concurrent modification exception");
}
- List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+ List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
assertThat(actual).hasSize(expected.size());
for (StatusBarNotification sbn : actual) {
assertThat(expected).contains(sbn.getKey());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index dfcab2b..018a916 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -430,6 +430,7 @@
when(mPermissionPolicyInternal.canShowPermissionPromptForTask(
any(ActivityManager.RecentTaskInfo.class))).thenReturn(false);
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
List<ActivityManager.AppTask> taskList = new ArrayList<>();
@@ -7643,8 +7644,9 @@
waitForIdle();
// A notification exists for the given record
- StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
- assertEquals(1, notifsBefore.length);
+ List<StatusBarNotification> notifsBefore =
+ mBinderService.getAppActiveNotifications(PKG, nr.getSbn().getUserId()).getList();
+ assertEquals(1, notifsBefore.size());
reset(mPackageManager);
@@ -9131,4 +9133,33 @@
// make sure we don't bother if the migration is not enabled
assertThat(mService.getAllUsersNotificationPermissions()).isNull();
}
+
+ @Test
+ public void testGetActiveNotification_filtersUsers() throws Exception {
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0, 10});
+
+ NotificationRecord nr0 =
+ generateNotificationRecord(mTestNotificationChannel, 0);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+ nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
+
+ NotificationRecord nr10 =
+ generateNotificationRecord(mTestNotificationChannel, 10);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag10",
+ nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
+
+ NotificationRecord nr11 =
+ generateNotificationRecord(mTestNotificationChannel, 11);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag11",
+ nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
+ waitForIdle();
+
+ StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+ assertEquals(2, notifs.length);
+ for (StatusBarNotification sbn : notifs) {
+ if (sbn.getUserId() == 11) {
+ fail("leaked data across users");
+ }
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index d922f40..5a6ca6d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -293,6 +293,7 @@
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
+ when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
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 3d89805..c21a5b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.window.BackNavigationInfo.typeToString;
@@ -117,6 +118,9 @@
private Task createTopTaskWithActivity() {
Task task = createTask(mDefaultDisplay);
ActivityRecord record = createActivityRecord(task);
+ // enable OnBackInvokedCallbacks
+ record.info.applicationInfo.privateFlagsExt |=
+ PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
when(record.mSurfaceControl.isValid()).thenReturn(true);
mAtm.setFocusedTask(task.mTaskId, record);
diff --git a/services/translation/OWNERS b/services/translation/OWNERS
index a1e663a..440f9a8 100644
--- a/services/translation/OWNERS
+++ b/services/translation/OWNERS
@@ -1,8 +1,3 @@
# Bug component: 994311
-adamhe@google.com
-augale@google.com
-joannechung@google.com
-lpeter@google.com
-svetoslavganov@google.com
-tymtsai@google.com
+include /core/java/android/view/translation/OWNERS
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 9f4fee8..364d592 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -43,6 +44,7 @@
import android.view.translation.TranslationCapability;
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationController;
import android.view.translation.UiTranslationManager.UiTranslationState;
import android.view.translation.UiTranslationSpec;
@@ -253,7 +255,10 @@
try (TransferPipe tp = new TransferPipe()) {
activityTokens.getApplicationThread().dumpActivity(tp.getWriteFd(),
activityTokens.getActivityToken(), prefix,
- new String[]{"--translation"});
+ new String[] {
+ Activity.DUMP_ARG_DUMP_DUMPABLE,
+ UiTranslationController.DUMPABLE_NAME
+ });
tp.go(fd);
} catch (IOException e) {
pw.println(prefix + "Failure while dumping the activity: " + e);
diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
index 27e8d69..ab8f69b 100644
--- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
+++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java
@@ -22,6 +22,7 @@
import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -39,6 +40,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
class BroadcastResponseStatsTracker {
private static final String TAG = "ResponseStatsTracker";
@@ -172,28 +175,27 @@
}
}
- @NonNull BroadcastResponseStats queryBroadcastResponseStats(int callingUid,
- @NonNull String packageName, long id, @UserIdInt int userId) {
- final BroadcastResponseStats aggregatedResponseStats =
- new BroadcastResponseStats(packageName);
+ @NonNull List<BroadcastResponseStats> queryBroadcastResponseStats(int callingUid,
+ @Nullable String packageName, @IntRange(from = 0) long id, @UserIdInt int userId) {
+ final List<BroadcastResponseStats> broadcastResponseStatsList = new ArrayList<>();
synchronized (mLock) {
final SparseArray<UserBroadcastResponseStats> responseStatsForCaller =
mUserResponseStats.get(callingUid);
if (responseStatsForCaller == null) {
- return aggregatedResponseStats;
+ return broadcastResponseStatsList;
}
final UserBroadcastResponseStats responseStatsForUser =
responseStatsForCaller.get(userId);
if (responseStatsForUser == null) {
- return aggregatedResponseStats;
+ return broadcastResponseStatsList;
}
- responseStatsForUser.aggregateBroadcastResponseStats(aggregatedResponseStats,
- packageName, id);
+ responseStatsForUser.populateAllBroadcastResponseStats(
+ broadcastResponseStatsList, packageName, id);
}
- return aggregatedResponseStats;
+ return broadcastResponseStatsList;
}
- void clearBroadcastResponseStats(int callingUid, @NonNull String packageName, long id,
+ void clearBroadcastResponseStats(int callingUid, @Nullable String packageName, long id,
@UserIdInt int userId) {
synchronized (mLock) {
final SparseArray<UserBroadcastResponseStats> responseStatsForCaller =
@@ -210,6 +212,16 @@
}
}
+ void clearBroadcastEvents(int callingUid, @UserIdInt int userId) {
+ synchronized (mLock) {
+ final UserBroadcastEvents userBroadcastEvents = mUserBroadcastEvents.get(userId);
+ if (userBroadcastEvents == null) {
+ return;
+ }
+ userBroadcastEvents.clear(callingUid);
+ }
+ }
+
void onUserRemoved(@UserIdInt int userId) {
synchronized (mLock) {
mUserBroadcastEvents.remove(userId);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4a761a7..06aa8f0 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -49,7 +49,7 @@
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.AppLaunchEstimateInfo;
import android.app.usage.AppStandbyInfo;
-import android.app.usage.BroadcastResponseStats;
+import android.app.usage.BroadcastResponseStatsList;
import android.app.usage.ConfigurationStats;
import android.app.usage.EventStats;
import android.app.usage.IUsageStatsManager;
@@ -2686,16 +2686,15 @@
@Override
@NonNull
- public BroadcastResponseStats queryBroadcastResponseStats(
- @NonNull String packageName,
- @IntRange(from = 1) long id,
+ public BroadcastResponseStatsList queryBroadcastResponseStats(
+ @Nullable String packageName,
+ @IntRange(from = 0) long id,
@NonNull String callingPackage,
@UserIdInt int userId) {
- Objects.requireNonNull(packageName);
Objects.requireNonNull(callingPackage);
// TODO: Move to Preconditions utility class
- if (id <= 0) {
- throw new IllegalArgumentException("id needs to be >0");
+ if (id < 0) {
+ throw new IllegalArgumentException("id needs to be >=0");
}
final int callingUid = Binder.getCallingUid();
@@ -2708,8 +2707,9 @@
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, false /* allowAll */, false /* requireFull */,
"queryBroadcastResponseStats" /* name */, callingPackage);
- return mResponseStatsTracker.queryBroadcastResponseStats(
- callingUid, packageName, id, userId);
+ return new BroadcastResponseStatsList(
+ mResponseStatsTracker.queryBroadcastResponseStats(
+ callingUid, packageName, id, userId));
}
@Override
@@ -2718,10 +2718,9 @@
@IntRange(from = 1) long id,
@NonNull String callingPackage,
@UserIdInt int userId) {
- Objects.requireNonNull(packageName);
Objects.requireNonNull(callingPackage);
- if (id <= 0) {
- throw new IllegalArgumentException("id needs to be >0");
+ if (id < 0) {
+ throw new IllegalArgumentException("id needs to be >=0");
}
final int callingUid = Binder.getCallingUid();
@@ -2737,6 +2736,23 @@
mResponseStatsTracker.clearBroadcastResponseStats(callingUid,
packageName, id, userId);
}
+
+ @Override
+ public void clearBroadcastEvents(@NonNull String callingPackage, @UserIdInt int userId) {
+ Objects.requireNonNull(callingPackage);
+
+ final int callingUid = Binder.getCallingUid();
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException(
+ "Caller does not have the permission needed to call this API; "
+ + "callingPackage=" + callingPackage
+ + ", callingUid=" + callingUid);
+ }
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid,
+ userId, false /* allowAll */, false /* requireFull */,
+ "clearBroadcastResponseStats" /* name */, callingPackage);
+ mResponseStatsTracker.clearBroadcastEvents(callingUid, userId);
+ }
}
void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
diff --git a/services/usage/java/com/android/server/usage/UserBroadcastEvents.java b/services/usage/java/com/android/server/usage/UserBroadcastEvents.java
index 819644846..0ec59c3 100644
--- a/services/usage/java/com/android/server/usage/UserBroadcastEvents.java
+++ b/services/usage/java/com/android/server/usage/UserBroadcastEvents.java
@@ -51,6 +51,10 @@
}
void onUidRemoved(int uid) {
+ clear(uid);
+ }
+
+ void clear(int uid) {
for (int i = mBroadcastEvents.size() - 1; i >= 0; --i) {
final LongSparseArray<BroadcastEvent> broadcastEvents = mBroadcastEvents.valueAt(i);
for (int j = broadcastEvents.size() - 1; j >= 0; --j) {
diff --git a/services/usage/java/com/android/server/usage/UserBroadcastResponseStats.java b/services/usage/java/com/android/server/usage/UserBroadcastResponseStats.java
index ac2a320..1828a71 100644
--- a/services/usage/java/com/android/server/usage/UserBroadcastResponseStats.java
+++ b/services/usage/java/com/android/server/usage/UserBroadcastResponseStats.java
@@ -16,6 +16,7 @@
package com.android.server.usage;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.usage.BroadcastResponseStats;
@@ -23,6 +24,8 @@
import com.android.internal.util.IndentingPrintWriter;
+import java.util.List;
+
class UserBroadcastResponseStats {
/**
* Contains the mapping of a BroadcastEvent type to it's aggregated stats.
@@ -39,31 +42,38 @@
BroadcastEvent broadcastEvent) {
BroadcastResponseStats responseStats = mResponseStats.get(broadcastEvent);
if (responseStats == null) {
- responseStats = new BroadcastResponseStats(broadcastEvent.getTargetPackage());
+ responseStats = new BroadcastResponseStats(broadcastEvent.getTargetPackage(),
+ broadcastEvent.getIdForResponseEvent());
mResponseStats.put(broadcastEvent, responseStats);
}
return responseStats;
}
- void aggregateBroadcastResponseStats(
- @NonNull BroadcastResponseStats responseStats,
- @NonNull String packageName, long id) {
+ void populateAllBroadcastResponseStats(
+ @NonNull List<BroadcastResponseStats> broadcastResponseStatsList,
+ @Nullable String packageName, @IntRange(from = 0) long id) {
for (int i = mResponseStats.size() - 1; i >= 0; --i) {
final BroadcastEvent broadcastEvent = mResponseStats.keyAt(i);
- if (broadcastEvent.getIdForResponseEvent() == id
- && broadcastEvent.getTargetPackage().equals(packageName)) {
- responseStats.addCounts(mResponseStats.valueAt(i));
+ if (id != 0 && id != broadcastEvent.getIdForResponseEvent()) {
+ continue;
}
+ if (packageName != null && !packageName.equals(broadcastEvent.getTargetPackage())) {
+ continue;
+ }
+ broadcastResponseStatsList.add(mResponseStats.valueAt(i));
}
}
- void clearBroadcastResponseStats(@NonNull String packageName, long id) {
+ void clearBroadcastResponseStats(@Nullable String packageName, @IntRange(from = 0) long id) {
for (int i = mResponseStats.size() - 1; i >= 0; --i) {
final BroadcastEvent broadcastEvent = mResponseStats.keyAt(i);
- if (broadcastEvent.getIdForResponseEvent() == id
- && broadcastEvent.getTargetPackage().equals(packageName)) {
- mResponseStats.removeAt(i);
+ if (id != 0 && id != broadcastEvent.getIdForResponseEvent()) {
+ continue;
}
+ if (packageName != null && !packageName.equals(broadcastEvent.getTargetPackage())) {
+ continue;
+ }
+ mResponseStats.removeAt(i);
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 2fb67d7..7f70301 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -498,6 +498,7 @@
// current USB state
private boolean mHostConnected;
+ private boolean mUsbAccessoryConnected;
private boolean mSourcePower;
private boolean mSinkPower;
private boolean mConfigured;
@@ -964,10 +965,10 @@
break;
case MSG_UPDATE_HOST_STATE:
Iterator devices = (Iterator) msg.obj;
- boolean connected = (msg.arg1 == 1);
+ mUsbAccessoryConnected = (msg.arg1 == 1);
if (DEBUG) {
- Slog.i(TAG, "HOST_STATE connected:" + connected);
+ Slog.i(TAG, "HOST_STATE connected:" + mUsbAccessoryConnected);
}
mHideUsbNotification = false;
@@ -1221,7 +1222,7 @@
} else if (mSourcePower) {
titleRes = com.android.internal.R.string.usb_supplying_notification_title;
id = SystemMessage.NOTE_USB_SUPPLYING;
- } else if (mHostConnected && mSinkPower && mUsbCharging) {
+ } else if (mHostConnected && mSinkPower && (mUsbCharging || mUsbAccessoryConnected)) {
titleRes = com.android.internal.R.string.usb_charging_notification_title;
id = SystemMessage.NOTE_USB_CHARGING;
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index d0825ba..f07a406 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -384,7 +384,7 @@
}
/**
- * Enables USB data when disabled due to {@link UsbPortStatus#USB_DATA_STATUS_DISABLED_DOCK}
+ * Enables USB data when disabled due to {@link UsbPortStatus#DATA_STATUS_DISABLED_DOCK}
*/
public void enableUsbDataWhileDocked(@NonNull String portId, long transactionId,
IUsbOperationInternal callback, IndentingPrintWriter pw) {
@@ -844,7 +844,7 @@
portInfo.contaminantDetectionStatus,
portInfo.usbDataStatus,
portInfo.powerTransferLimited,
- portInfo.powerBrickStatus, pw);
+ portInfo.powerBrickConnectionStatus, pw);
}
} else {
for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -859,7 +859,7 @@
currentPortInfo.contaminantDetectionStatus,
currentPortInfo.usbDataStatus,
currentPortInfo.powerTransferLimited,
- currentPortInfo.powerBrickStatus, pw);
+ currentPortInfo.powerBrickConnectionStatus, pw);
}
}
@@ -895,9 +895,9 @@
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
- int[] usbDataStatus,
+ int usbDataStatus,
boolean powerTransferLimited,
- int powerBrickStatus,
+ int powerBrickConnectionStatus,
IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
@@ -957,7 +957,7 @@
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
mPorts.put(portId, portInfo);
} else {
// Validate that ports aren't changing definition out from under us.
@@ -995,7 +995,7 @@
currentDataRole, canChangeDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus)) {
+ powerTransferLimited, powerBrickConnectionStatus)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1222,7 +1222,7 @@
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED,
- new int[]{UsbPortStatus.USB_DATA_STATUS_UNKNOWN}, false,
+ UsbPortStatus.DATA_STATUS_UNKNOWN, false,
UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN);
dispositionChanged = true;
}
@@ -1238,31 +1238,12 @@
return dispositionChanged;
}
- private boolean dataStatusEquals(int[] dataStatusL, int[] dataStatusR) {
- if (dataStatusL == null && dataStatusR == null) {
- return true;
- }
- if ((dataStatusL == null && dataStatusR != null)
- || (dataStatusL != null && dataStatusR == null)) {
- return false;
- }
- if (dataStatusL.length != dataStatusR.length) {
- return false;
- }
- for (int i = 0; i < dataStatusL.length; i++) {
- if (dataStatusL[i] != dataStatusR[i]) {
- return false;
- }
- }
- return true;
- }
-
public boolean setStatus(int currentMode, boolean canChangeMode,
int currentPowerRole, boolean canChangePowerRole,
int currentDataRole, boolean canChangeDataRole,
int supportedRoleCombinations, int contaminantProtectionStatus,
- int contaminantDetectionStatus, int[] usbDataStatus,
- boolean powerTransferLimited, int powerBrickStatus) {
+ int contaminantDetectionStatus, int usbDataStatus,
+ boolean powerTransferLimited, int powerBrickConnectionStatus) {
boolean dispositionChanged = false;
mCanChangeMode = canChangeMode;
@@ -1278,15 +1259,16 @@
!= contaminantProtectionStatus
|| mUsbPortStatus.getContaminantDetectionStatus()
!= contaminantDetectionStatus
- || !dataStatusEquals(mUsbPortStatus.getUsbDataStatus(), usbDataStatus)
+ || mUsbPortStatus.getUsbDataStatus()
+ != usbDataStatus
|| mUsbPortStatus.isPowerTransferLimited()
!= powerTransferLimited
- || mUsbPortStatus.getPowerBrickStatus()
- != powerBrickStatus) {
+ || mUsbPortStatus.getPowerBrickConnectionStatus()
+ != powerBrickConnectionStatus) {
mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
supportedRoleCombinations, contaminantProtectionStatus,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
dispositionChanged = true;
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index f3308bb..c0ecf58 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -63,6 +63,8 @@
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
+import dalvik.annotation.optimization.NeverCompile;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -883,6 +885,7 @@
}
}
+ @NeverCompile // Avoid size overhead of debugging code.
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
index dd25620..128a051 100644
--- a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -37,9 +37,9 @@
public int contaminantProtectionStatus;
public boolean supportsEnableContaminantPresenceDetection;
public int contaminantDetectionStatus;
- public int[] usbDataStatus;
+ public int usbDataStatus;
public boolean powerTransferLimited;
- public int powerBrickStatus;
+ public int powerBrickConnectionStatus;
public RawPortInfo(String portId, int supportedModes) {
this.portId = portId;
@@ -49,9 +49,10 @@
this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
this.supportsEnableContaminantPresenceDetection = false;
this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
- this.usbDataStatus[0] = UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+ this.usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+
this.powerTransferLimited = false;
- this.powerBrickStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
+ this.powerBrickConnectionStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
}
public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -62,9 +63,9 @@
int contaminantProtectionStatus,
boolean supportsEnableContaminantPresenceDetection,
int contaminantDetectionStatus,
- int[] usbDataStatus,
+ int usbDataStatus,
boolean powerTransferLimited,
- int powerBrickStatus) {
+ int powerBrickConnectionStatus) {
this.portId = portId;
this.supportedModes = supportedModes;
this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -82,7 +83,7 @@
this.contaminantDetectionStatus = contaminantDetectionStatus;
this.usbDataStatus = usbDataStatus;
this.powerTransferLimited = powerTransferLimited;
- this.powerBrickStatus = powerBrickStatus;
+ this.powerBrickConnectionStatus = powerBrickConnectionStatus;
}
@Override
@@ -105,10 +106,9 @@
dest.writeInt(contaminantProtectionStatus);
dest.writeBoolean(supportsEnableContaminantPresenceDetection);
dest.writeInt(contaminantDetectionStatus);
- dest.writeInt(usbDataStatus.length);
- dest.writeIntArray(usbDataStatus);
+ dest.writeInt(usbDataStatus);
dest.writeBoolean(powerTransferLimited);
- dest.writeInt(powerBrickStatus);
+ dest.writeInt(powerBrickConnectionStatus);
}
public static final Parcelable.Creator<RawPortInfo> CREATOR =
@@ -128,10 +128,9 @@
int contaminantProtectionStatus = in.readInt();
boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
int contaminantDetectionStatus = in.readInt();
- int[] usbDataStatus = new int[in.readInt()];
- in.readIntArray(usbDataStatus);
+ int usbDataStatus = in.readInt();
boolean powerTransferLimited = in.readBoolean();
- int powerBrickStatus = in.readInt();
+ int powerBrickConnectionStatus = in.readInt();
return new RawPortInfo(id, supportedModes,
supportedContaminantProtectionModes, currentMode, canChangeMode,
currentPowerRole, canChangePowerRole,
@@ -140,7 +139,7 @@
contaminantProtectionStatus,
supportsEnableContaminantPresenceDetection,
contaminantDetectionStatus, usbDataStatus,
- powerTransferLimited, powerBrickStatus);
+ powerTransferLimited, powerBrickConnectionStatus);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index f468db3..1db018e 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -73,6 +73,42 @@
private boolean mSystemReady;
private long mTransactionId;
+ /**
+ * USB data status is not known.
+ */
+ public static final int USB_DATA_STATUS_UNKNOWN = 0;
+
+ /**
+ * USB data is enabled.
+ */
+ public static final int USB_DATA_STATUS_ENABLED = 1;
+
+ /**
+ * USB data is disabled as the port is too hot.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+
+ /**
+ * USB data is disabled due to contaminated port.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+
+ /**
+ * USB data is disabled due to docking event.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+
+ /**
+ * USB data is disabled by
+ * {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+
+ /**
+ * USB data is disabled for debug.
+ */
+ public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
synchronized (mLock) {
if (mProxy == null) {
@@ -489,12 +525,34 @@
return supportedContaminantProtectionModes;
}
- private int[] toIntArray(byte[] input) {
- int[] output = new int[input.length];
- for (int i = 0; i < input.length; i++) {
- output[i] = input[i];
+ private int toUsbDataStatusInt(byte[] usbDataStatusHal) {
+ int usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+ for (int i = 0; i < usbDataStatusHal.length; i++) {
+ switch (usbDataStatusHal[i]) {
+ case USB_DATA_STATUS_ENABLED:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_ENABLED;
+ break;
+ case USB_DATA_STATUS_DISABLED_OVERHEAT:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+ break;
+ case USB_DATA_STATUS_DISABLED_CONTAMINANT:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+ break;
+ case USB_DATA_STATUS_DISABLED_DOCK:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+ break;
+ case USB_DATA_STATUS_DISABLED_FORCE:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+ break;
+ case USB_DATA_STATUS_DISABLED_DEBUG:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
+ break;
+ default:
+ usbDataStatus |= UsbPortStatus.DATA_STATUS_UNKNOWN;
+ }
}
- return output;
+ UsbPortManager.logAndPrint(Log.INFO, mPw, "AIDL UsbDataStatus:" + usbDataStatus);
+ return usbDataStatus;
}
@Override
@@ -528,7 +586,7 @@
toContaminantProtectionStatus(current.contaminantProtectionStatus),
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
- toIntArray(current.usbDataStatus),
+ toUsbDataStatusInt(current.usbDataStatus),
current.powerTransferLimited,
current.powerBrickStatus);
newPortInfo.add(temp);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index 64e8adc..c7f0775 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -33,8 +33,8 @@
import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
import static com.android.server.usb.UsbPortManager.logAndPrint;
@@ -85,7 +85,7 @@
private HALCallback mHALCallback;
private boolean mSystemReady;
// Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
- private static int sUsbDataStatus = USB_DATA_STATUS_UNKNOWN;
+ private static int sUsbDataStatus = DATA_STATUS_UNKNOWN;
public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
int version;
@@ -375,7 +375,7 @@
}
}
if (success) {
- sUsbDataStatus = enable ? USB_DATA_STATUS_UNKNOWN : USB_DATA_STATUS_DISABLED_FORCE;
+ sUsbDataStatus = enable ? DATA_STATUS_UNKNOWN : DATA_STATUS_DISABLED_FORCE;
}
try {
callback.onOperationComplete(success
@@ -421,7 +421,7 @@
current.canChangePowerRole,
current.currentDataRole, current.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
@@ -455,7 +455,7 @@
current.status.canChangePowerRole,
current.status.currentDataRole, current.status.canChangeDataRole,
false, CONTAMINANT_PROTECTION_NONE,
- false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+ false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
@@ -493,7 +493,7 @@
current.contaminantProtectionStatus,
current.supportsEnableContaminantPresenceDetection,
current.contaminantDetectionStatus,
- new int[sUsbDataStatus],
+ sUsbDataStatus,
false, POWER_BRICK_STATUS_UNKNOWN);
newPortInfo.add(temp);
UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
new file mode 100644
index 0000000..542c6ad
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable ActivityStatsTechSpecificInfo;
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
new file mode 100644
index 0000000..e5a20ea
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
@@ -0,0 +1,245 @@
+/*
+ * 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 android.telephony;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ServiceState.FrequencyRange;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Technology specific activity stats info. List of the activity stats for each RATs (2G, 3G, 4G and
+ * 5G) and frequency ranges (HIGH for sub6 and MMWAVE) in case of 5G. In case implementation doesn't
+ * have RAT specific activity stats then send only one activity stats info with RAT unknown.
+ *
+ * @hide
+ */
+public final class ActivityStatsTechSpecificInfo implements Parcelable {
+ private static final int TX_POWER_LEVELS = 5;
+
+ private int mRat;
+ private int mFrequencyRange;
+ private int[] mTxTimeMs;
+ private int mRxTimeMs;
+
+ /** @hide */
+ public ActivityStatsTechSpecificInfo(
+ int rat, @FrequencyRange int frequencyRange, @NonNull int[] txTimeMs, int rxTimeMs) {
+ Objects.requireNonNull(txTimeMs);
+ if (txTimeMs.length != TX_POWER_LEVELS) {
+ throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+ }
+ mRat = rat;
+ mFrequencyRange = frequencyRange;
+ mTxTimeMs = txTimeMs;
+ mRxTimeMs = rxTimeMs;
+ }
+
+ /**
+ * Returns the radio access technology for this activity stats info.
+ *
+ * The returned value is define in {@link AccessNetworkConstants.AccessNetworkType};
+ * @hide
+ */
+ public int getRat() {
+ return mRat;
+ }
+
+ /**
+ * Returns the rough frequency range for this activity stats info.
+ *
+ * The returned value is define in {@link ServiceState.FrequencyRange};
+ * @hide
+ */
+ public @FrequencyRange int getFrequencyRange() {
+ return mFrequencyRange;
+ }
+
+ /**
+ * Gets the amount of time the modem spent transmitting at a certain power level.
+ *
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+ * power level.
+ */
+ public @DurationMillisLong long getTransmitTimeMillis(int powerLevel) {
+ return mTxTimeMs[powerLevel];
+ }
+
+ /**
+ * @return The raw array of transmit power durations
+ * @hide
+ */
+ @NonNull
+ public int[] getTransmitTimeMillis() {
+ return mTxTimeMs;
+ }
+
+ /**
+ * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+ *
+ * @return Time in milliseconds.
+ * @hide
+ */
+ public @DurationMillisLong long getReceiveTimeMillis() {
+ return mRxTimeMs;
+ }
+ /** @hide */
+ public void setRat(int rat) {
+ mRat = rat;
+ }
+
+ /** @hide */
+ public void setFrequencyRange(@FrequencyRange int frequencyRange) {
+ mFrequencyRange = frequencyRange;
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int receiveTimeMillis) {
+ mRxTimeMs = receiveTimeMillis;
+ }
+
+ /**
+ * Provided for convenience, since the API surface needs to return longs but internal
+ * representations are ints.
+ *
+ * @hide
+ */
+ public void setReceiveTimeMillis(long receiveTimeMillis) {
+ mRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /** @hide */
+ public void setTransmitTimeMillis(int[] txTimeMs) {
+ mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ }
+
+ /** @hide */
+ public boolean isTxPowerValid() {
+ return Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
+ }
+
+ /** @hide */
+ public boolean isRxPowerValid() {
+ return getReceiveTimeMillis() >= 0;
+ }
+
+ /** @hide */
+ public boolean isTxPowerEmpty() {
+ boolean isTxPowerEmpty =
+ mTxTimeMs == null
+ || mTxTimeMs.length == 0
+ || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
+ return isTxPowerEmpty;
+ }
+
+ /** @hide */
+ public boolean isRxPowerEmpty() {
+ return getReceiveTimeMillis() == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mRat, mFrequencyRange, mRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ActivityStatsTechSpecificInfo)) return false;
+ ActivityStatsTechSpecificInfo that = (ActivityStatsTechSpecificInfo) o;
+ return mRat == that.mRat
+ && mFrequencyRange == that.mFrequencyRange
+ && Arrays.equals(mTxTimeMs, that.mTxTimeMs)
+ && mRxTimeMs == that.mRxTimeMs;
+ }
+
+ private static String ratToString(int type) {
+ switch (type) {
+ case AccessNetworkConstants.AccessNetworkType.UNKNOWN:
+ return "UNKNOWN";
+ case AccessNetworkConstants.AccessNetworkType.GERAN:
+ return "GERAN";
+ case AccessNetworkConstants.AccessNetworkType.UTRAN:
+ return "UTRAN";
+ case AccessNetworkConstants.AccessNetworkType.EUTRAN:
+ return "EUTRAN";
+ case AccessNetworkConstants.AccessNetworkType.CDMA2000:
+ return "CDMA2000";
+ case AccessNetworkConstants.AccessNetworkType.IWLAN:
+ return "IWLAN";
+ case AccessNetworkConstants.AccessNetworkType.NGRAN:
+ return "NGRAN";
+ default:
+ return Integer.toString(type);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("{mRat=")
+ .append(ratToString(mRat))
+ .append(",mFrequencyRange=")
+ .append(ServiceState.frequencyRangeToString(mFrequencyRange))
+ .append(",mTxTimeMs[]=")
+ .append(Arrays.toString(mTxTimeMs))
+ .append(",mRxTimeMs=")
+ .append(mRxTimeMs)
+ .append("}")
+ .toString();
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<
+ ActivityStatsTechSpecificInfo>
+ CREATOR =
+ new Parcelable.Creator<ActivityStatsTechSpecificInfo>() {
+ public ActivityStatsTechSpecificInfo createFromParcel(@NonNull Parcel in) {
+ int rat = in.readInt();
+ int frequencyRange = in.readInt();
+ int[] txTimeMs = new int[TX_POWER_LEVELS];
+ in.readIntArray(txTimeMs);
+ int rxTimeMs = in.readInt();
+ return new ActivityStatsTechSpecificInfo(
+ rat, frequencyRange, txTimeMs, rxTimeMs);
+ }
+
+ public ActivityStatsTechSpecificInfo[] newArray(int size) {
+ return new ActivityStatsTechSpecificInfo[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mRat);
+ dest.writeInt(mFrequencyRange);
+ dest.writeIntArray(mTxTimeMs);
+ dest.writeInt(mRxTimeMs);
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2c39863..eb3df1c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -5395,7 +5395,7 @@
defaults.putPersistableBundle(
KEY_RCS_REQUIRES_PROVISIONING_BUNDLE, new PersistableBundle());
- defaults.putBoolean(KEY_GRUU_ENABLED_BOOL, true);
+ defaults.putBoolean(KEY_GRUU_ENABLED_BOOL, false);
defaults.putBoolean(KEY_SIP_OVER_IPSEC_ENABLED_BOOL, true);
defaults.putBoolean(KEY_KEEP_PDN_UP_IN_NO_VOPS_BOOL, false);
defaults.putBoolean(KEY_REGISTRATION_EVENT_PACKAGE_SUPPORTED_BOOL, true);
@@ -5410,7 +5410,7 @@
defaults.putInt(KEY_SIP_TIMER_H_MILLIS_INT, 128000);
defaults.putInt(KEY_SIP_TIMER_J_MILLIS_INT, 128000);
defaults.putInt(KEY_SIP_SERVER_PORT_NUMBER_INT, 5060);
- defaults.putInt(KEY_REQUEST_URI_TYPE_INT, REQUEST_URI_FORMAT_SIP);
+ defaults.putInt(KEY_REQUEST_URI_TYPE_INT, REQUEST_URI_FORMAT_TEL);
defaults.putInt(KEY_SIP_PREFERRED_TRANSPORT_INT, PREFERRED_TRANSPORT_DYNAMIC_UDP_TCP);
defaults.putInt(KEY_IPV4_SIP_MTU_SIZE_CELLULAR_INT, 1500);
defaults.putInt(KEY_IPV6_SIP_MTU_SIZE_CELLULAR_INT, 1500);
@@ -6431,11 +6431,11 @@
defaults.putBoolean(KEY_MULTIENDPOINT_SUPPORTED_BOOL, false);
defaults.putBoolean(KEY_SESSION_TIMER_SUPPORTED_BOOL, true);
defaults.putBoolean(KEY_OIP_SOURCE_FROM_HEADER_BOOL, false);
- defaults.putBoolean(KEY_PRACK_SUPPORTED_FOR_18X_BOOL, true);
+ defaults.putBoolean(KEY_PRACK_SUPPORTED_FOR_18X_BOOL, false);
defaults.putBoolean(KEY_VOICE_QOS_PRECONDITION_SUPPORTED_BOOL, true);
defaults.putBoolean(KEY_VOICE_ON_DEFAULT_BEARER_SUPPORTED_BOOL, false);
- defaults.putInt(KEY_SESSION_REFRESHER_TYPE_INT, SESSION_REFRESHER_TYPE_UNKNOWN);
+ defaults.putInt(KEY_SESSION_REFRESHER_TYPE_INT, SESSION_REFRESHER_TYPE_UAC);
defaults.putInt(KEY_SESSION_PRIVACY_TYPE_INT, SESSION_PRIVACY_TYPE_HEADER);
defaults.putInt(KEY_SESSION_REFRESH_METHOD_INT,
SESSION_REFRESH_METHOD_UPDATE_PREFERRED);
@@ -6457,7 +6457,9 @@
KEY_AUDIO_INACTIVITY_CALL_END_REASONS_INT_ARRAY,
new int[] {
Ims.RTCP_INACTIVITY_ON_CONNECTED,
- Ims.RTP_INACTIVITY_ON_CONNECTED
+ Ims.RTP_INACTIVITY_ON_CONNECTED,
+ Ims.E911_RTCP_INACTIVITY_ON_CONNECTED,
+ Ims.RTCP_INACTIVITY_ON_HOLD
});
defaults.putIntArray(
@@ -6821,7 +6823,7 @@
AccessNetworkType.IWLAN
});
- defaults.putInt(KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT, 20000);
+ defaults.putInt(KEY_EMERGENCY_REGISTRATION_TIMER_MILLIS_INT, 10000);
defaults.putInt(KEY_REFRESH_GEOLOCATION_TIMEOUT_MILLIS_INT, 5000);
return defaults;
@@ -7494,7 +7496,7 @@
private static PersistableBundle getDefaults() {
PersistableBundle defaults = new PersistableBundle();
- defaults.putBoolean(KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL, true);
+ defaults.putBoolean(KEY_UT_REQUIRES_IMS_REGISTRATION_BOOL, false);
defaults.putBoolean(KEY_USE_CSFB_ON_XCAP_OVER_UT_FAILURE_BOOL, true);
defaults.putBoolean(KEY_UT_SUPPORTED_WHEN_PS_DATA_OFF_BOOL, true);
defaults.putBoolean(KEY_NETWORK_INITIATED_USSD_OVER_IMS_SUPPORTED_BOOL, true);
@@ -8124,6 +8126,13 @@
"telephony_data_handover_retry_rules_string_array";
/**
+ * Indicates whether delay tearing down IMS data network until voice call ends.
+ * @hide
+ */
+ public static final String KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL =
+ "delay_ims_tear_down_until_call_end_bool";
+
+ /**
* The patterns of missed incoming call sms. This is the regular expression used for
* matching the missed incoming call's date, time, and caller id. The pattern should match
* fields for at least month, day, hour, and minute. Year is optional although it is encouraged.
@@ -8217,7 +8226,9 @@
"store_sim_pin_for_unattended_reboot_bool";
/**
- * Determine whether "Enable 2G" toggle can be shown.
+ * Allow whether the user can use the "Allow 2G" toggle in Settings.
+ *
+ * If {@code true} then the toggle is disabled (i.e. grayed out).
*
* Used to trade privacy/security against potentially reduced carrier coverage for some
* carriers.
@@ -8968,6 +8979,7 @@
KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, new String[] {
"retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"
});
+ sDefaults.putBoolean(KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, false);
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 837124f..ca6dc2d 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Objects;
@@ -76,7 +78,8 @@
/**
* @hide
*/
- DataSpecificRegistrationInfo(
+ @VisibleForTesting
+ public DataSpecificRegistrationInfo(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
boolean isEnDcAvailable, @Nullable VopsSupportInfo vops) {
this.maxDataCalls = maxDataCalls;
@@ -186,7 +189,7 @@
/**
* @return The VOPS (Voice over Packet Switched) support information.
*
- * The instance of {@link LTEVopsSupportInfo}, or {@link NrVopsSupportInfo},
+ * The instance of {@link LteVopsSupportInfo}, or {@link NrVopsSupportInfo},
* null if there is there is no VOPS support information available.
*/
@Nullable
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ec6c25d..730a9d1 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -25,6 +25,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import android.telephony.ServiceState.FrequencyRange;
import android.util.Range;
import java.lang.annotation.Retention;
@@ -94,8 +95,10 @@
private long mTimestamp;
private int mSleepTimeMs;
private int mIdleTimeMs;
- private int[] mTxTimeMs;
- private int mRxTimeMs;
+ private int[] mTotalTxTimeMs;
+ private int mTotalRxTimeMs;
+ private int mSizeOfSpecificInfo;
+ private ActivityStatsTechSpecificInfo[] mActivityStatsTechSpecificInfo;
/**
* @hide
@@ -110,8 +113,17 @@
mTimestamp = timestamp;
mSleepTimeMs = sleepTimeMs;
mIdleTimeMs = idleTimeMs;
- mTxTimeMs = txTimeMs;
- mRxTimeMs = rxTimeMs;
+ mTotalTxTimeMs = txTimeMs;
+ mTotalRxTimeMs = rxTimeMs;
+
+ mActivityStatsTechSpecificInfo = new ActivityStatsTechSpecificInfo[1];
+ mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+ mActivityStatsTechSpecificInfo[0] =
+ new ActivityStatsTechSpecificInfo(
+ AccessNetworkConstants.AccessNetworkType.UNKNOWN,
+ ServiceState.FREQUENCY_RANGE_UNKNOWN,
+ txTimeMs,
+ rxTimeMs);
}
/**
@@ -124,14 +136,49 @@
this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
}
+ /** @hide */
+ public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
+ @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+ mTimestamp = timestamp;
+ mSleepTimeMs = sleepTimeMs;
+ mIdleTimeMs = idleTimeMs;
+ mActivityStatsTechSpecificInfo = activityStatsTechSpecificInfo;
+ mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+ mTotalTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ for (int i = 0; i < getNumTxPowerLevels(); i++) {
+ for (int j = 0; j < getSpecificInfoLength(); j++) {
+ mTotalTxTimeMs[i] = mTotalTxTimeMs[i]
+ + (int) mActivityStatsTechSpecificInfo[j].getTransmitTimeMillis(i);
+ }
+ }
+ mTotalRxTimeMs = 0;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ mTotalRxTimeMs =
+ mTotalRxTimeMs + (int) mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+
+ /**
+ * Provided for convenience in manipulation since the API exposes long values but internal
+ * representations are ints.
+ * @hide
+ */
+ public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+ @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+ this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, activityStatsTechSpecificInfo);
+ }
+
@Override
public String toString() {
return "ModemActivityInfo{"
- + " mTimestamp=" + mTimestamp
- + " mSleepTimeMs=" + mSleepTimeMs
- + " mIdleTimeMs=" + mIdleTimeMs
- + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
- + " mRxTimeMs=" + mRxTimeMs
+ + " mTimestamp="
+ + mTimestamp
+ + " mSleepTimeMs="
+ + mSleepTimeMs
+ + " mIdleTimeMs="
+ + mIdleTimeMs
+ + " mActivityStatsTechSpecificInfo="
+ + Arrays.toString(mActivityStatsTechSpecificInfo)
+ "}";
}
@@ -145,11 +192,17 @@
long timestamp = in.readLong();
int sleepTimeMs = in.readInt();
int idleTimeMs = in.readInt();
- int[] txTimeMs = new int[TX_POWER_LEVELS];
- in.readIntArray(txTimeMs);
- int rxTimeMs = in.readInt();
- return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
- txTimeMs, rxTimeMs);
+ Parcelable[] tempSpecifiers =
+ in.createTypedArray(ActivityStatsTechSpecificInfo.CREATOR);
+ ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo;
+ activityStatsTechSpecificInfo =
+ new ActivityStatsTechSpecificInfo[tempSpecifiers.length];
+ for (int i = 0; i < tempSpecifiers.length; i++) {
+ activityStatsTechSpecificInfo[i] =
+ (ActivityStatsTechSpecificInfo) tempSpecifiers[i];
+ }
+ return new ModemActivityInfo(
+ timestamp, sleepTimeMs, idleTimeMs, activityStatsTechSpecificInfo);
}
public ModemActivityInfo[] newArray(int size) {
@@ -165,15 +218,14 @@
dest.writeLong(mTimestamp);
dest.writeInt(mSleepTimeMs);
dest.writeInt(mIdleTimeMs);
- dest.writeIntArray(mTxTimeMs);
- dest.writeInt(mRxTimeMs);
+ dest.writeTypedArray(mActivityStatsTechSpecificInfo, flags);
}
/**
* Gets the timestamp at which this modem activity info was recorded.
*
- * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
- * {@link ModemActivityInfo} was recorded.
+ * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this {@link
+ * ModemActivityInfo} was recorded.
*/
public @ElapsedRealtimeLong long getTimestampMillis() {
return mTimestamp;
@@ -188,14 +240,41 @@
* Gets the amount of time the modem spent transmitting at a certain power level.
*
* @param powerLevel The power level to query.
- * @return The amount of time, in milliseconds, that the modem spent transmitting at the
- * given power level.
+ * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+ * power level.
*/
public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
@TxPowerLevel int powerLevel) {
- return mTxTimeMs[powerLevel];
+ long txTimeMsAtPowerLevel = 0;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ txTimeMsAtPowerLevel +=
+ mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ return txTimeMsAtPowerLevel;
}
+ /** @hide */
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel, int rat) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ }
+ return 0;
+ }
+
+ /** @hide */
+ public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+ @TxPowerLevel int powerLevel, int rat, @FrequencyRange int freq) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+ }
+ }
+ return 0;
+ }
/**
* Gets the range of transmit powers corresponding to a certain power level.
*
@@ -208,17 +287,64 @@
}
/** @hide */
- public void setTransmitTimeMillis(int[] txTimeMs) {
- mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ public int getSpecificInfoRat(int index) {
+ return mActivityStatsTechSpecificInfo[index].getRat();
}
+ /** @hide */
+ public int getSpecificInfoFrequencyRange(int index) {
+ return mActivityStatsTechSpecificInfo[index].getFrequencyRange();
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int[] txTimeMs) {
+ mTotalTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int rat, int[] txTimeMs) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+ }
+ }
+ }
+ /** @hide */
+ public void setTransmitTimeMillis(int rat, int freq, int[] txTimeMs) {
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+ }
+ }
+ }
/**
* @return The raw array of transmit power durations
* @hide
*/
@NonNull
public int[] getTransmitTimeMillis() {
- return mTxTimeMs;
+ return mTotalTxTimeMs;
+ }
+
+ /** @hide */
+ public int[] getTransmitTimeMillis(@AccessNetworkConstants.RadioAccessNetworkType int rat) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+ }
+ }
+ return new int[5];
+ }
+
+ /** @hide */
+ public int[] getTransmitTimeMillis(
+ @AccessNetworkConstants.RadioAccessNetworkType int rat, @FrequencyRange int freq) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+ }
+ }
+ return new int[5];
}
/**
@@ -238,6 +364,7 @@
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setSleepTimeMillis(long sleepTimeMillis) {
@@ -257,14 +384,63 @@
*/
public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
- txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+
+ ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo;
+ mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()];
+
+ boolean matched;
+ for (int i = 0; i < other.getSpecificInfoLength(); i++) {
+ matched = false;
+ for (int j = 0; j < getSpecificInfoLength(); j++) {
+ int rat = mActivityStatsTechSpecificInfo[j].getRat();
+ if (rat == other.mActivityStatsTechSpecificInfo[i].getRat() && !matched) {
+ if (mActivityStatsTechSpecificInfo[j].getRat()
+ == AccessNetworkConstants.AccessNetworkType.NGRAN) {
+ if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange()
+ == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) {
+ int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange();
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ txTimeMs[lvl] =
+ (int) (other.getTransmitDurationMillisAtPowerLevel(
+ lvl, rat, freq)
+ - getTransmitDurationMillisAtPowerLevel(
+ lvl, rat, freq));
+ }
+ matched = true;
+ mDeltaSpecificInfo[i] =
+ new ActivityStatsTechSpecificInfo(
+ rat,
+ freq,
+ txTimeMs,
+ (int) (other.getReceiveTimeMillis(rat, freq)
+ - getReceiveTimeMillis(rat, freq)));
+ }
+ } else {
+ for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+ txTimeMs[lvl] =
+ (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat)
+ - getTransmitDurationMillisAtPowerLevel(lvl, rat));
+ }
+ matched = true;
+ mDeltaSpecificInfo[i] =
+ new ActivityStatsTechSpecificInfo(
+ rat,
+ ServiceState.FREQUENCY_RANGE_UNKNOWN,
+ txTimeMs,
+ (int) (other.getReceiveTimeMillis(rat)
+ - getReceiveTimeMillis(rat)));
+ }
+ }
+ }
+ if (!matched) {
+ mDeltaSpecificInfo[i] = other.mActivityStatsTechSpecificInfo[i];
+ }
}
- return new ModemActivityInfo(other.getTimestampMillis(),
+ return new ModemActivityInfo(
+ other.getTimestampMillis(),
other.getSleepTimeMillis() - getSleepTimeMillis(),
other.getIdleTimeMillis() - getIdleTimeMillis(),
- txTimeMs,
- other.getReceiveTimeMillis() - getReceiveTimeMillis());
+ mDeltaSpecificInfo);
}
/**
@@ -285,6 +461,7 @@
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setIdleTimeMillis(long idleTimeMillis) {
@@ -297,21 +474,66 @@
* @return Time in milliseconds.
*/
public @DurationMillisLong long getReceiveTimeMillis() {
- return mRxTimeMs;
+ return mTotalRxTimeMs;
+ }
+
+ /** @hide */
+ public @DurationMillisLong long getReceiveTimeMillis(int rat) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+ return 0;
+ }
+ /** @hide */
+ public @DurationMillisLong long getReceiveTimeMillis(int rat, int freq) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+ }
+ }
+ return 0;
}
/** @hide */
public void setReceiveTimeMillis(int rxTimeMillis) {
- mRxTimeMs = rxTimeMillis;
+ mTotalRxTimeMs = rxTimeMillis;
}
/**
* Provided for convenience, since the API surface needs to return longs but internal
* representations are ints.
+ *
* @hide
*/
public void setReceiveTimeMillis(long receiveTimeMillis) {
- mRxTimeMs = (int) receiveTimeMillis;
+ mTotalRxTimeMs = (int) receiveTimeMillis;
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int rat, long receiveTimeMillis) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+ mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+ }
+ }
+ }
+
+ /** @hide */
+ public void setReceiveTimeMillis(int rat, int freq, long receiveTimeMillis) {
+ for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+ if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+ && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+ mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+ }
+ }
+ }
+
+ /** @hide */
+ public int getSpecificInfoLength() {
+ return mSizeOfSpecificInfo;
}
/**
@@ -323,23 +545,42 @@
*/
@TestApi
public boolean isValid() {
- boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
-
- return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
- && (getReceiveTimeMillis() >= 0) && !isEmpty());
+ if (mActivityStatsTechSpecificInfo == null) {
+ return false;
+ } else {
+ boolean isTxPowerValid = true;
+ boolean isRxPowerValid = true;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (!mActivityStatsTechSpecificInfo[i].isTxPowerValid()) {
+ isTxPowerValid = false;
+ }
+ if (!mActivityStatsTechSpecificInfo[i].isRxPowerValid()) {
+ isRxPowerValid = false;
+ }
+ }
+ return isTxPowerValid
+ && isRxPowerValid
+ && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0) && !isEmpty());
+ }
}
/** @hide */
@TestApi
public boolean isEmpty() {
- boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
- || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
-
- return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
- && (getReceiveTimeMillis() == 0));
+ boolean isTxPowerEmpty = false;
+ boolean isRxPowerEmpty = false;
+ for (int i = 0; i < getSpecificInfoLength(); i++) {
+ if (mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
+ isTxPowerEmpty = true;
+ }
+ if (mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
+ isRxPowerEmpty = true;
+ }
+ }
+ return isTxPowerEmpty
+ && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0) && isRxPowerEmpty);
}
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -348,14 +589,15 @@
return mTimestamp == that.mTimestamp
&& mSleepTimeMs == that.mSleepTimeMs
&& mIdleTimeMs == that.mIdleTimeMs
- && mRxTimeMs == that.mRxTimeMs
- && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+ && mSizeOfSpecificInfo == that.mSizeOfSpecificInfo
+ && Arrays.equals(
+ mActivityStatsTechSpecificInfo, that.mActivityStatsTechSpecificInfo);
}
@Override
public int hashCode() {
- int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
- result = 31 * result + Arrays.hashCode(mTxTimeMs);
+ int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mTotalRxTimeMs);
+ result = 31 * result + Arrays.hashCode(mTotalTxTimeMs);
return result;
}
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c18443e..c701e44 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -242,13 +242,16 @@
* @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
* information is not available.
* @param rplmn the registered plmn or the last plmn for attempted registration if reg failed.
+ * @param voiceSpecificInfo Voice specific registration information.
+ * @param dataSpecificInfo Data specific registration information.
*/
private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
- @RegistrationState int registrationState,
- @NetworkType int accessNetworkTechnology, int rejectCause,
- boolean emergencyOnly,
- @Nullable @ServiceType List<Integer> availableServices,
- @Nullable CellIdentity cellIdentity, @Nullable String rplmn) {
+ @RegistrationState int registrationState,
+ @NetworkType int accessNetworkTechnology, int rejectCause,
+ boolean emergencyOnly, @Nullable @ServiceType List<Integer> availableServices,
+ @Nullable CellIdentity cellIdentity, @Nullable String rplmn,
+ @Nullable VoiceSpecificRegistrationInfo voiceSpecificInfo,
+ @Nullable DataSpecificRegistrationInfo dataSpecificInfo) {
mDomain = domain;
mTransportType = transportType;
mRegistrationState = registrationState;
@@ -262,6 +265,10 @@
mEmergencyOnly = emergencyOnly;
mNrState = NR_STATE_NONE;
mRplmn = rplmn;
+ mVoiceSpecificInfo = voiceSpecificInfo;
+ mDataSpecificInfo = dataSpecificInfo;
+
+ updateNrState();
}
/**
@@ -276,10 +283,9 @@
boolean cssSupported, int roamingIndicator, int systemIsInPrl,
int defaultRoamingIndicator) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
- emergencyOnly, availableServices, cellIdentity, rplmn);
-
- mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
- systemIsInPrl, defaultRoamingIndicator);
+ emergencyOnly, availableServices, cellIdentity, rplmn,
+ new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
+ systemIsInPrl, defaultRoamingIndicator), null);
}
/**
@@ -295,11 +301,9 @@
boolean isNrAvailable, boolean isEndcAvailable,
@Nullable VopsSupportInfo vopsSupportInfo) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
- emergencyOnly, availableServices, cellIdentity, rplmn);
- mDataSpecificInfo = new DataSpecificRegistrationInfo(
- maxDataCalls, isDcNrRestricted, isNrAvailable,
- isEndcAvailable, vopsSupportInfo);
- updateNrState();
+ emergencyOnly, availableServices, cellIdentity, rplmn, null,
+ new DataSpecificRegistrationInfo(maxDataCalls, isDcNrRestricted, isNrAvailable,
+ isEndcAvailable, vopsSupportInfo));
}
private NetworkRegistrationInfo(Parcel source) {
@@ -804,6 +808,12 @@
@NonNull
private String mRplmn = "";
+ @Nullable
+ private DataSpecificRegistrationInfo mDataSpecificRegistrationInfo;
+
+ @Nullable
+ private VoiceSpecificRegistrationInfo mVoiceSpecificRegistrationInfo;
+
/**
* Default constructor for Builder.
*/
@@ -930,6 +940,30 @@
}
/**
+ * Set voice specific registration information.
+ *
+ * @param info The voice specific registration information.
+ * @return The builder.
+ * @hide
+ */
+ public @NonNull Builder setVoiceSpecificInfo(@NonNull VoiceSpecificRegistrationInfo info) {
+ mVoiceSpecificRegistrationInfo = info;
+ return this;
+ }
+
+ /**
+ * Set data specific registration information.
+ *
+ * @param info The data specific registration information.
+ * @return The builder.
+ * @hide
+ */
+ public @NonNull Builder setDataSpecificInfo(@NonNull DataSpecificRegistrationInfo info) {
+ mDataSpecificRegistrationInfo = info;
+ return this;
+ }
+
+ /**
* Build the NetworkRegistrationInfo.
* @return the NetworkRegistrationInfo object.
* @hide
@@ -938,7 +972,8 @@
public @NonNull NetworkRegistrationInfo build() {
return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mRplmn);
+ mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
+ mDataSpecificRegistrationInfo);
}
}
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 65f5632..6fe9bf9 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1205,7 +1205,15 @@
}
}
- private void init() {
+ /**
+ * Initialize the service state. Set everything to the default value.
+ *
+ * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+ * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+ * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+ * {@link NetworkRegistrationInfo}.
+ */
+ private void init(boolean legacyMode) {
if (DBG) Rlog.d(LOG_TAG, "init");
mVoiceRegState = STATE_OUT_OF_SERVICE;
mDataRegState = STATE_OUT_OF_SERVICE;
@@ -1237,6 +1245,13 @@
.setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
.build());
+ if (!legacyMode) {
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
+ }
}
mOperatorAlphaLongRaw = null;
mOperatorAlphaShortRaw = null;
@@ -1245,15 +1260,32 @@
}
public void setStateOutOfService() {
- init();
+ init(true);
}
public void setStateOff() {
- init();
+ init(true);
mVoiceRegState = STATE_POWER_OFF;
mDataRegState = STATE_POWER_OFF;
}
+ /**
+ * Set the service state to out-of-service
+ *
+ * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+ * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+ * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+ * @param powerOff {@code true} if this is a power off case (i.e. Airplane mode on).
+ * @hide
+ */
+ public void setOutOfService(boolean legacyMode, boolean powerOff) {
+ init(legacyMode);
+ if (powerOff) {
+ mVoiceRegState = STATE_POWER_OFF;
+ mDataRegState = STATE_POWER_OFF;
+ }
+ }
+
public void setState(int state) {
setVoiceRegState(state);
if (DBG) Rlog.e(LOG_TAG, "[ServiceState] setState deprecated use setVoiceRegState()");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 613b0a6..f57c32c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6967,6 +6967,11 @@
*
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
+ * It is strongly recommended that callers of this should firstly create a new TelephonyManager
+ * instance by calling {@link TelephonyManager#createForSubscriptionId(int)}. Failure to do so
+ * can result in unpredictable and detrimental behavior like callers can end up talking to the
+ * wrong SIM card.
+ *
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -7060,6 +7065,8 @@
}
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
+ } catch (IllegalStateException ex) {
+ Rlog.e(TAG, "iccCloseLogicalChannel IllegalStateException", ex);
}
return false;
}
@@ -7107,6 +7114,10 @@
* Closes a previously opened logical channel to the ICC card.
*
* Input parameters equivalent to TS 27.007 AT+CCHC command.
+ * It is strongly recommended that callers of this API should firstly create
+ * new TelephonyManager instance by calling
+ * {@link TelephonyManager#createForSubscriptionId(int)}. Failure to do so can result in
+ * unpredictable and detrimental behavior like callers can end up talking to the wrong SIM card.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
@@ -7115,6 +7126,7 @@
* @param channel is the channel id to be closed as returned by a successful
* iccOpenLogicalChannel.
* @return true if the channel was closed successfully.
+ * @throws IllegalArgumentException if input parameters are wrong. e.g., invalid channel
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
public boolean iccCloseLogicalChannel(int channel) {
@@ -7122,8 +7134,6 @@
return iccCloseLogicalChannel(getSubId(), channel);
} catch (IllegalStateException ex) {
Rlog.e(TAG, "iccCloseLogicalChannel IllegalStateException", ex);
- } catch (IllegalArgumentException ex) {
- Rlog.e(TAG, "iccCloseLogicalChannel IllegalArgumentException", ex);
}
return false;
}
@@ -7154,6 +7164,8 @@
}
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
+ } catch (IllegalStateException ex) {
+ Rlog.e(TAG, "iccCloseLogicalChannel IllegalStateException", ex);
}
return false;
}
@@ -7255,6 +7267,11 @@
*
* Input parameters equivalent to TS 27.007 AT+CGLA command.
*
+ * It is strongly recommended that callers of this API should firstly create a new
+ * TelephonyManager instance by calling
+ * {@link TelephonyManager#createForSubscriptionId(int)}. Failure to do so can result in
+ * unpredictable and detrimental behavior like callers can end up talking to the wrong SIM card.
+ *
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a49a61b5..b6ae530 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -25,15 +25,20 @@
import android.annotation.SystemApi;
import android.app.Activity;
import android.app.PendingIntent;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
+import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
import android.telephony.euicc.EuiccCardManager.ResetOption;
+import android.util.Log;
import com.android.internal.telephony.euicc.IEuiccController;
@@ -57,6 +62,7 @@
*/
@RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
public class EuiccManager {
+ private static final String TAG = "EuiccManager";
/**
* Intent action to launch the embedded SIM (eUICC) management settings screen.
@@ -811,6 +817,14 @@
*/
public static final int ERROR_INVALID_PORT = 10017;
+ /**
+ * Apps targeting on Android T and beyond will get exception whenever switchToSubscription
+ * without portIndex is called for disable subscription.
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ public static final long SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE = 218393363L;
private final Context mContext;
private int mCardId;
@@ -1127,7 +1141,7 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be enabled.
*
- * <p> From Android T, devices might support MEP(Multiple Enabled Profile), the subscription
+ * <p> From Android T, devices might support MEP(Multiple Enabled Profiles), the subscription
* can be installed on different port from the eUICC. Calling apps with carrier privilege
* (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently active subscriptions
* can use {@link #switchToSubscription(int, int, PendingIntent)} to specify which port to
@@ -1138,10 +1152,12 @@
*
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
- * current profile without activating another profile to replace it. If it's a disable
- * operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS}
- * permission, or the calling app must be authorized to manage the active subscription on
- * the target eUICC.
+ * current profile without activating another profile to replace it. Calling apps targeting
+ * on android T must use {@link #switchToSubscription(int, int, PendingIntent)} API for
+ * disable profile, port index can be found from {@link SubscriptionInfo#getPortIndex()}.
+ * If it's a disable operation, requires the
+ * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or the
+ * calling app must be authorized to manage the active subscription on the target eUICC.
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
@@ -1151,6 +1167,18 @@
return;
}
try {
+ // TODO: Uncomment below compat change code once callers are ported to use
+ // switchToSubscription with portIndex for disable operation.
+ // if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ // && getIEuiccController().isCompatChangeEnabled(mContext.getOpPackageName(),
+ // SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE)) {
+ // // Apps targeting on Android T and beyond will get exception whenever
+ // // switchToSubscription without portIndex is called with INVALID_SUBSCRIPTION_ID.
+ // Log.e(TAG, "switchToSubscription without portIndex is not allowed for"
+ // + " disable operation");
+ // throw new IllegalArgumentException("Must use switchToSubscription with portIndex"
+ // + " API for disable operation");
+ // }
getIEuiccController().switchToSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
@@ -1180,7 +1208,10 @@
* current profile without activating another profile to replace it. If it's a disable
* operation, requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS}
* permission, or the calling app must be authorized to manage the active subscription on
- * the target eUICC.
+ * the target eUICC. From Android T, multiple enabled profiles is supported. Calling apps
+ * targeting on android T must use {@link #switchToSubscription(int, int, PendingIntent)}
+ * API for disable profile, port index can be found from
+ * {@link SubscriptionInfo#getPortIndex()}.
* @param portIndex the index of the port to target for the enabled subscription
* @param callbackIntent a PendingIntent to launch when the operation completes.
*/
@@ -1192,6 +1223,17 @@
return;
}
try {
+ boolean canWriteEmbeddedSubscriptions = mContext.checkCallingOrSelfPermission(
+ Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
+ == PackageManager.PERMISSION_GRANTED;
+ // If the caller is not privileged caller and does not have the carrier privilege over
+ // any active subscription, do not continue.
+ if (!canWriteEmbeddedSubscriptions && !getIEuiccController()
+ .hasCarrierPrivilegesForPackageOnAnyPhone(mContext.getOpPackageName())) {
+ Log.e(TAG, "Not permitted to use switchToSubscription with portIndex");
+ throw new SecurityException(
+ "Must have carrier privileges to use switchToSubscription with portIndex");
+ }
getIEuiccController().switchToSubscriptionWithPort(mCardId,
subscriptionId, portIndex, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index dda95b1..19f1a5b 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -55,4 +55,6 @@
List<String> getSupportedCountries(boolean isSupported);
boolean isSupportedCountry(String countryIso);
boolean isSimPortAvailable(int cardId, int portIndex, String callingPackage);
+ boolean hasCarrierPrivilegesForPackageOnAnyPhone(String callingPackage);
+ boolean isCompatChangeEnabled(String callingPackage, long changeId);
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 429541c..71e576a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -44,6 +44,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 219749605)
class LaunchAppShowImeAndDialogThemeAppTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@@ -119,4 +120,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 5f0176e..ba5698c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -61,6 +61,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group2
+@FlakyTest(bugId = 219757170)
class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
@@ -87,7 +88,7 @@
}
transitions {
device.reopenAppFromOverview(wmHelper)
- wmHelper.waitImeShown()
+ require(wmHelper.waitImeShown()) { "IME didn't show in time" }
}
teardown {
test {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 065b1c2..3b3a303 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,16 +16,19 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Presubmit
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
+import android.platform.test.annotations.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,7 +57,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppColdTest(testSpec: FlickerTestParameter)
+ : OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
new file mode 100644
index 0000000..849e3ae
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest_ShellTransit.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test cold launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenAppColdTest`
+ *
+ * Actions:
+ * Make sure no apps are running on the device
+ * Launch an app [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppColdTest_ShellTransit(testSpec: FlickerTestParameter) : OpenAppColdTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 797919b..18d017d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,21 +17,22 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.Display
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -62,8 +63,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppFromOverviewTest(testSpec: FlickerTestParameter)
+open class OpenAppFromOverviewTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
new file mode 100644
index 0000000..24716ff
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest_ShellTransit.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching an app from the recents app view (the overview)
+ *
+ * To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press recents
+ * Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to
+ * complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppFromOverviewTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppFromOverviewTest(testSpec) {
+ @Before
+ override fun before() {
+ assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index f75c50e..0ba5369 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,19 +16,22 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.Surface
import android.view.WindowManagerPolicyConstants
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -57,11 +60,16 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
+open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter)
: OpenAppFromLockTransition(testSpec) {
override val testApp = NonResizeableAppHelper(instrumentation)
private val colorFadComponent = FlickerComponentName("", "ColorFade BLAST#")
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Checks that the nav bar layer starts invisible, becomes visible during unlocking animation
* and remains visible at the end
@@ -148,6 +156,11 @@
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
+ @FlakyTest(bugId = 218470989)
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt
new file mode 100644
index 0000000..f8afcd9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest_ShellTransit.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test launching an app while the device is locked
+ *
+ * To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ *
+ * Actions:
+ * Lock the device.
+ * Launch an app on top of the lock screen [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppNonResizeableTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppNonResizeableTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 3159bf1..2562098 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -17,14 +17,17 @@
package com.android.server.wm.flicker.launch
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.helpers.setRotation
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -54,8 +57,13 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class OpenAppWarmTest(testSpec: FlickerTestParameter)
+open class OpenAppWarmTest(testSpec: FlickerTestParameter)
: OpenAppFromLauncherTransition(testSpec) {
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
/**
* Defines the transition used to run the test
*/
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
new file mode 100644
index 0000000..0ce73f4
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest_ShellTransit.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test warm launching an app from launcher
+ *
+ * To run this test: `atest FlickerTests:OpenAppWarmTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press home
+ * Relaunch an app [testApp] and wait animation to complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219688533)
+class OpenAppWarmTest_ShellTransit(testSpec: FlickerTestParameter)
+ : OpenAppWarmTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 5301e02..f21b1d6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -33,12 +33,15 @@
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,7 +64,7 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
-class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
+open class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
private val testApp1 = SimpleAppHelper(instrumentation)
@@ -69,6 +72,11 @@
private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
@@ -326,4 +334,4 @@
)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
new file mode 100644
index 0000000..07fe274
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.quickswitch
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ *
+ * Actions:
+ * Launch an app [testApp1]
+ * Launch another app [testApp2]
+ * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+@FlakyTest(bugId = 219690120)
+class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestParameter)
+ : QuickSwitchBetweenTwoAppsBackTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 3ae484b..15fd5e1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,17 +17,20 @@
package com.android.server.wm.flicker.rotation
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
import android.view.WindowManager
import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.traces.common.FlickerComponentName
+import org.junit.Assume
+import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -76,11 +79,16 @@
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class SeamlessAppRotationTest(
+open class SeamlessAppRotationTest(
testSpec: FlickerTestParameter
) : RotationTransition(testSpec) {
override val testApp = SeamlessRotationAppHelper(instrumentation)
+ @Before
+ open fun before() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ }
+
override val transition: FlickerBuilder.() -> Unit
get() = {
super.transition(this)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt
new file mode 100644
index 0000000..be55751
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest_ShellTransit.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.rotation
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.annotation.Group3
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import org.junit.Assume
+import org.junit.Before
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test opening an app and cycling through app rotations using seamless rotations
+ *
+ * Currently runs:
+ * 0 -> 90 degrees
+ * 0 -> 90 degrees (with starved UI thread)
+ * 90 -> 0 degrees
+ * 90 -> 0 degrees (with starved UI thread)
+ *
+ * Actions:
+ * Launch an app in fullscreen and supporting seamless rotation (via intent)
+ * Set initial device orientation
+ * Start tracing
+ * Change device orientation
+ * Stop tracing
+ *
+ * To run this test: `atest FlickerTests:SeamlessAppRotationTest`
+ *
+ * To run only the presubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Presubmit`
+ *
+ * To run only the postsubmit assertions add: `--
+ * --module-arg FlickerTests:exclude-annotation:androidx.test.filters.FlakyTest
+ * --module-arg FlickerTests:include-annotation:android.platform.test.annotations.Postsubmit`
+ *
+ * To run only the flaky assertions add: `--
+ * --module-arg FlickerTests:include-annotation:androidx.test.filters.FlakyTest`
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [RotationTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+@FlakyTest(bugId = 219689723)
+class SeamlessAppRotationTest_ShellTransit(
+ testSpec: FlickerTestParameter
+) : SeamlessAppRotationTest(testSpec) {
+ @Before
+ override fun before() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ }
+}
diff --git a/tests/Internal/src/com/android/internal/util/UserIconsTest.java b/tests/Internal/src/com/android/internal/util/UserIconsTest.java
new file mode 100644
index 0000000..cc7b20b
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/util/UserIconsTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class UserIconsTest {
+
+ @Test
+ public void convertToBitmapAtUserIconSize_sizeIsCorrect() {
+ Resources res = InstrumentationRegistry.getTargetContext().getResources();
+ Drawable icon = UserIcons.getDefaultUserIcon(res, 0, true);
+ Bitmap bitmap = UserIcons.convertToBitmapAtUserIconSize(res, icon);
+ int expectedSize = res.getDimensionPixelSize(R.dimen.user_icon_size);
+
+ assertThat(bitmap.getWidth()).isEqualTo(expectedSize);
+ assertThat(bitmap.getHeight()).isEqualTo(expectedSize);
+ }
+
+}
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 978bf3e..7b1f7a5 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -174,7 +174,7 @@
private IntentFilter getIntentFilter() {
final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt());
return captor.getValue();
}
@@ -258,7 +258,8 @@
eq(mTelephonySubscriptionTracker),
any(IntentFilter.class),
any(),
- eq(mHandler));
+ eq(mHandler),
+ eq(Context.RECEIVER_NOT_EXPORTED));
final IntentFilter filter = getIntentFilter();
assertEquals(2, filter.countActions());
assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));