summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt19
-rw-r--r--api/system-current.txt8
-rw-r--r--api/test-current.txt2
-rw-r--r--cmds/statsd/src/atoms.proto18
-rw-r--r--cmds/statsd/src/guardrail/StatsdStats.h1
-rw-r--r--cmds/statsd/tests/guardrail/StatsdStats_test.cpp33
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java17
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java13
-rw-r--r--core/java/android/content/pm/PackageParser.java7
-rw-r--r--core/java/android/hardware/display/ColorDisplayManager.java19
-rw-r--r--core/java/android/hardware/display/IColorDisplayManager.aidl1
-rw-r--r--core/java/android/os/FileUtils.java6
-rw-r--r--core/java/android/provider/DeviceConfig.java19
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/service/textclassifier/TEST_MAPPING7
-rw-r--r--core/java/android/view/InputDevice.java6
-rw-r--r--core/java/android/view/LayoutInflater.java7
-rw-r--r--core/java/android/view/View.java30
-rw-r--r--core/java/android/view/ViewGroup.java4
-rw-r--r--core/java/android/view/ViewStub.java3
-rw-r--r--core/java/android/view/animation/Animation.java56
-rw-r--r--core/java/android/view/autofill/AutofillManager.java12
-rw-r--r--core/java/android/view/textclassifier/TEST_MAPPING23
-rw-r--r--core/java/android/widget/AbsListView.java4
-rw-r--r--core/java/android/widget/AbsSeekBar.java2
-rw-r--r--core/java/android/widget/AbsSpinner.java2
-rw-r--r--core/java/android/widget/ActivityChooserView.java2
-rw-r--r--core/java/android/widget/AdapterViewAnimator.java3
-rw-r--r--core/java/android/widget/AdapterViewFlipper.java2
-rw-r--r--core/java/android/widget/AnalogClock.java2
-rw-r--r--core/java/android/widget/AutoCompleteTextView.java4
-rw-r--r--core/java/android/widget/CalendarView.java2
-rw-r--r--core/java/android/widget/CheckedTextView.java2
-rw-r--r--core/java/android/widget/Chronometer.java2
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/DatePicker.java2
-rw-r--r--core/java/android/widget/DayPickerView.java2
-rw-r--r--core/java/android/widget/ExpandableListView.java2
-rw-r--r--core/java/android/widget/FrameLayout.java2
-rw-r--r--core/java/android/widget/Gallery.java2
-rw-r--r--core/java/android/widget/GridLayout.java2
-rw-r--r--core/java/android/widget/GridView.java2
-rw-r--r--core/java/android/widget/HorizontalScrollView.java116
-rw-r--r--core/java/android/widget/ImageView.java2
-rw-r--r--core/java/android/widget/LinearLayout.java2
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/android/widget/NumberPicker.java2
-rw-r--r--core/java/android/widget/ProgressBar.java4
-rw-r--r--core/java/android/widget/RadialTimePickerView.java2
-rw-r--r--core/java/android/widget/RadioGroup.java2
-rw-r--r--core/java/android/widget/RatingBar.java2
-rw-r--r--core/java/android/widget/RelativeLayout.java2
-rw-r--r--core/java/android/widget/ScrollView.java119
-rw-r--r--core/java/android/widget/SearchView.java2
-rw-r--r--core/java/android/widget/SlidingDrawer.java2
-rw-r--r--core/java/android/widget/Spinner.java2
-rw-r--r--core/java/android/widget/StackView.java2
-rw-r--r--core/java/android/widget/Switch.java2
-rw-r--r--core/java/android/widget/TabHost.java2
-rw-r--r--core/java/android/widget/TabWidget.java2
-rw-r--r--core/java/android/widget/TextClock.java12
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--core/java/android/widget/TimePicker.java2
-rw-r--r--core/java/android/widget/ToggleButton.java2
-rw-r--r--core/java/android/widget/Toolbar.java2
-rw-r--r--core/java/android/widget/TwoLineListItem.java2
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java37
-rw-r--r--core/java/com/android/internal/os/LooperStats.java10
-rw-r--r--core/res/res/drawable/ic_action_open.xml24
-rw-r--r--core/res/res/values/attrs_manifest.xml9
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java3
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java3
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java67
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java28
-rw-r--r--graphics/java/android/graphics/Typeface.java7
-rw-r--r--media/java/android/media/IRingtonePlayer.aidl3
-rw-r--r--media/java/android/media/Ringtone.java3
-rw-r--r--media/java/android/media/VolumeShaper.aidl19
-rw-r--r--media/jni/soundpool/SoundPool.cpp9
-rw-r--r--native/android/libandroid.map.txt1
-rw-r--r--native/android/surface_control.cpp14
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java4
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java26
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java37
-rw-r--r--packages/SystemUI/res/drawable/privacy_chip_bg.xml3
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml119
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_chip.xml19
-rw-r--r--packages/SystemUI/res/values/dimens.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java51
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java39
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java38
-rw-r--r--services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java3
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java8
-rw-r--r--services/core/java/com/android/server/LooperStatsService.java13
-rw-r--r--services/core/java/com/android/server/adb/AdbDebuggingManager.java20
-rw-r--r--services/core/java/com/android/server/am/UserController.java3
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java20
-rw-r--r--services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java2
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java7
-rw-r--r--services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java78
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java108
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java87
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java9
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java94
-rw-r--r--services/usage/java/com/android/server/usage/AppTimeLimitController.java5
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java2
-rw-r--r--telecomm/java/android/telecom/DefaultDialerManager.java34
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java14
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java3
-rw-r--r--wifi/java/android/net/wifi/aware/TlvBufferUtils.java125
-rw-r--r--wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java44
130 files changed, 1707 insertions, 423 deletions
diff --git a/api/current.txt b/api/current.txt
index 10d55f5cb39a..0002a0cba9cf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -48997,6 +48997,7 @@ package android.view {
method public boolean[] hasKeys(int...);
method public boolean hasMicrophone();
method public boolean isEnabled();
+ method public boolean isExternal();
method public boolean isVirtual();
method public boolean supportsSource(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -52612,7 +52613,6 @@ package android.view.animation {
public abstract class Animation implements java.lang.Cloneable {
ctor public Animation();
ctor public Animation(android.content.Context, android.util.AttributeSet);
- method public void addAnimationListener(android.view.animation.Animation.AnimationListener);
method protected void applyTransformation(float, android.view.animation.Transformation);
method public void cancel();
method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
@@ -52637,7 +52637,6 @@ package android.view.animation {
method public void initialize(int, int, int, int);
method public boolean isFillEnabled();
method public boolean isInitialized();
- method public void removeAnimationListener(android.view.animation.Animation.AnimationListener);
method public void reset();
method protected float resolveSize(int, float, int, int);
method public void restrictDuration(long);
@@ -55870,11 +55869,16 @@ package android.widget {
method public boolean executeKeyEvent(android.view.KeyEvent);
method public void fling(int);
method public boolean fullScroll(int);
+ method @ColorInt public int getLeftEdgeEffectColor();
method public int getMaxScrollAmount();
+ method @ColorInt public int getRightEdgeEffectColor();
method public boolean isFillViewport();
method public boolean isSmoothScrollingEnabled();
method public boolean pageScroll(int);
+ method public void setEdgeEffectColor(@ColorInt int);
method public void setFillViewport(boolean);
+ method public void setLeftEdgeEffectColor(@ColorInt int);
+ method public void setRightEdgeEffectColor(@ColorInt int);
method public void setSmoothScrollingEnabled(boolean);
method public final void smoothScrollBy(int, int);
method public final void smoothScrollTo(int, int);
@@ -56673,13 +56677,18 @@ package android.widget {
method public boolean executeKeyEvent(android.view.KeyEvent);
method public void fling(int);
method public boolean fullScroll(int);
+ method @ColorInt public int getBottomEdgeEffectColor();
method public int getMaxScrollAmount();
+ method @ColorInt public int getTopEdgeEffectColor();
method public boolean isFillViewport();
method public boolean isSmoothScrollingEnabled();
method public boolean pageScroll(int);
method public void scrollToDescendant(android.view.View);
+ method public void setBottomEdgeEffectColor(@ColorInt int);
+ method public void setEdgeEffectColor(@ColorInt int);
method public void setFillViewport(boolean);
method public void setSmoothScrollingEnabled(boolean);
+ method public void setTopEdgeEffectColor(@ColorInt int);
method public final void smoothScrollBy(int, int);
method public final void smoothScrollTo(int, int);
}
@@ -61200,9 +61209,9 @@ package java.lang.invoke {
method public String getName();
method public int getReferenceKind();
method public default boolean isVarArgs();
- method public static boolean refKindIsField(int);
- method public static boolean refKindIsValid(int);
- method public static String refKindName(int);
+ method @Deprecated public static boolean refKindIsField(int);
+ method @Deprecated public static boolean refKindIsValid(int);
+ method @Deprecated public static String refKindName(int);
method public static String referenceKindToString(int);
method public <T extends java.lang.reflect.Member> T reflectAs(Class<T>, java.lang.invoke.MethodHandles.Lookup);
method public static String toString(int, Class<?>, String, java.lang.invoke.MethodType);
diff --git a/api/system-current.txt b/api/system-current.txt
index c9b8c3867e59..7babf568bdb9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -205,6 +205,7 @@ package android {
}
public static final class R.attr {
+ field public static final int allowClearUserDataOnFailedRestore = 16844198; // 0x10105a6
field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2
field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
@@ -1150,7 +1151,7 @@ package android.app.usage {
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 public int getUsageSource();
- method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, 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[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
@@ -5786,6 +5787,11 @@ package android.provider {
field public static final String NAMESPACE = "runtime_native_boot";
}
+ public static interface DeviceConfig.Scheduler {
+ field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
+ field public static final String NAMESPACE = "scheduler";
+ }
+
public static interface DeviceConfig.Storage {
field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
field public static final String NAMESPACE = "storage";
diff --git a/api/test-current.txt b/api/test-current.txt
index b2ead4ab2464..695401164089 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1813,7 +1813,6 @@ package android.provider {
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
- field public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags";
field public static final String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
field public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS = "captive_portal_fallback_probe_specs";
field public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
@@ -2694,6 +2693,7 @@ package android.view.autofill {
public final class AutofillManager {
method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
+ field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7ddb783d71e1..458e0f5788dc 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -297,6 +297,7 @@ message Atom {
NumBiometricsEnrolled num_faces_enrolled = 10048;
RoleHolder role_holder = 10049;
DangerousPermissionState dangerous_permission_state = 10050;
+ TrainInfo train_info = 10051;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -5503,3 +5504,20 @@ message DeviceIdentifierAccessDenied {
// True if the package is privileged.
optional bool is_priv_app = 4;
}
+
+/**
+ * Potential experiment ids that goes with a train install.
+ */
+message TrainExperimentIds {
+ repeated int64 experiment_id = 1;
+}
+
+/**
+ * Pulls the ongoing mainline install train version code.
+ * Pulled from StatsCompanionService
+ */
+message TrainInfo {
+ optional int64 train_version_code = 1;
+
+ optional TrainExperimentIds train_experiment_id = 2;
+}
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 2999b649a509..ea3f3b32b0c4 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -511,6 +511,7 @@ private:
FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
FRIEND_TEST(StatsdStatsTest, TestSystemServerCrash);
FRIEND_TEST(StatsdStatsTest, TestPullAtomStats);
+ FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats);
};
} // namespace statsd
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 6069516e9666..92aa998d9720 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -278,6 +278,39 @@ TEST(StatsdStatsTest, TestPullAtomStats) {
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
}
+TEST(StatsdStatsTest, TestAtomMetricsStats) {
+ StatsdStats stats;
+ time_t now = time(nullptr);
+ // old event, we get it from the stats buffer. should be ignored.
+ stats.noteBucketDropped(1000L);
+
+ stats.noteBucketBoundaryDelayNs(1000L, -1L);
+ stats.noteBucketBoundaryDelayNs(1000L, -10L);
+ stats.noteBucketBoundaryDelayNs(1000L, 2L);
+
+ stats.noteBucketBoundaryDelayNs(1001L, 1L);
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+
+ EXPECT_EQ(2, report.atom_metric_stats().size());
+
+ auto atomStats = report.atom_metric_stats(0);
+ EXPECT_EQ(1000L, atomStats.metric_id());
+ EXPECT_EQ(1L, atomStats.bucket_dropped());
+ EXPECT_EQ(-10L, atomStats.min_bucket_boundary_delay_ns());
+ EXPECT_EQ(2L, atomStats.max_bucket_boundary_delay_ns());
+
+ auto atomStats2 = report.atom_metric_stats(1);
+ EXPECT_EQ(1001L, atomStats2.metric_id());
+ EXPECT_EQ(0L, atomStats2.bucket_dropped());
+ EXPECT_EQ(0L, atomStats2.min_bucket_boundary_delay_ns());
+ EXPECT_EQ(1L, atomStats2.max_bucket_boundary_delay_ns());
+}
+
TEST(StatsdStatsTest, TestAnomalyMonitor) {
StatsdStats stats;
stats.noteRegisteredAnomalyAlarmChanged();
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 51397a243420..dc5bdc673249 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -745,7 +745,11 @@ public final class UsageStatsManager {
* Registering an {@code observerId} that was already registered will override the previous one.
* No more than 1000 unique {@code observerId} may be registered by a single uid
* at any one time.
- * A limit may be unregistered via {@link #unregisterAppUsageLimitObserver}
+ * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via
+ * {@link #unregisterAppUsageLimitObserver}.
+ * <p>
+ * Note: usage limits are not persisted in the system and are cleared on reboots. Callers
+ * must reset any limits that they need on reboots.
* <p>
* This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here
* will be visible to the launcher so that it can report the limit to the user and how much
@@ -757,12 +761,15 @@ public final class UsageStatsManager {
* @param observedEntities The list of packages and token to observe for usage time. Cannot be
* null and must include at least one package or token.
* @param timeLimit The total time the set of apps can be in the foreground before the
- * callbackIntent is delivered. Must be at least one minute.
+ * callbackIntent is delivered. Must be at least one minute. Note: a limit of
+ * 0 can be set to indicate that the user has already exhausted the limit for
+ * a group, in which case, the given {@code callbackIntent} will be ignored.
* @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
- * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
+ * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
* exceeded by the group of apps. The delivered Intent will also contain
* the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
- * {@link #EXTRA_TIME_USED}. Cannot be null.
+ * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
+ * being registered with a {@code timeLimit} of 0.
* @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
* permissions.
* @hide
@@ -772,7 +779,7 @@ public final class UsageStatsManager {
android.Manifest.permission.SUSPEND_APPS,
android.Manifest.permission.OBSERVE_APP_USAGE})
public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
- long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
+ long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) {
try {
mService.registerAppUsageLimitObserver(observerId, observedEntities,
timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b27c5dc1b457..6c6fcb2ea558 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -650,6 +650,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_USE_EMBEDDED_DEX = 1 << 25;
+ /**
+ * Value for {@link #privateFlags}: indicates whether this application's data will be cleared
+ * on a failed restore.
+ *
+ * <p>Comes from the
+ * android.R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore attribute
+ * of the &lt;application&gt; tag.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1 << 26;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -676,6 +688,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
PRIVATE_FLAG_VENDOR,
PRIVATE_FLAG_VIRTUAL_PRELOAD,
PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,
+ PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlags {}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 96b6eb527002..0abd5eaaf2aa 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3747,6 +3747,13 @@ public class PackageParser {
ai.privateFlags |= PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable
+ .AndroidManifestApplication_allowClearUserDataOnFailedRestore,
+ true)) {
+ ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE;
+ }
+
ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
ai.minAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_minAspectRatio, 0);
diff --git a/core/java/android/hardware/display/ColorDisplayManager.java b/core/java/android/hardware/display/ColorDisplayManager.java
index 27f0b0425ec3..f413d7cc92af 100644
--- a/core/java/android/hardware/display/ColorDisplayManager.java
+++ b/core/java/android/hardware/display/ColorDisplayManager.java
@@ -365,6 +365,17 @@ public final class ColorDisplayManager {
}
/**
+ * Gets whether or not a non-default saturation level is currently applied to the display.
+ *
+ * @return {@code true} if the display is not at full saturation
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS)
+ public boolean isSaturationActivated() {
+ return mManager.isSaturationActivated();
+ }
+
+ /**
* Set the level of color saturation to apply to a specific app.
*
* @param packageName the package name of the app whose windows should be desaturated
@@ -588,6 +599,14 @@ public final class ColorDisplayManager {
}
}
+ boolean isSaturationActivated() {
+ try {
+ return mCdm.isSaturationActivated();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
boolean setAppSaturationLevel(String packageName, int saturationLevel) {
try {
return mCdm.setAppSaturationLevel(packageName, saturationLevel);
diff --git a/core/java/android/hardware/display/IColorDisplayManager.aidl b/core/java/android/hardware/display/IColorDisplayManager.aidl
index 30e76cfe2787..88b59a6eb8db 100644
--- a/core/java/android/hardware/display/IColorDisplayManager.aidl
+++ b/core/java/android/hardware/display/IColorDisplayManager.aidl
@@ -24,6 +24,7 @@ interface IColorDisplayManager {
boolean setSaturationLevel(int saturationLevel);
boolean setAppSaturationLevel(String packageName, int saturationLevel);
+ boolean isSaturationActivated();
int getTransformCapabilities();
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 629289bb7a45..0384faa88be5 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1093,6 +1093,12 @@ public class FileUtils {
return buildUniqueFileWithExtension(parent, parts[0], parts[1]);
}
+ /** {@hide} */
+ public static File buildNonUniqueFile(File parent, String mimeType, String displayName) {
+ final String[] parts = splitFileName(mimeType, displayName);
+ return buildFile(parent, parts[0], parts[1]);
+ }
+
/**
* Generates a unique file name under the given parent directory, keeping
* any extension intact.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 41d3cbb88f5c..8254e33bcadd 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -308,6 +308,25 @@ public final class DeviceConfig {
String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
}
+ /**
+ * Namespace for system scheduler related features. These features will be applied
+ * immediately upon change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface Scheduler {
+ String NAMESPACE = "scheduler";
+
+ /**
+ * Flag for enabling fast metrics collection in system scheduler.
+ * A flag value of '' or '0' means the fast metrics collection is not
+ * enabled. Otherwise fast metrics collection is enabled and flag value
+ * is the order id.
+ */
+ String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
+ }
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index de84e713a6f7..3747ec6f4003 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13285,17 +13285,6 @@ public final class Settings {
public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets";
/**
- * Used to emulate Smart Suggestion for Augmented Autofill during development
- *
- * <p>Valid values: {@code 0x1} for IME and/or {@code 0x2} for popup window.
- *
- * @hide
- */
- @TestApi
- public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS =
- "autofill_smart_suggestion_emulation_flags";
-
- /**
* Exemptions to the hidden API blacklist.
*
* @hide
diff --git a/core/java/android/service/textclassifier/TEST_MAPPING b/core/java/android/service/textclassifier/TEST_MAPPING
new file mode 100644
index 000000000000..ccf26315852d
--- /dev/null
+++ b/core/java/android/service/textclassifier/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/core/java/android/view/textclassifier"
+ }
+ ]
+}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7295259a0f89..868a9de93972 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -22,6 +22,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
+import android.os.Build;
import android.os.NullVibrator;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,7 +55,7 @@ public final class InputDevice implements Parcelable {
private final int mProductId;
private final String mDescriptor;
private final InputDeviceIdentifier mIdentifier;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private final boolean mIsExternal;
private final int mSources;
private final int mKeyboardType;
@@ -608,10 +609,7 @@ public final class InputDevice implements Parcelable {
* peripheral bus), otherwise it is built-in.
*
* @return True if the device is external.
- *
- * @hide
*/
- @UnsupportedAppUsage
public boolean isExternal() {
return mIsExternal;
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 3f18d8b46e2a..39b6876d86c7 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -95,7 +95,12 @@ public abstract class LayoutInflater {
protected final Context mContext;
// these are optional, set by the caller
- @UnsupportedAppUsage
+ /**
+ * If any developer has desire to change this value, they should instead use
+ * {@link #cloneInContext(Context)} and set the new factory in thew newly-created
+ * LayoutInflater.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mFactorySet;
@UnsupportedAppUsage
private Factory mFactory;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3f2795ba1e00..83df33e9742e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4030,8 +4030,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* {@hide}
+ *
+ * Not available for general use. If you need help, hang up and then dial one of the following
+ * public APIs:
+ *
+ * @see #isAttachedToWindow() for current attach state
+ * @see #onAttachedToWindow() for subclasses performing work when becoming attached
+ * @see #onDetachedFromWindow() for subclasses performing work when becoming detached
+ * @see OnAttachStateChangeListener for other code performing work on attach/detach
+ * @see #getHandler() for posting messages to this view's UI thread/looper
+ * @see #getParent() for interacting with the parent chain
+ * @see #getWindowToken() for the current window token
+ * @see #getRootView() for the view at the root of the attached hierarchy
+ * @see #getDisplay() for the Display this view is presented on
+ * @see #getRootWindowInsets() for the current insets applied to the whole attached window
+ * @see #hasWindowFocus() for whether the attached window is currently focused
+ * @see #getWindowVisibility() for checking the visibility of the attached window
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
AttachInfo mAttachInfo;
/**
@@ -28193,18 +28209,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
View mViewRequestingLayout;
/**
- * Used to track views that need (at least) a partial relayout at their current size
- * during the next traversal.
- */
- List<View> mPartialLayoutViews = new ArrayList<>();
-
- /**
- * Swapped with mPartialLayoutViews during layout to avoid concurrent
- * modification. Lazily assigned during ViewRootImpl layout.
- */
- List<View> mEmptyPartialLayoutViews;
-
- /**
* Used to track the identity of the current drag operation.
*/
IBinder mDragToken;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d2b40f75a6a8..aaf1d110c8c2 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -703,7 +703,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private void initFromAttributes(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup,
+ defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ViewGroup, attrs, a, defStyleAttr,
defStyleRes);
final int N = a.getIndexCount();
diff --git a/core/java/android/view/ViewStub.java b/core/java/android/view/ViewStub.java
index e9d1b8784914..9ca16327844c 100644
--- a/core/java/android/view/ViewStub.java
+++ b/core/java/android/view/ViewStub.java
@@ -108,6 +108,9 @@ public final class ViewStub extends View {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.ViewStub, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr,
+ defStyleRes);
+
mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index dfd9a2e95cb7..e0950948afb8 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -23,6 +23,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
+import android.os.Build;
import android.os.Handler;
import android.os.SystemProperties;
import android.util.AttributeSet;
@@ -30,9 +31,6 @@ import android.util.TypedValue;
import dalvik.system.CloseGuard;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Abstraction for an Animation that can be applied to Views, Surfaces, or
* other objects. See the {@link android.view.animation animation package
@@ -187,15 +185,12 @@ public abstract class Animation implements Cloneable {
/**
* An animation listener to be notified when the animation starts, ends or repeats.
*/
- @UnsupportedAppUsage
+ // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet
+ // and add your new listener to that set
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981)
private AnimationListener mListener;
/**
- * A list of animation listeners to be notified when the animation starts, ends or repeats.
- */
- private List<AnimationListener> mListeners;
-
- /**
* Desired Z order mode during animation.
*/
private int mZAdjustment;
@@ -833,7 +828,7 @@ public abstract class Animation implements Cloneable {
}
private boolean hasAnimationListener() {
- return mListener != null || (mListeners != null && !mListeners.isEmpty());
+ return mListener != null;
}
/**
@@ -848,32 +843,6 @@ public abstract class Animation implements Cloneable {
}
/**
- * <p>Adds an animation listener to this animation. The animation listener
- * is notified of animation events such as the end of the animation or the
- * repetition of the animation.</p>
- *
- * @param listener the animation listener to be notified
- */
- public void addAnimationListener(AnimationListener listener) {
- if (mListeners == null) {
- mListeners = new ArrayList<>(1);
- }
- mListeners.add(listener);
- }
-
- /**
- * <p>Removes an animation listener that has been added with
- * {@link #addAnimationListener(AnimationListener)}.</p>
- *
- * @param listener the animation listener to be removed
- */
- public void removeAnimationListener(AnimationListener listener) {
- if (mListeners != null) {
- mListeners.remove(listener);
- }
- }
-
- /**
* Gurantees that this animation has an interpolator. Will use
* a AccelerateDecelerateInterpolator is nothing else was specified.
*/
@@ -1003,33 +972,18 @@ public abstract class Animation implements Cloneable {
if (mListener != null) {
mListener.onAnimationStart(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationStart(this);
- }
- }
}
void dispatchAnimationRepeat() {
if (mListener != null) {
mListener.onAnimationRepeat(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationRepeat(this);
- }
- }
}
void dispatchAnimationEnd() {
if (mListener != null) {
mListener.onAnimationEnd(this);
}
- if (mListeners != null && !mListeners.isEmpty()) {
- for (AnimationListener listener : mListeners) {
- listener.onAnimationEnd(this);
- }
- }
}
/**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 83fc017373a6..397fc6610d5a 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -17,7 +17,6 @@
package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
-import static android.util.DebugUtils.flagsToString;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
@@ -354,6 +353,15 @@ public final class AutofillManager {
public @interface SmartSuggestionMode {}
/**
+ * Used to emulate Smart Suggestion for Augmented Autofill during development
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
+ "smart_suggestion_supported_modes";
+
+ /**
* Makes an authentication id from a request id and a dataset id.
*
* @param requestId The request id.
@@ -2347,7 +2355,7 @@ public final class AutofillManager {
/** @hide */
public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) {
- return flagsToString(AutofillManager.class, "FLAG_SMART_SUGGESTION_", flags);
+ return (flags == FLAG_SMART_SUGGESTION_SYSTEM) ? "1-SYSTEM" : flags + "-UNSUPPORTED";
}
@GuardedBy("mLock")
diff --git a/core/java/android/view/textclassifier/TEST_MAPPING b/core/java/android/view/textclassifier/TEST_MAPPING
new file mode 100644
index 000000000000..0d3c3465f2d6
--- /dev/null
+++ b/core/java/android/view/textclassifier/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.textclassifier"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsViewTestCases",
+ "options": [
+ {
+ "include-filter": "android.view.textclassifier.cts"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9d7a482aa611..4b7c393b1b96 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -657,7 +657,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private Runnable mClearScrollingCache;
Runnable mPositionScrollAfterLayout;
private int mMinimumVelocity;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740)
private int mMaximumVelocity;
private float mVelocityScale = 1.0f;
@@ -875,6 +875,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AbsListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AbsListView, attrs, a, defStyleAttr,
+ defStyleRes);
final Drawable selector = a.getDrawable(R.styleable.AbsListView_listSelector);
if (selector != null) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index c8be1d66ed4a..cd5f2e222b39 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -107,6 +107,8 @@ public abstract class AbsSeekBar extends ProgressBar {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SeekBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SeekBar, attrs, a, defStyleAttr,
+ defStyleRes);
final Drawable thumb = a.getDrawable(R.styleable.SeekBar_thumb);
setThumb(thumb);
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 816c9499e292..3dcba48b8dc8 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -82,6 +82,8 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AbsSpinner, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AbsSpinner, attrs, a, defStyleAttr,
+ defStyleRes);
final CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
if (entries != null) {
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 58715eefc25e..89ea0747b532 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -232,6 +232,8 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
TypedArray attributesArray = context.obtainStyledAttributes(attrs,
R.styleable.ActivityChooserView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ActivityChooserView, attrs,
+ attributesArray, defStyleAttr, defStyleRes);
mInitialActivityCount = attributesArray.getInt(
R.styleable.ActivityChooserView_initialActivityCount,
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 6f293684ad3c..5174c1a34fcd 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -180,6 +180,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AdapterViewAnimator, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewAnimator,
+ attrs, a, defStyleAttr, defStyleRes);
+
int resource = a.getResourceId(
com.android.internal.R.styleable.AdapterViewAnimator_inAnimation, 0);
if (resource > 0) {
diff --git a/core/java/android/widget/AdapterViewFlipper.java b/core/java/android/widget/AdapterViewFlipper.java
index 18d74705773a..065089f53633 100644
--- a/core/java/android/widget/AdapterViewFlipper.java
+++ b/core/java/android/widget/AdapterViewFlipper.java
@@ -69,6 +69,8 @@ public class AdapterViewFlipper extends AdapterViewAnimator {
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.AdapterViewFlipper, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AdapterViewFlipper,
+ attrs, a, defStyleAttr, defStyleRes);
mFlipInterval = a.getInt(
com.android.internal.R.styleable.AdapterViewFlipper_flipInterval, DEFAULT_INTERVAL);
mAutoStart = a.getBoolean(
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 795b03493efb..339947ac8d5a 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -81,6 +81,8 @@ public class AnalogClock extends View {
final Resources r = context.getResources();
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
+ attrs, a, defStyleAttr, defStyleRes);
mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial);
if (mDial == null) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7ed7aa293f21..904a86261e6c 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -227,6 +227,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
+ attrs, a, defStyleAttr, defStyleRes);
if (popupTheme != null) {
mPopupContext = new ContextThemeWrapper(context, popupTheme);
@@ -245,6 +247,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe
if (mPopupContext != context) {
pa = mPopupContext.obtainStyledAttributes(
attrs, R.styleable.AutoCompleteTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.AutoCompleteTextView,
+ attrs, a, defStyleAttr, defStyleRes);
} else {
pa = a;
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 6c74c8c24c44..b552aa6c85c4 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -112,6 +112,8 @@ public class CalendarView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CalendarView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CalendarView,
+ attrs, a, defStyleAttr, defStyleRes);
final int mode = a.getInt(R.styleable.CalendarView_calendarViewMode, MODE_HOLO);
a.recycle();
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index b7fdcbe2b399..99440f862871 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -90,6 +90,8 @@ public class CheckedTextView extends TextView implements Checkable {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.CheckedTextView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CheckedTextView,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(R.styleable.CheckedTextView_checkMark);
if (d != null) {
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 66c35d903366..0b67cad0112b 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -116,6 +116,8 @@ public class Chronometer extends TextView {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Chronometer, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Chronometer,
+ attrs, a, defStyleAttr, defStyleRes);
setFormat(a.getString(R.styleable.Chronometer_format));
setCountDown(a.getBoolean(R.styleable.Chronometer_countDown, false));
a.recycle();
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index a0f93da90847..3cfd373c2906 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -100,6 +100,8 @@ public abstract class CompoundButton extends Button implements Checkable {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.CompoundButton, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.CompoundButton,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(com.android.internal.R.styleable.CompoundButton_button);
if (d != null) {
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index cca951ca9298..ada4f00256eb 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -161,6 +161,8 @@ public class DatePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.DatePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final boolean isDialogMode = a.getBoolean(R.styleable.DatePicker_dialogMode, false);
final int requestedMode = a.getInt(R.styleable.DatePicker_datePickerMode, MODE_SPINNER);
final int firstDayOfWeek = a.getInt(R.styleable.DatePicker_firstDayOfWeek, 0);
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index f712d5fa65ca..67fef13d23f2 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -82,6 +82,8 @@ class DayPickerView extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CalendarView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.CalendarView,
+ attrs, a, defStyleAttr, defStyleRes);
final int firstDayOfWeek = a.getInt(R.styleable.CalendarView_firstDayOfWeek,
LocaleData.get(Locale.getDefault()).firstDayOfWeek);
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 33d15394332e..2cc013ec4f78 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -242,6 +242,8 @@ public class ExpandableListView extends ListView {
final TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.ExpandableListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ExpandableListView,
+ attrs, a, defStyleAttr, defStyleRes);
mGroupIndicator = a.getDrawable(
com.android.internal.R.styleable.ExpandableListView_groupIndicator);
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 5723b9467aa2..3570c79430a4 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -100,6 +100,8 @@ public class FrameLayout extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.FrameLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.FrameLayout,
+ attrs, a, defStyleAttr, defStyleRes);
if (a.getBoolean(R.styleable.FrameLayout_measureAllChildren, false)) {
setMeasureAllChildren(true);
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index d6a0ae48cc13..64192aaff1cf 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -213,6 +213,8 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Gallery, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Gallery,
+ attrs, a, defStyleAttr, defStyleRes);
int index = a.getInt(com.android.internal.R.styleable.Gallery_gravity, -1);
if (index >= 0) {
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c8abf18f88f9..1c8bb0470e2e 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -303,6 +303,8 @@ public class GridLayout extends ViewGroup {
mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.GridLayout,
+ attrs, a, defStyleAttr, defStyleRes);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index bbbe369d5262..a6129b04d14f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -150,6 +150,8 @@ public class GridView extends AbsListView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.GridView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.GridView,
+ attrs, a, defStyleAttr, defStyleRes);
int hSpacing = a.getDimensionPixelOffset(
R.styleable.GridView_horizontalSpacing, 0);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 1c5f837728a0..25cfdc7e4411 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -80,10 +81,24 @@ public class HorizontalScrollView extends FrameLayout {
private final Rect mTempRect = new Rect();
@UnsupportedAppUsage
private OverScroller mScroller;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowLeft;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowRight;
+ /**
+ * Tracks the state of the left edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124053130)
+ private EdgeEffect mEdgeGlowLeft = new EdgeEffect(getContext());
+
+ /**
+ * Tracks the state of the bottom edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052619)
+ private EdgeEffect mEdgeGlowRight = new EdgeEffect(getContext());
/**
* Position of the last motion event.
@@ -175,6 +190,8 @@ public class HorizontalScrollView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, android.R.styleable.HorizontalScrollView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, android.R.styleable.HorizontalScrollView,
+ attrs, a, defStyleAttr, defStyleRes);
setFillViewport(a.getBoolean(android.R.styleable.HorizontalScrollView_fillViewport, false));
@@ -216,6 +233,74 @@ public class HorizontalScrollView extends FrameLayout {
}
/**
+ * Sets the edge effect color for both left and right edge effects.
+ *
+ * @param color The color for the edge effects.
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setEdgeEffectColor(@ColorInt int color) {
+ setLeftEdgeEffectColor(color);
+ setRightEdgeEffectColor(color);
+ }
+
+ /**
+ * Sets the right edge effect color.
+ *
+ * @param color The color for the right edge effect.
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setRightEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowRight.setColor(color);
+ }
+
+ /**
+ * Sets the left edge effect color.
+ *
+ * @param color The color for the left edge effect.
+ * @see #setRightEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ * @see #getRightEdgeEffectColor()
+ */
+ public void setLeftEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowLeft.setColor(color);
+ }
+
+ /**
+ * Returns the left edge effect color.
+ *
+ * @return The left edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getRightEdgeEffectColor()
+ */
+ @ColorInt
+ public int getLeftEdgeEffectColor() {
+ return mEdgeGlowLeft.getColor();
+ }
+
+ /**
+ * Returns the right edge effect color.
+ *
+ * @return The right edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setLeftEdgeEffectColor(int)
+ * @see #setRightEdgeEffectColor(int)
+ * @see #getLeftEdgeEffectColor()
+ */
+ @ColorInt
+ public int getRightEdgeEffectColor() {
+ return mEdgeGlowRight.getColor();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
@@ -665,7 +750,7 @@ public class HorizontalScrollView extends FrameLayout {
mEdgeGlowLeft.onRelease();
}
}
- if (mEdgeGlowLeft != null
+ if (shouldDisplayEdgeEffects()
&& (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished())) {
postInvalidateOnAnimation();
}
@@ -693,7 +778,7 @@ public class HorizontalScrollView extends FrameLayout {
mIsBeingDragged = false;
recycleVelocityTracker();
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
@@ -708,7 +793,7 @@ public class HorizontalScrollView extends FrameLayout {
mIsBeingDragged = false;
recycleVelocityTracker();
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowLeft.onRelease();
mEdgeGlowRight.onRelease();
}
@@ -1650,26 +1735,15 @@ public class HorizontalScrollView extends FrameLayout {
}
}
- @Override
- public void setOverScrollMode(int mode) {
- if (mode != OVER_SCROLL_NEVER) {
- if (mEdgeGlowLeft == null) {
- Context context = getContext();
- mEdgeGlowLeft = new EdgeEffect(context);
- mEdgeGlowRight = new EdgeEffect(context);
- }
- } else {
- mEdgeGlowLeft = null;
- mEdgeGlowRight = null;
- }
- super.setOverScrollMode(mode);
+ private boolean shouldDisplayEdgeEffects() {
+ return getOverScrollMode() != OVER_SCROLL_NEVER;
}
@SuppressWarnings({"SuspiciousNameCombination"})
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mEdgeGlowLeft != null) {
+ if (shouldDisplayEdgeEffects()) {
final int scrollX = mScrollX;
if (!mEdgeGlowLeft.isFinished()) {
final int restoreCount = canvas.save();
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 800b19cdd77e..9ae62ef8ab7a 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -200,6 +200,8 @@ public class ImageView extends View {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ImageView,
+ attrs, a, defStyleAttr, defStyleRes);
final Drawable d = a.getDrawable(R.styleable.ImageView_src);
if (d != null) {
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 64769b5337df..e833df9d498a 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -264,6 +264,8 @@ public class LinearLayout extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.LinearLayout,
+ attrs, a, defStyleAttr, defStyleRes);
int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1);
if (index >= 0) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 311f8968150c..2aa019b5d0f4 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -236,6 +236,8 @@ public class ListView extends AbsListView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ListView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ListView,
+ attrs, a, defStyleAttr, defStyleRes);
final CharSequence[] entries = a.getTextArray(R.styleable.ListView_entries);
if (entries != null) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 157992a98a4a..89bb2738b899 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -639,6 +639,8 @@ public class NumberPicker extends LinearLayout {
// process style attributes
final TypedArray attributesArray = context.obtainStyledAttributes(
attrs, R.styleable.NumberPicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.NumberPicker,
+ attrs, attributesArray, defStyleAttr, defStyleRes);
final int layoutResId = attributesArray.getResourceId(
R.styleable.NumberPicker_internalLayout, DEFAULT_LAYOUT_RESOURCE_ID);
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 30df5b5a09a3..29f070ed5a65 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -203,7 +203,7 @@ public class ProgressBar extends View {
private int mDuration;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private boolean mIndeterminate;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 124049927)
private boolean mOnlyIndeterminate;
private Transformation mTransformation;
private AlphaAnimation mAnimation;
@@ -267,6 +267,8 @@ public class ProgressBar extends View {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.ProgressBar,
+ attrs, a, defStyleAttr, defStyleRes);
mNoInvalidate = true;
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 757a4ca04871..f3600b0de22b 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -404,6 +404,8 @@ public class RadialTimePickerView extends View {
final Context context = getContext();
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.TimePicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TimePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final ColorStateList numbersTextColor = a.getColorStateList(
R.styleable.TimePicker_numbersTextColor);
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index ab12eaccad45..c62c16c7e719 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -98,6 +98,8 @@ public class RadioGroup extends LinearLayout {
// XML layout file
TypedArray attributes = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.RadioGroup, com.android.internal.R.attr.radioButtonStyle, 0);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.RadioGroup,
+ attrs, attributes, com.android.internal.R.attr.radioButtonStyle, 0);
int value = attributes.getResourceId(R.styleable.RadioGroup_checkedButton, View.NO_ID);
if (value != View.NO_ID) {
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 9f9fdee46fdf..3cf3d9102d21 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -93,6 +93,8 @@ public class RatingBar extends AbsSeekBar {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.RatingBar, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.RatingBar,
+ attrs, a, defStyleAttr, defStyleRes);
final int numStars = a.getInt(R.styleable.RatingBar_numStars, mNumStars);
setIsIndicator(a.getBoolean(R.styleable.RatingBar_isIndicator, !mIsUserSeekable));
final float rating = a.getFloat(R.styleable.RatingBar_rating, -1);
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 556bfd19f942..109c0a432c1b 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -257,6 +257,8 @@ public class RelativeLayout extends ViewGroup {
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.RelativeLayout, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.RelativeLayout,
+ attrs, a, defStyleAttr, defStyleRes);
mIgnoreGravity = a.getResourceId(R.styleable.RelativeLayout_ignoreGravity, View.NO_ID);
mGravity = a.getInt(R.styleable.RelativeLayout_gravity, mGravity);
a.recycle();
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index c3609038b08f..7e72c6a4789c 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -89,10 +90,25 @@ public class ScrollView extends FrameLayout {
private final Rect mTempRect = new Rect();
@UnsupportedAppUsage
private OverScroller mScroller;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowTop;
- @UnsupportedAppUsage
- private EdgeEffect mEdgeGlowBottom;
+ /**
+ * Tracks the state of the top edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768600)
+ private EdgeEffect mEdgeGlowTop = new EdgeEffect(getContext());
+
+ /**
+ * Tracks the state of the bottom edge glow.
+ *
+ * Even though this field is practically final, we cannot make it final because there are apps
+ * setting it via reflection and they need to keep working until they target Q.
+ */
+ @NonNull
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769386)
+ private EdgeEffect mEdgeGlowBottom = new EdgeEffect(getContext());
/**
* Position of the last motion event.
@@ -201,6 +217,8 @@ public class ScrollView extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ScrollView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ScrollView,
+ attrs, a, defStyleAttr, defStyleRes);
setFillViewport(a.getBoolean(R.styleable.ScrollView_fillViewport, false));
@@ -247,6 +265,74 @@ public class ScrollView extends FrameLayout {
}
/**
+ * Sets the edge effect color for both top and bottom edge effects.
+ *
+ * @param color The color for the edge effects.
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setEdgeEffectColor(@ColorInt int color) {
+ setTopEdgeEffectColor(color);
+ setBottomEdgeEffectColor(color);
+ }
+
+ /**
+ * Sets the bottom edge effect color.
+ *
+ * @param color The color for the bottom edge effect.
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setBottomEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowBottom.setColor(color);
+ }
+
+ /**
+ * Sets the top edge effect color.
+ *
+ * @param color The color for the top edge effect.
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #setEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ * @see #getBottomEdgeEffectColor()
+ */
+ public void setTopEdgeEffectColor(@ColorInt int color) {
+ mEdgeGlowTop.setColor(color);
+ }
+
+ /**
+ * Returns the top edge effect color.
+ *
+ * @return The top edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getBottomEdgeEffectColor()
+ */
+ @ColorInt
+ public int getTopEdgeEffectColor() {
+ return mEdgeGlowTop.getColor();
+ }
+
+ /**
+ * Returns the bottom edge effect color.
+ *
+ * @return The bottom edge effect color.
+ * @see #setEdgeEffectColor(int)
+ * @see #setTopEdgeEffectColor(int)
+ * @see #setBottomEdgeEffectColor(int)
+ * @see #getTopEdgeEffectColor()
+ */
+ @ColorInt
+ public int getBottomEdgeEffectColor() {
+ return mEdgeGlowBottom.getColor();
+ }
+
+ /**
* @return The maximum amount this scroll view will scroll in response to
* an arrow event.
*/
@@ -624,6 +710,10 @@ public class ScrollView extends FrameLayout {
return mIsBeingDragged;
}
+ private boolean shouldDisplayEdgeEffects() {
+ return getOverScrollMode() != OVER_SCROLL_NEVER;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
initVelocityTrackerIfNotExists();
@@ -732,7 +822,7 @@ public class ScrollView extends FrameLayout {
mEdgeGlowTop.onRelease();
}
}
- if (mEdgeGlowTop != null
+ if (shouldDisplayEdgeEffects()
&& (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
postInvalidateOnAnimation();
}
@@ -1670,7 +1760,7 @@ public class ScrollView extends FrameLayout {
recycleVelocityTracker();
- if (mEdgeGlowTop != null) {
+ if (shouldDisplayEdgeEffects()) {
mEdgeGlowTop.onRelease();
mEdgeGlowBottom.onRelease();
}
@@ -1700,21 +1790,6 @@ public class ScrollView extends FrameLayout {
}
@Override
- public void setOverScrollMode(int mode) {
- if (mode != OVER_SCROLL_NEVER) {
- if (mEdgeGlowTop == null) {
- Context context = getContext();
- mEdgeGlowTop = new EdgeEffect(context);
- mEdgeGlowBottom = new EdgeEffect(context);
- }
- } else {
- mEdgeGlowTop = null;
- mEdgeGlowBottom = null;
- }
- super.setOverScrollMode(mode);
- }
-
- @Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
return (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
}
@@ -1758,7 +1833,7 @@ public class ScrollView extends FrameLayout {
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mEdgeGlowTop != null) {
+ if (shouldDisplayEdgeEffects()) {
final int scrollY = mScrollY;
final boolean clipToPadding = getClipToPadding();
if (!mEdgeGlowTop.isFinished()) {
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index af3b8c0afe08..630c38a734bd 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -283,6 +283,8 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SearchView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SearchView,
+ attrs, a, defStyleAttr, defStyleRes);
final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
final int layoutResId = a.getResourceId(
diff --git a/core/java/android/widget/SlidingDrawer.java b/core/java/android/widget/SlidingDrawer.java
index 8011c3aef494..2ab2b2407a50 100644
--- a/core/java/android/widget/SlidingDrawer.java
+++ b/core/java/android/widget/SlidingDrawer.java
@@ -218,6 +218,8 @@ public class SlidingDrawer extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.SlidingDrawer, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.SlidingDrawer,
+ attrs, a, defStyleAttr, defStyleRes);
int orientation = a.getInt(R.styleable.SlidingDrawer_orientation, ORIENTATION_VERTICAL);
mVertical = orientation == ORIENTATION_VERTICAL;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index fb56d9739435..d6c657b4dc21 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -247,6 +247,8 @@ public class Spinner extends AbsSpinner implements OnClickListener {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.Spinner, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.Spinner,
+ attrs, a, defStyleAttr, defStyleRes);
if (popupTheme != null) {
mPopupContext = new ContextThemeWrapper(context, popupTheme);
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 6cc86b9b871c..5091eea1898d 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -176,6 +176,8 @@ public class StackView extends AdapterViewAnimator {
super(context, attrs, defStyleAttr, defStyleRes);
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.StackView, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.StackView,
+ attrs, a, defStyleAttr, defStyleRes);
mResOutColor = a.getColor(
com.android.internal.R.styleable.StackView_resOutColor, 0);
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index af4f0202fd6a..ea9cd421d438 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -239,6 +239,8 @@ public class Switch extends CompoundButton {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.Switch, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.Switch,
+ attrs, a, defStyleAttr, defStyleRes);
mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_thumb);
if (mThumbDrawable != null) {
mThumbDrawable.setCallback(this);
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index b1fcbc33bbc9..481704c80287 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -93,6 +93,8 @@ public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchMode
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TabWidget, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TabWidget,
+ attrs, a, defStyleAttr, defStyleRes);
mTabLayoutId = a.getResourceId(R.styleable.TabWidget_tabLayout, 0);
a.recycle();
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index a90741b48684..49a0f39b3bad 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -95,6 +95,8 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TabWidget, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TabWidget,
+ attrs, a, defStyleAttr, defStyleRes);
mDrawBottomStrips = a.getBoolean(R.styleable.TabWidget_tabStripEnabled, mDrawBottomStrips);
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 7f462cb3289b..616c4b51eca0 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -242,6 +242,8 @@ public class TextClock extends TextView {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TextClock, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TextClock,
+ attrs, a, defStyleAttr, defStyleRes);
try {
mFormat12 = a.getText(R.styleable.TextClock_format12Hour);
mFormat24 = a.getText(R.styleable.TextClock_format24Hour);
@@ -610,8 +612,16 @@ public class TextClock extends TextView {
resolver.registerContentObserver(uri, true,
mFormatChangeObserver, UserHandle.USER_ALL);
} else {
+ // UserHandle.myUserId() is needed. This class is supported by the
+ // remote views mechanism and as a part of that the remote views
+ // can be inflated by a context for another user without the app
+ // having interact users permission - just for loading resources.
+ // For example, when adding widgets from a managed profile to the
+ // home screen. Therefore, we register the ContentObserver with the user
+ // the app is running (e.g. the launcher) and not the user of the
+ // context (e.g. the widget's profile).
resolver.registerContentObserver(uri, true,
- mFormatChangeObserver);
+ mFormatChangeObserver, UserHandle.myUserId());
}
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d87600125a54..51eaa12aa314 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -664,7 +664,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@UnsupportedAppUsage
private CharWrapper mCharWrapper;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 124050217)
private Marquee mMarquee;
@UnsupportedAppUsage
private boolean mRestartMarquee;
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index b239ce638e68..97a8ade589d1 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -127,6 +127,8 @@ public class TimePicker extends FrameLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.TimePicker,
+ attrs, a, defStyleAttr, defStyleRes);
final boolean isDialogMode = a.getBoolean(R.styleable.TimePicker_dialogMode, false);
final int requestedMode = a.getInt(R.styleable.TimePicker_timePickerMode, MODE_SPINNER);
a.recycle();
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index bba6da6b7b4c..b76c2cafd912 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -48,6 +48,8 @@ public class ToggleButton extends CompoundButton {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ToggleButton, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.ToggleButton,
+ attrs, a, defStyleAttr, defStyleRes);
mTextOn = a.getText(com.android.internal.R.styleable.ToggleButton_textOn);
mTextOff = a.getText(com.android.internal.R.styleable.ToggleButton_textOff);
mDisabledAlpha = a.getFloat(com.android.internal.R.styleable.ToggleButton_disabledAlpha, 0.5f);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index a33c47d86673..f25109ee82df 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -237,6 +237,8 @@ public class Toolbar extends ViewGroup {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,
defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, R.styleable.Toolbar,
+ attrs, a, defStyleAttr, defStyleRes);
mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java
index 553b86e1f0c2..4c613a71a3ac 100644
--- a/core/java/android/widget/TwoLineListItem.java
+++ b/core/java/android/widget/TwoLineListItem.java
@@ -62,6 +62,8 @@ public class TwoLineListItem extends RelativeLayout {
final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.TwoLineListItem, defStyleAttr, defStyleRes);
+ saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TwoLineListItem,
+ attrs, a, defStyleAttr, defStyleRes);
a.recycle();
}
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index 2c272dea073b..7f4d8a2d0587 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -52,6 +52,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
public static final boolean ENABLED_DEFAULT = true;
public static final boolean DETAILED_TRACKING_DEFAULT = true;
public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 100;
+ public static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false;
+ public static final boolean DEFAULT_TRACK_DIRECT_CALLING_UID = true;
public static final int MAX_BINDER_CALL_STATS_COUNT_DEFAULT = 5000;
private static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
@@ -85,6 +87,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
private long mStartElapsedTime = SystemClock.elapsedRealtime();
private long mCallStatsCount = 0;
private boolean mAddDebugEntries = false;
+ private boolean mTrackDirectCallingUid = DEFAULT_TRACK_DIRECT_CALLING_UID;
+ private boolean mTrackScreenInteractive = DEFAULT_TRACK_SCREEN_INTERACTIVE;
private CachedDeviceState.Readonly mDeviceState;
private CachedDeviceState.TimeInStateStopwatch mBatteryStopwatch;
@@ -160,7 +164,12 @@ public class BinderCallsStats implements BinderInternal.Observer {
duration = 0;
latencyDuration = 0;
}
- final int callingUid = getCallingUid();
+ final boolean screenInteractive = mTrackScreenInteractive
+ ? mDeviceState.isScreenInteractive()
+ : OVERFLOW_SCREEN_INTERACTIVE;
+ final int callingUid = mTrackDirectCallingUid
+ ? getCallingUid()
+ : OVERFLOW_DIRECT_CALLING_UID;
synchronized (mLock) {
// This was already checked in #callStart but check again while synchronized.
@@ -177,7 +186,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
final CallStat callStat = uidEntry.getOrCreate(
callingUid, s.binderClass, s.transactionCode,
- mDeviceState.isScreenInteractive(),
+ screenInteractive,
mCallStatsCount >= mMaxBinderCallStatsCount);
final boolean isNewCallStat = callStat.callCount == 0;
if (isNewCallStat) {
@@ -484,6 +493,30 @@ public class BinderCallsStats implements BinderInternal.Observer {
}
}
+ /**
+ * Whether to track the screen state.
+ */
+ public void setTrackScreenInteractive(boolean enabled) {
+ synchronized (mLock) {
+ if (enabled != mTrackScreenInteractive) {
+ mTrackScreenInteractive = enabled;
+ reset();
+ }
+ }
+ }
+
+ /**
+ * Whether to track direct caller uid.
+ */
+ public void setTrackDirectCallerUid(boolean enabled) {
+ synchronized (mLock) {
+ if (enabled != mTrackDirectCallingUid) {
+ mTrackDirectCallingUid = enabled;
+ reset();
+ }
+ }
+ }
+
public void setAddDebugEntries(boolean addDebugEntries) {
mAddDebugEntries = addDebugEntries;
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index b3d9ca7670b5..c059721eb2d3 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -39,6 +39,7 @@ import java.util.concurrent.ThreadLocalRandom;
public class LooperStats implements Looper.Observer {
public static final String DEBUG_ENTRY_PREFIX = "__DEBUG_";
private static final int SESSION_POOL_SIZE = 50;
+ private static final boolean DISABLED_SCREEN_STATE_TRACKING_VALUE = false;
@GuardedBy("mLock")
private final SparseArray<Entry> mEntries = new SparseArray<>(512);
@@ -54,6 +55,7 @@ public class LooperStats implements Looper.Observer {
private long mStartCurrentTime = System.currentTimeMillis();
private long mStartElapsedTime = SystemClock.elapsedRealtime();
private boolean mAddDebugEntries = false;
+ private boolean mTrackScreenInteractive = false;
public LooperStats(int samplingInterval, int entriesSizeCap) {
this.mSamplingInterval = samplingInterval;
@@ -218,9 +220,15 @@ public class LooperStats implements Looper.Observer {
mSamplingInterval = samplingInterval;
}
+ public void setTrackScreenInteractive(boolean enabled) {
+ mTrackScreenInteractive = enabled;
+ }
+
@Nullable
private Entry findEntry(Message msg, boolean allowCreateNew) {
- final boolean isInteractive = mDeviceState.isScreenInteractive();
+ final boolean isInteractive = mTrackScreenInteractive
+ ? mDeviceState.isScreenInteractive()
+ : DISABLED_SCREEN_STATE_TRACKING_VALUE;
final int id = Entry.idFor(msg, isInteractive);
Entry entry;
synchronized (mLock) {
diff --git a/core/res/res/drawable/ic_action_open.xml b/core/res/res/drawable/ic_action_open.xml
new file mode 100644
index 000000000000..3d3d36ece0af
--- /dev/null
+++ b/core/res/res/drawable/ic_action_open.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
+</vector> \ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 53cae638db80..1053184bc2fc 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,7 +118,7 @@
<attr name="manageSpaceActivity" format="string" />
<!-- Option to let applications specify that user data can/cannot be
- cleared. This flag is turned on by default.
+ cleared by the user in Settings. This flag is turned on by default.
<em>This attribute is usable only by applications
included in the system image. Third-party apps cannot use it.</em> -->
<attr name="allowClearUserData" format="boolean" />
@@ -1661,7 +1661,12 @@
<!-- If {@code true} the user is prompted to keep the app's data on uninstall -->
<attr name="hasFragileUserData" />
- <attr name="zygotePreloadName" />
+ <attr name="zygotePreloadName" />
+
+ <!-- If {@code true} the system will clear app's data if a restore operation fails.
+ This flag is turned on by default. <em>This attribute is usable only by system apps.
+ </em> -->
+ <attr name="allowClearUserDataOnFailedRestore"/>
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d2c3b40cc3b6..5e65605a4c65 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2939,6 +2939,8 @@
<public name="zygotePreloadName" />
<public name="useEmbeddedDex" />
<public name="forceUriPermissions" />
+ <!-- @hide @SystemApi -->
+ <public name="allowClearUserDataOnFailedRestore"/>
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 410a8c168b5d..8e251fd4ea6f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3643,4 +3643,6 @@
<java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" />
<java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" />
<java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
+
+ <java-symbol type="drawable" name="ic_action_open" />
</resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ec57f793f15f..206682a1955b 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -128,7 +128,6 @@ public class SettingsBackupTest {
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index 213cd405e903..93315f11d242 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -20,11 +20,12 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.graphics.Matrix;
-import android.support.test.InstrumentationRegistry;
import android.view.View;
import android.view.ViewStructure.HtmlInfo;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
+import androidx.test.InstrumentationRegistry;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index bdd03707c1f1..d2d03e565522 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -382,7 +382,6 @@ public class TextClassifierTest {
assertThat(textLanguage, isTextLanguage("ja"));
}
- /* DISABLED: b/122467291
@Test
public void testSuggestConversationActions_textReplyOnly_maxThree() {
if (isTextClassifierDisabled()) return;
@@ -410,7 +409,7 @@ public class TextClassifierTest {
assertThat(conversationAction,
isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
}
- }*/
+ }
@Test
public void testSuggestConversationActions_textReplyOnly_noMax() {
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 1d35143e3fab..e375af3f7b0e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -658,6 +658,67 @@ public class BinderCallsStatsTest {
assertTrue(debugEntry3.latencyMicros >= 0);
}
+ @Test
+ public void testTrackScreenInteractiveDisabled() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setTrackScreenInteractive(false);
+ Binder binder = new Binder();
+
+ mDeviceState.setScreenInteractive(false);
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ mDeviceState.setScreenInteractive(true);
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 1000; // shoud be ignored.
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
+ Assert.assertNotNull(uidEntry);
+ assertEquals(2, uidEntry.callCount);
+
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(false, callStats.screenInteractive);
+ assertEquals(2, callStats.callCount);
+ assertEquals(2, callStats.recordedCallCount);
+ }
+
+ @Test
+ public void testTrackCallingUidDisabled() {
+ TestBinderCallsStats bcs = new TestBinderCallsStats();
+ bcs.setTrackDirectCallerUid(false);
+ Binder binder = new Binder();
+
+ bcs.setCallingUid(1);
+ CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 10;
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ bcs.setCallingUid(2);
+ callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
+ bcs.time += 1000; // shoud be ignored.
+ bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+
+ SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries();
+ assertEquals(1, uidEntries.size());
+ BinderCallsStats.UidEntry uidEntry = uidEntries.get(WORKSOURCE_UID);
+ Assert.assertNotNull(uidEntry);
+ assertEquals(2, uidEntry.callCount);
+
+ List<BinderCallsStats.CallStat> callStatsList = new ArrayList(uidEntry.getCallStatsList());
+ assertEquals(1, callStatsList.size());
+ BinderCallsStats.CallStat callStats = callStatsList.get(0);
+ assertEquals(-1, callStats.callingUid);
+ assertEquals(2, callStats.callCount);
+ assertEquals(2, callStats.recordedCallCount);
+ }
+
+
class TestBinderCallsStats extends BinderCallsStats {
public int callingUid = CALLING_UID;
public long time = 1234;
@@ -682,6 +743,8 @@ public class BinderCallsStatsTest {
});
setSamplingInterval(1);
setAddDebugEntries(false);
+ setTrackScreenInteractive(true);
+ setTrackDirectCallerUid(true);
if (deviceState != null) {
setDeviceState(deviceState.getReadonlyClient());
}
@@ -701,6 +764,10 @@ public class BinderCallsStatsTest {
protected int getCallingUid() {
return callingUid;
}
+
+ protected void setCallingUid(int uid) {
+ callingUid = uid;
+ }
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 79b847754311..3edf5f87258b 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -476,6 +476,33 @@ public final class LooperStatsTest {
assertThat(debugEntry3.totalLatencyMicros).isAtLeast(0L);
}
+ @Test
+ public void testScreenStateTrackingDisabled() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+ looperStats.setTrackScreenInteractive(false);
+
+ Message message = mHandlerFirst.obtainMessage(1000);
+ message.workSourceUid = 1000;
+ message.when = looperStats.getSystemUptimeMillis();
+
+ looperStats.tickUptime(30);
+ mDeviceState.setScreenInteractive(false);
+ Object token = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token, message);
+
+ looperStats.tickUptime(30);
+ mDeviceState.setScreenInteractive(true);
+ token = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token, message);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(1);
+ LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.isInteractive).isEqualTo(false);
+ assertThat(entry.messageCount).isEqualTo(2);
+ assertThat(entry.recordedMessageCount).isEqualTo(2);
+ }
+
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
try {
r.run();
@@ -501,6 +528,7 @@ public final class LooperStatsTest {
super(samplingInterval, sizeCap);
mSamplingInterval = samplingInterval;
setAddDebugEntries(false);
+ setTrackScreenInteractive(true);
if (deviceState != null) {
setDeviceState(deviceState.getReadonlyClient());
}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 7c9529b8ff71..56be05b51d1a 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -175,7 +175,12 @@ public class Typeface {
private int[] mSupportedAxes;
private static final int[] EMPTY_AXES = {};
- @UnsupportedAppUsage
+ /**
+ * Please use font in xml and also your application global theme to change the default Typeface.
+ * android:textViewStyle and its attribute android:textAppearance can be used in order to change
+ * typeface and other text related properties.
+ */
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private static void setDefault(Typeface t) {
sDefaultTypeface = t;
nativeSetDefault(t.native_instance);
diff --git a/media/java/android/media/IRingtonePlayer.aidl b/media/java/android/media/IRingtonePlayer.aidl
index 5f6686a88a7e..c038f36206f6 100644
--- a/media/java/android/media/IRingtonePlayer.aidl
+++ b/media/java/android/media/IRingtonePlayer.aidl
@@ -17,6 +17,7 @@
package android.media;
import android.media.AudioAttributes;
+import android.media.VolumeShaper;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
@@ -27,6 +28,8 @@ import android.os.UserHandle;
interface IRingtonePlayer {
/** Used for Ringtone.java playback */
oneway void play(IBinder token, in Uri uri, in AudioAttributes aa, float volume, boolean looping);
+ oneway void playWithVolumeShaping(IBinder token, in Uri uri, in AudioAttributes aa,
+ float volume, boolean looping, in @nullable VolumeShaper.Configuration volumeShaperConfig);
oneway void stop(IBinder token);
boolean isPlaying(IBinder token);
oneway void setPlaybackProperties(IBinder token, float volume, boolean looping);
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 73d3d889e464..eb680c8377f4 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -381,7 +381,8 @@ public class Ringtone {
volume = mVolume;
}
try {
- mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes, volume, looping);
+ mRemotePlayer.playWithVolumeShaping(mRemoteToken, canonicalUri, mAudioAttributes,
+ volume, looping, mVolumeShaperConfig);
} catch (RemoteException e) {
if (!playFallbackRingtone()) {
Log.w(TAG, "Problem playing ringtone: " + e);
diff --git a/media/java/android/media/VolumeShaper.aidl b/media/java/android/media/VolumeShaper.aidl
new file mode 100644
index 000000000000..e99c13f8a6f3
--- /dev/null
+++ b/media/java/android/media/VolumeShaper.aidl
@@ -0,0 +1,19 @@
+/* Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable VolumeShaper;
+parcelable VolumeShaper.Configuration;
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index e08dab48ce39..49066950a9fb 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -17,8 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SoundPool"
+#include <chrono>
#include <inttypes.h>
-
+#include <thread>
#include <utils/Log.h>
#define USE_SHARED_MEM_BUFFER
@@ -967,6 +968,12 @@ bool SoundChannel::doStop_l()
if (mState != IDLE) {
setVolume_l(0, 0);
ALOGV("stop");
+ // Since we're forcibly halting the previously playing content,
+ // we sleep here to ensure the volume is ramped down before we stop the track.
+ // Ideally the sleep time is the mixer period, or an approximation thereof
+ // (Fast vs Normal tracks are different).
+ // TODO: consider pausing instead of stop here.
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
mAudioTrack->stop();
mPrevSampleID = mSample->sampleID();
mSample.clear();
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 51afbc7d91b0..730c409a91fb 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -230,6 +230,7 @@ LIBANDROID {
ASurfaceTransaction_reparent; # introduced=29
ASurfaceTransaction_setBuffer; # introduced=29
ASurfaceTransaction_setBufferAlpha; # introduced=29
+ ASurfaceTransaction_setBufferDataSpace; # introduced=29
ASurfaceTransaction_setBufferTransparency; # introduced=29
ASurfaceTransaction_setColor; # introduced=29
ASurfaceTransaction_setDamageRegion; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 7d2934b8554e..d07052bb3b3f 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -440,6 +440,20 @@ void ASurfaceTransaction_setBufferAlpha(ASurfaceTransaction* aSurfaceTransaction
transaction->setAlpha(surfaceControl, alpha);
}
+void ASurfaceTransaction_setBufferDataSpace(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl,
+ ADataSpace aDataSpace) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ LOG_ALWAYS_FATAL_IF(!isDataSpaceValid(surfaceControl, aDataSpace), "invalid dataspace");
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setDataspace(surfaceControl, static_cast<ui::Dataspace>(aDataSpace));
+}
+
void ASurfaceTransaction_setHdrMetadata_smpte2086(ASurfaceTransaction* aSurfaceTransaction,
ASurfaceControl* aSurfaceControl,
struct AHdrMetadata_smpte2086* metadata) {
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b6b229c770b2..c5e598d8ce46 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -230,6 +230,10 @@ public class Assistant extends NotificationAssistantService {
NotificationEntry entry =
new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
+ if (DEBUG) {
+ Log.d(TAG, String.format("Creating Adjustment for %s, with %d actions, and %d replies.",
+ sbn.getKey(), suggestions.actions.size(), suggestions.replies.size()));
+ }
return createEnqueuedNotificationAdjustment(
entry, suggestions.actions, suggestions.replies);
}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 08cc39fc4935..f372fe55dfb0 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -21,6 +21,7 @@ import android.app.Notification;
import android.app.Person;
import android.app.RemoteAction;
import android.content.Context;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
@@ -42,6 +43,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
public class SmartActionsHelper {
@@ -120,6 +122,12 @@ public class SmartActionsHelper {
if (messages.isEmpty()) {
return Collections.emptyList();
}
+ // Do not generate smart actions if the last message is from the local user.
+ ConversationActions.Message lastMessage = messages.get(messages.size() - 1);
+ if (arePersonsEqual(
+ ConversationActions.Message.PERSON_USER_SELF, lastMessage.getAuthor())) {
+ return Collections.emptyList();
+ }
TextClassifier.EntityConfig.Builder typeConfigBuilder =
new TextClassifier.EntityConfig.Builder();
@@ -230,8 +238,11 @@ public class SmartActionsHelper {
private Notification.Action createNotificationAction(
RemoteAction remoteAction, String actionType) {
+ Icon icon = remoteAction.shouldShowIcon()
+ ? remoteAction.getIcon()
+ : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open);
return new Notification.Action.Builder(
- remoteAction.getIcon(),
+ icon,
remoteAction.getTitle(),
remoteAction.getActionIntent())
.setContextual(true)
@@ -312,13 +323,12 @@ public class SmartActionsHelper {
if (message == null) {
continue;
}
+ // As per the javadoc of Notification.addMessage, null means local user.
Person senderPerson = message.getSenderPerson();
- // Skip encoding once the sender is missing as it is important to distinguish
- // local user and remote user when generating replies.
if (senderPerson == null) {
- break;
+ senderPerson = localUser;
}
- Person author = localUser != null && localUser.equals(senderPerson)
+ Person author = localUser != null && arePersonsEqual(localUser, senderPerson)
? ConversationActions.Message.PERSON_USER_SELF : senderPerson;
extractMessages.push(new ConversationActions.Message.Builder(author)
.setText(message.getText())
@@ -333,6 +343,12 @@ public class SmartActionsHelper {
return new ArrayList<>(extractMessages);
}
+ private static boolean arePersonsEqual(@NonNull Person left, @NonNull Person right) {
+ return Objects.equals(left.getKey(), right.getKey())
+ && Objects.equals(left.getName(), right.getName())
+ && Objects.equals(left.getUri(), right.getUri());
+ }
+
static class SmartSuggestions {
public final ArrayList<CharSequence> replies;
public final ArrayList<Notification.Action> actions;
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index ebbd961b6f23..74c20fc09df2 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -222,22 +222,29 @@ public class SmartActionsHelperTest {
List<ConversationActions.Message> messages =
runSuggestAndCaptureRequest().getConversation();
- assertThat(messages).hasSize(3);
+ assertThat(messages).hasSize(4);
- ConversationActions.Message secondMessage = messages.get(0);
+ ConversationActions.Message firstMessage = messages.get(0);
+ MessageSubject.assertThat(firstMessage).hasText("firstMessage");
+ MessageSubject.assertThat(firstMessage)
+ .hasPerson(ConversationActions.Message.PERSON_USER_SELF);
+ MessageSubject.assertThat(firstMessage)
+ .hasReferenceTime(createZonedDateTimeFromMsUtc(1000));
+
+ ConversationActions.Message secondMessage = messages.get(1);
MessageSubject.assertThat(secondMessage).hasText("secondMessage");
MessageSubject.assertThat(secondMessage)
.hasPerson(ConversationActions.Message.PERSON_USER_SELF);
MessageSubject.assertThat(secondMessage)
.hasReferenceTime(createZonedDateTimeFromMsUtc(2000));
- ConversationActions.Message thirdMessage = messages.get(1);
+ ConversationActions.Message thirdMessage = messages.get(2);
MessageSubject.assertThat(thirdMessage).hasText("thirdMessage");
MessageSubject.assertThat(thirdMessage).hasPerson(userA);
MessageSubject.assertThat(thirdMessage)
.hasReferenceTime(createZonedDateTimeFromMsUtc(3000));
- ConversationActions.Message fourthMessage = messages.get(2);
+ ConversationActions.Message fourthMessage = messages.get(3);
MessageSubject.assertThat(fourthMessage).hasText("fourthMessage");
MessageSubject.assertThat(fourthMessage).hasPerson(userB);
MessageSubject.assertThat(fourthMessage)
@@ -245,6 +252,28 @@ public class SmartActionsHelperTest {
}
@Test
+ public void testSuggest_lastMessageLocalUser() {
+ Person me = new Person.Builder().setName("Me").build();
+ Person userA = new Person.Builder().setName("A").build();
+ Notification.MessagingStyle style =
+ new Notification.MessagingStyle(me)
+ .addMessage("firstMessage", 1000, userA)
+ .addMessage("secondMessage", 2000, me);
+ Notification notification =
+ mNotificationBuilder
+ .setContentText("You have two new messages")
+ .setStyle(style)
+ .setActions(createReplyAction())
+ .build();
+ when(mStatusBarNotification.getNotification()).thenReturn(notification);
+
+ mSmartActionsHelper.suggest(createNotificationEntry());
+
+ verify(mTextClassifier, never())
+ .suggestConversationActions(any(ConversationActions.Request.class));
+ }
+
+ @Test
public void testSuggest_messageStyle_noPerson() {
Person me = new Person.Builder().setName("Me").build();
Notification.MessagingStyle style =
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index 36d06591460b..f1158ef11ccc 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -17,6 +17,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#4a4a4a" />
- <padding android:padding="@dimen/ongoing_appops_chip_bg_padding" />
+ <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
+ android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/>
<corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index d502baa956b0..91353d7fb8ba 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -71,18 +71,38 @@
android:maxLines="1"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkg_divider" />
- <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
- <ImageButton
- android:id="@+id/info"
- android:layout_width="56dp"
- android:layout_height="56dp"
- android:layout_alignParentEnd="true"
+ <LinearLayout
+ android:id="@+id/info_and_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:background="@drawable/ripple_drawable"
- android:contentDescription="@string/notification_more_settings"
- android:padding="16dp"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/colorAccent" />
+ android:layout_alignParentEnd="true"
+ android:paddingHorizontal="16dp"
+ android:orientation="horizontal">
+ <!-- Optional link to app. Only appears if the channel is not disabled and the app
+asked for it -->
+ <ImageButton
+ android:id="@+id/app_settings"
+ android:layout_width="40dp"
+ android:layout_height="56dp"
+ android:layout_centerVertical="true"
+ android:paddingRight="16dp"
+ android:visibility="gone"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_app_settings"
+ android:src="@drawable/ic_settings"
+ android:tint="?android:attr/colorAccent" />
+ <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
+ <ImageButton
+ android:id="@+id/info"
+ android:layout_width="24dp"
+ android:layout_height="56dp"
+ android:layout_centerVertical="true"
+ android:background="@drawable/ripple_drawable"
+ android:contentDescription="@string/notification_more_settings"
+ android:src="@drawable/ic_info"
+ android:tint="?android:attr/colorAccent" />
+ </LinearLayout>
</RelativeLayout>
<LinearLayout
@@ -143,50 +163,61 @@
</LinearLayout>
<!-- Settings and Done buttons -->
- <LinearLayout
+ <RelativeLayout
android:id="@+id/block_or_minimize"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_guts_button_spacing"
android:layout_marginStart="@dimen/notification_guts_button_side_margin"
android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:gravity="end"
- android:orientation="horizontal">
-
- <!-- Optional link to app. Only appears if the channel is not disabled and the app
- asked for it -->
+ android:clipChildren="false"
+ android:clipToPadding="false">
<TextView
- android:id="@+id/app_settings"
- android:text="@string/notification_app_settings"
+ android:id="@+id/done"
+ android:text="@string/inline_done_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:visibility="gone"
- android:ellipsize="end"
- android:maxLines="1"
+ android:layout_centerVertical="true"
style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/block"
- android:text="@string/inline_stop_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/minimize"
- android:text="@string/inline_minimize_button"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button" />
- <TextView
- android:id="@+id/keep"
- android:minWidth="48dp"
- android:text="@string/inline_keep_button"
+
+ <LinearLayout
+ android:id="@+id/block_buttons"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </LinearLayout>
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:orientation="horizontal">
+ <TextView
+ android:id="@+id/deliver_silently"
+ android:text="@string/inline_deliver_silently_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ android:paddingRight="24dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/block"
+ android:text="@string/inline_block_button"
+ android:minWidth="48dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/minimize"
+ android:text="@string/inline_minimize_button"
+ android:minWidth="48dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </LinearLayout>
+
+
+ </RelativeLayout>
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index cbdd51b24388..58fe81109731 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -29,14 +29,25 @@
android:orientation="horizontal"
android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
- android:background="@drawable/privacy_chip_bg"
android:focusable="true">
+ <TextView
+ android:id="@+id/in_use_text"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical|start"
+ android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+ android:gravity="center_vertical"
+ android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+ android:textColor="@color/status_bar_clock_color"
+ android:text="@string/ongoing_privacy_chip_in_use"
+ />
+
<LinearLayout
android:id="@+id/icons_container"
android:layout_height="match_parent"
android:layout_width="wrap_content"
- android:layout_gravity="center_vertical|start"
+ android:layout_gravity="center_vertical"
android:gravity="center_vertical"
/>
@@ -51,7 +62,7 @@
android:gravity="center_vertical"
android:textAppearance="@style/TextAppearance.StatusBar.Clock"
android:textColor="@color/status_bar_clock_color"
- android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin"
- android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin"
+ android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+ android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
/>
</com.android.systemui.privacy.OngoingPrivacyChip> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 03445352e330..1e1245fe0d86 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -967,7 +967,7 @@
<!-- Height and width of App Opp icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_icon_size">24dp</dimen>
<!-- Left margin of App Opp icons in Ongoing App Ops dialog -->
- <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
+ <dimen name="ongoing_appops_dialog_icon_margin">12dp</dimen>
<!-- Height and width of Application icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
<!-- Height and width of Plus sign in Ongoing App Ops dialog -->
@@ -988,12 +988,14 @@
<dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
<!-- Padding between background of Ongoing App Ops chip and content -->
<dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
- <!-- Margin between icons of Ongoing App Ops chip -->
- <dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QQS-->
+ <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
+ <!-- Margin between icons of Ongoing App Ops chip when QS-->
+ <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen>
<!-- Icon size of Ongoing App Ops chip -->
<dimen name="ongoing_appops_chip_icon_size">18dp</dimen>
<!-- Radius of Ongoing App Ops chip corners -->
- <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
+ <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen>
<!-- Text size for Ongoing App Ops dialog title -->
<dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
<!-- Text size for Ongoing App Ops dialog items -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db4a6cc1d704..db92ed258064 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1573,12 +1573,18 @@
<string name="inline_blocking_helper">You usually dismiss these notifications.
\nKeep showing them?</string>
+ <!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=25] -->
+ <string name="inline_done_button">Done</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
<!-- Notification inline controls: block notifications button -->
<string name="inline_stop_button">Stop notifications</string>
+ <!-- Notification inline controls: button to deliver notifications silently from this channel [CHAR_LIMIT=35] -->
+ <string name="inline_deliver_silently_button">Deliver Silently</string>
+
<!-- Notification inline controls: button to block notifications from this channel [CHAR_LIMIT=35] -->
<string name="inline_block_button">Block</string>
@@ -2301,6 +2307,9 @@
<!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
<string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
+ <!-- Ongoing Privacy "Chip" in use text [CHAR LIMIT=10]-->
+ <string name="ongoing_privacy_chip_in_use">In use:</string>
+
<!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]-->
<plurals name="ongoing_privacy_chip_content_multiple_apps_single_op">
<item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index bf9d7ba61189..976a766dcc09 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -34,8 +34,10 @@ import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.StatsLog;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageButton;
@@ -234,6 +236,8 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
mStackView.collapseStack(() -> {
try {
n.contentIntent.send();
+ logBubbleClickEvent(mEntry.notification,
+ StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP);
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Failed to send intent for bubble with key: "
+ (mEntry != null ? mEntry.key : " null entry"));
@@ -242,7 +246,11 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
} else if (id == R.id.settings_button) {
Intent intent = getSettingsIntent(mEntry.notification.getPackageName(),
mEntry.notification.getUid());
- mStackView.collapseStack(() -> mContext.startActivity(intent));
+ mStackView.collapseStack(() -> {
+ mContext.startActivity(intent);
+ logBubbleClickEvent(mEntry.notification,
+ StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
+ });
} else if (id == R.id.no_bubbles_button) {
setBubblesAllowed(false);
} else if (id == R.id.yes_bubbles_button) {
@@ -262,6 +270,9 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
} else if (mOnBubbleBlockedListener != null) {
mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
}
+ logBubbleClickEvent(mEntry.notification,
+ allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
+ StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
} catch (RemoteException e) {
Log.w(TAG, e);
}
@@ -318,4 +329,22 @@ public class BubbleExpandedView extends LinearLayout implements View.OnClickList
*/
void onBubbleBlocked(NotificationEntry entry);
}
+
+ /**
+ * Logs bubble UI click event.
+ *
+ * @param notification the bubble notification that user is interacting with.
+ * @param action the user interaction enum.
+ */
+ private void logBubbleClickEvent(StatusBarNotification notification, int action) {
+ StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
+ notification.getPackageName(),
+ notification.getNotification().getChannelId(),
+ notification.getId(),
+ mStackView.getBubbleIndex(mStackView.getExpandedBubble()),
+ mStackView.getBubbleCount(),
+ action,
+ mStackView.getNormalizedXPosition(),
+ mStackView.getNormalizedYPosition());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index f6f3fa646232..2b344f6cf195 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -773,7 +773,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* @return the number of bubbles in the stack view.
*/
- private int getBubbleCount() {
+ public int getBubbleCount() {
return mBubbleContainer.getChildCount();
}
@@ -784,14 +784,14 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
* @return the index of the bubble view within the bubble stack. The range of the position
* is between 0 and the bubble count minus 1.
*/
- private int getBubbleIndex(BubbleView bubbleView) {
+ public int getBubbleIndex(BubbleView bubbleView) {
return mBubbleContainer.indexOfChild(bubbleView);
}
/**
* @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
*/
- private float getNormalizedXPosition() {
+ public float getNormalizedXPosition() {
return new BigDecimal(getPosition().x / mDisplaySize.x)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
@@ -800,7 +800,7 @@ public class BubbleStackView extends FrameLayout implements BubbleTouchHandler.F
/**
* @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
*/
- private float getNormalizedYPosition() {
+ public float getNormalizedYPosition() {
return new BigDecimal(getPosition().y / mDisplaySize.y)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index ddd9cbf209d6..aebadf936e0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -16,6 +16,7 @@
package com.android.systemui.media;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -24,6 +25,7 @@ import android.media.AudioAttributes;
import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.media.Ringtone;
+import android.media.VolumeShaper;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
@@ -78,11 +80,16 @@ public class RingtonePlayer extends SystemUI {
private final Ringtone mRingtone;
public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
+ this(token, uri, user, aa, null);
+ }
+
+ Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa,
+ @Nullable VolumeShaper.Configuration volumeShaperConfig) {
mToken = token;
mRingtone = new Ringtone(getContextForUser(user), false);
mRingtone.setAudioAttributes(aa);
- mRingtone.setUri(uri);
+ mRingtone.setUri(uri, volumeShaperConfig);
}
@Override
@@ -99,6 +106,12 @@ public class RingtonePlayer extends SystemUI {
@Override
public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
throws RemoteException {
+ playWithVolumeShaping(token, uri, aa, volume, looping, null);
+ }
+ @Override
+ public void playWithVolumeShaping(IBinder token, Uri uri, AudioAttributes aa, float volume,
+ boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
+ throws RemoteException {
if (LOGD) {
Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
+ Binder.getCallingUid() + ")");
@@ -108,7 +121,7 @@ public class RingtonePlayer extends SystemUI {
client = mClients.get(token);
if (client == null) {
final UserHandle user = Binder.getCallingUserHandle();
- client = new Client(token, uri, user, aa);
+ client = new Client(token, uri, user, aa, volumeShaperConfig);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 65ed889f34e1..ecbf0246a8ba 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -16,6 +16,7 @@ package com.android.systemui.privacy
import android.content.Context
import android.util.AttributeSet
+import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
@@ -29,14 +30,25 @@ class OngoingPrivacyChip @JvmOverloads constructor(
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
- private val iconMargin =
- context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
+ private val iconMarginExpanded = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_icon_margin_expanded)
+ private val iconMarginCollapsed = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_chip_icon_margin_collapsed)
private val iconSize =
context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
- val iconColor = context.resources.getColor(
+ private val iconColor = context.resources.getColor(
R.color.status_bar_clock_color, context.theme)
+ private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
private lateinit var text: TextView
private lateinit var iconsContainer: LinearLayout
+ private lateinit var inUseText: TextView
+ var expanded = false
+ set(value) {
+ if (value != field) {
+ field = value
+ updateView()
+ }
+ }
var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>())
var privacyList = emptyList<PrivacyItem>()
set(value) {
@@ -48,15 +60,18 @@ class OngoingPrivacyChip @JvmOverloads constructor(
override fun onFinishInflate() {
super.onFinishInflate()
+ inUseText = findViewById(R.id.in_use_text)
text = findViewById(R.id.text_container)
iconsContainer = findViewById(R.id.icons_container)
}
// Should only be called if the builder icons or app changed
private fun updateView() {
+ inUseText.visibility = if (expanded) View.GONE else View.VISIBLE
+ background = if (expanded) backgroundDrawable else null
fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
iconsContainer.removeAllViews()
- dialogBuilder.generateIcons().forEach {
+ dialogBuilder.generateIcons().forEachIndexed { i, it ->
it.mutate()
it.setTint(iconColor)
val image = ImageView(context).apply {
@@ -64,17 +79,19 @@ class OngoingPrivacyChip @JvmOverloads constructor(
scaleType = ImageView.ScaleType.CENTER_INSIDE
}
iconsContainer.addView(image, iconSize, iconSize)
- val lp = image.layoutParams as MarginLayoutParams
- lp.marginStart = iconMargin
- image.layoutParams = lp
+ if (i != 0) {
+ val lp = image.layoutParams as MarginLayoutParams
+ lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed
+ image.layoutParams = lp
+ }
}
}
if (!privacyList.isEmpty()) {
generateContentDescription()
setIcons(builder, iconsContainer)
- text.visibility = if (builder.types.size == 1) VISIBLE else GONE
- if (builder.types.size == 1) {
+ text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
+ if (builder.types.size == 1 && expanded) {
if (builder.app != null) {
text.setText(builder.app?.applicationName)
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index b865ce8d261a..f91c9d944439 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -189,6 +189,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
oldBottom) -> updateAnimator(right - left));
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+ updateEverything();
}
private void updateAnimator(int width) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 74e82b270aa0..ee9255c54a62 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -124,6 +124,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private TintedIconManager mIconManager;
private TouchAnimator mStatusIconsAlphaAnimator;
private TouchAnimator mHeaderTextContainerAlphaAnimator;
+ private TouchAnimator mPrivacyChipAlphaAnimator;
private View mSystemIconsView;
private View mQuickQsStatusIcons;
@@ -212,6 +213,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mNextAlarmTextView = findViewById(R.id.next_alarm_text);
mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
mRingerModeTextView = findViewById(R.id.ringer_mode_text);
+ mPrivacyChip = findViewById(R.id.privacy_chip);
+ mPrivacyChip.setOnClickListener(this);
updateResources();
@@ -230,8 +233,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mClockView = findViewById(R.id.clock);
mClockView.setOnClickListener(this);
mDateView = findViewById(R.id.date);
- mPrivacyChip = findViewById(R.id.privacy_chip);
- mPrivacyChip.setOnClickListener(this);
mSpace = findViewById(R.id.space);
// Tint for the battery icons are handled in setupHost()
@@ -383,6 +384,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
updateStatusIconAlphaAnimator();
updateHeaderTextContainerAlphaAnimator();
+ updatePrivacyChipAlphaAnimator();
}
private void updateStatusIconAlphaAnimator() {
@@ -398,6 +400,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements
.build();
}
+ private void updatePrivacyChipAlphaAnimator() {
+ mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
+ .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
+ .build();
+ }
+
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mExpanded = expanded;
@@ -431,6 +439,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements
if (mHeaderTextContainerAlphaAnimator != null) {
mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
}
+ if (mPrivacyChipAlphaAnimator != null) {
+ mPrivacyChip.setExpanded(expansionFraction > 0.5);
+ mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
+ }
// Check the original expansion fraction - we don't want to show the tooltip until the
// panel is pulled all the way out.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
index 43b5503682cc..a1fcbebecea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationCounters.java
@@ -30,6 +30,9 @@ public class NotificationCounters {
/** Counter tag for when the user hits 'stop notifications' in the blocking helper. */
public static final String BLOCKING_HELPER_STOP_NOTIFICATIONS =
"blocking_helper_stop_notifications";
+ /** Counter tag for when the user hits 'deliver silently' in the blocking helper. */
+ public static final String BLOCKING_HELPER_DELIVER_SILENTLY =
+ "blocking_helper_deliver_silently";
/** Counter tag for when the user hits 'show silently' in the blocking helper. */
public static final String BLOCKING_HELPER_TOGGLE_SILENT =
"blocking_helper_toggle_silent";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 80956159c20b..1dc48d4b18b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -68,6 +68,7 @@ import java.util.List;
public class NotificationContentView extends FrameLayout {
private static final String TAG = "NotificationContentView";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final int VISIBLE_TYPE_CONTRACTED = 0;
public static final int VISIBLE_TYPE_EXPANDED = 1;
public static final int VISIBLE_TYPE_HEADSUP = 2;
@@ -1319,6 +1320,14 @@ public class NotificationContentView extends FrameLayout {
SmartRepliesAndActions smartRepliesAndActions =
chooseSmartRepliesAndActions(mSmartReplyConstants, entry);
+ if (DEBUG) {
+ Log.d(TAG, String.format("Adding suggestions for %s, %d actions, and %d replies.",
+ entry.notification.getKey(),
+ smartRepliesAndActions.smartActions == null ? 0 :
+ smartRepliesAndActions.smartActions.actions.size(),
+ smartRepliesAndActions.smartReplies == null ? 0 :
+ smartRepliesAndActions.smartReplies.choices.length));
+ }
applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput);
applySmartReplyView(smartRepliesAndActions, entry);
@@ -1341,6 +1350,10 @@ public class NotificationContentView extends FrameLayout {
notification.findRemoteInputActionPair(true /* freeform */);
if (!smartReplyConstants.isEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
+ + entry.notification.getKey());
+ }
return new SmartRepliesAndActions(null, null, freeformRemoteInputActionPair != null);
}
// Only use smart replies from the app if they target P or above. We have this check because
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index c7b2fab54fff..37237317fc95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -84,6 +84,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public static final int ACTION_UNDO = 1;
public static final int ACTION_TOGGLE_SILENT = 2;
public static final int ACTION_BLOCK = 3;
+ public static final int ACTION_DELIVER_SILENTLY = 4;
private INotificationManager mINotificationManager;
private PackageManager mPm;
@@ -135,30 +136,26 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
};
private OnClickListener mOnToggleSilent = v -> {
- Runnable saveImportance = () -> {
- swapContent(ACTION_TOGGLE_SILENT, true /* animate */);
- if (mIsForBlockingHelper) {
- mMetricsLogger.write(getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME));
- }
- };
- if (mCheckSaveListener != null) {
- mCheckSaveListener.checkSave(saveImportance, mSbn);
- } else {
- saveImportance.run();
- }
+ handleSaveImportance(ACTION_TOGGLE_SILENT, MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME);
+ };
+
+ private OnClickListener mOnDeliverSilently = v -> {
+ handleSaveImportance(
+ ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
};
private OnClickListener mOnStopOrMinimizeNotifications = v -> {
+ handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
+ };
+
+ private void handleSaveImportance(int action, int metricsSubtype) {
Runnable saveImportance = () -> {
- swapContent(ACTION_BLOCK, true /* animate */);
+ swapContent(action, true /* animate */);
if (mIsForBlockingHelper) {
mMetricsLogger.write(getLogMaker()
.setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
.setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED));
+ .setSubtype(metricsSubtype));
}
};
if (mCheckSaveListener != null) {
@@ -166,7 +163,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
} else {
saveImportance.run();
}
- };
+ }
private OnClickListener mOnUndo = v -> {
// Reset exit counter that we'll log and record an undo event separately (not an exit event)
@@ -283,8 +280,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mMetricsLogger.write(notificationControlsLogMaker());
}
-
-
private void bindHeader() throws RemoteException {
// Package name
Drawable pkgicon = null;
@@ -479,17 +474,21 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
View block = findViewById(R.id.block);
- TextView keep = findViewById(R.id.keep);
+ TextView done = findViewById(R.id.done);
View minimize = findViewById(R.id.minimize);
+ View deliverSilently = findViewById(R.id.deliver_silently);
+
block.setOnClickListener(mOnStopOrMinimizeNotifications);
- keep.setOnClickListener(mOnKeepShowing);
+ done.setOnClickListener(mOnKeepShowing);
minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
+ deliverSilently.setOnClickListener(mOnDeliverSilently);
if (mIsNonblockable) {
- keep.setText(android.R.string.ok);
+ done.setText(android.R.string.ok);
block.setVisibility(GONE);
minimize.setVisibility(GONE);
+ deliverSilently.setVisibility(GONE);
} else if (mIsForeground) {
block.setVisibility(GONE);
minimize.setVisibility(VISIBLE);
@@ -499,7 +498,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
// Set up app settings link (i.e. Customize)
- TextView settingsLinkView = findViewById(R.id.app_settings);
+ View settingsLinkView = findViewById(R.id.app_settings);
Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
mSingleNotificationChannel,
mSbn.getId(), mSbn.getTag());
@@ -507,7 +506,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
&& settingsIntent != null
&& !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
settingsLinkView.setVisibility(VISIBLE);
- settingsLinkView.setText(mContext.getString(R.string.notification_app_settings));
settingsLinkView.setOnClickListener((View view) -> {
mAppSettingsClickListener.onClick(view, settingsIntent);
});
@@ -531,6 +529,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
case ACTION_UNDO:
mChosenImportance = mStartingChannelImportance;
break;
+ case ACTION_DELIVER_SILENTLY:
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
+ mChosenImportance = IMPORTANCE_LOW;
+ confirmationText.setText(R.string.notification_channel_silenced);
+ break;
case ACTION_TOGGLE_SILENT:
mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT;
if (mWasShownHighPriority) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 105bd9dd8793..19a73f6c2d5b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -737,7 +737,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
- mNotificationInfo.findViewById(R.id.keep).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -765,7 +765,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
- mNotificationInfo.findViewById(R.id.keep).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -961,6 +961,41 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
+ public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
+ throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ mNotificationInfo.bindNotification(
+ mMockPackageManager,
+ mMockINotificationManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ 1 /* numChannels */,
+ mSbn,
+ null /* checkSaveListener */,
+ null /* onSettingsClick */,
+ null /* onAppSettingsClick */,
+ true /*provisioned */,
+ false /* isNonblockable */,
+ true /* isForBlockingHelper */,
+ true /* isUserSentimentNegative */,
+ IMPORTANCE_DEFAULT,
+ false);
+
+ mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
+ waitForUndoButton();
+ mNotificationInfo.handleCloseControls(true, false);
+
+ mTestableLooper.processAllMessages();
+ ArgumentCaptor<NotificationChannel> updated =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), eq(TEST_UID), updated.capture());
+ assertTrue((updated.getValue().getUserLockedFields()
+ & USER_LOCKED_IMPORTANCE) != 0);
+ assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+ }
+
+ @Test
public void testKeepUpdatesNotificationChannel() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 2e45fa72eaac..4a3f12674eb7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -49,6 +49,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.autofill.FillEventHistory;
import android.service.autofill.UserData;
@@ -167,10 +168,14 @@ public final class AutofillManagerService
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
mAm = LocalServices.getService(ActivityManagerInternal.class);
+ DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
+ ActivityThread.currentApplication().getMainExecutor(),
+ (namespace, name, value) -> setSmartSuggestionModesFromDeviceConfig(value));
+
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
setMaxVisibleDatasetsFromSettings();
- setSmartSuggestionEmulationFromSettings();
+ setSmartSuggestionModesFromDeviceConfig();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -197,9 +202,6 @@ public final class AutofillManagerService
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer,
UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer,
- UserHandle.USER_ALL);
}
@Override // from AbstractMasterSystemService
@@ -214,9 +216,6 @@ public final class AutofillManagerService
case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS:
setMaxVisibleDatasetsFromSettings();
break;
- case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS:
- setSmartSuggestionEmulationFromSettings();
- break;
default:
Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
// fall through
@@ -457,14 +456,25 @@ public final class AutofillManagerService
}
}
- private void setSmartSuggestionEmulationFromSettings() {
- final int flags = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0);
- if (sDebug) {
- Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): "
- + getSmartSuggestionModeToString(flags));
- }
+ private void setSmartSuggestionModesFromDeviceConfig() {
+ final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_AUTOFILL,
+ AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES);
+ setSmartSuggestionModesFromDeviceConfig(value);
+ }
+ private void setSmartSuggestionModesFromDeviceConfig(@Nullable String value) {
+ if (sDebug) Slog.d(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): value=" + value);
+ final int flags;
+ if (value == null) {
+ flags = AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+ } else {
+ try {
+ flags = Integer.parseInt(value);
+ } catch (Exception e) {
+ Slog.w(TAG, "setSmartSuggestionEmulationFromDeviceConfig(): NAN:" + value);
+ return;
+ }
+ }
synchronized (mLock) {
mSupportedSmartSuggestionModes = flags;
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
index 39d5c9d0b777..86ad52d9a42b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
@@ -77,15 +77,12 @@ public final class ContentCaptureManagerServiceShellCommand extends ShellCommand
pw.println(" Temporarily (for DURATION ms) changes the service implemtation.");
pw.println(" To reset, call with just the USER_ID argument.");
pw.println("");
- pw.println("");
pw.println(" set default-service-enabled USER_ID [true|false]");
pw.println(" Enable / disable the default service for the user.");
pw.println("");
- pw.println("");
pw.println(" get default-service-enabled USER_ID");
pw.println(" Checks whether the default service is enabled for the user.");
pw.println("");
- pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index eafa0e2a6786..e51025943df4 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -121,6 +121,8 @@ public class BinderCallsStatsService extends Binder {
private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking";
private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state";
+ private static final String SETTINGS_TRACK_DIRECT_CALLING_UID_KEY = "track_calling_uid";
private static final String SETTINGS_MAX_CALL_STATS_KEY = "max_call_stats_count";
private boolean mEnabled;
@@ -169,6 +171,12 @@ public class BinderCallsStatsService extends Binder {
mBinderCallsStats.setMaxBinderCallStats(mParser.getInt(
SETTINGS_MAX_CALL_STATS_KEY,
BinderCallsStats.MAX_BINDER_CALL_STATS_COUNT_DEFAULT));
+ mBinderCallsStats.setTrackScreenInteractive(
+ mParser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY,
+ BinderCallsStats.DEFAULT_TRACK_SCREEN_INTERACTIVE));
+ mBinderCallsStats.setTrackDirectCallerUid(
+ mParser.getBoolean(SETTINGS_TRACK_DIRECT_CALLING_UID_KEY,
+ BinderCallsStats.DEFAULT_TRACK_DIRECT_CALLING_UID));
final boolean enabled =
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 9184128d466f..c334540f48cc 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -51,16 +51,19 @@ public class LooperStatsService extends Binder {
private static final String LOOPER_STATS_SERVICE_NAME = "looper_stats";
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
+ private static final String SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY = "track_screen_state";
private static final String DEBUG_SYS_LOOPER_STATS_ENABLED =
"debug.sys.looper_stats_enabled";
private static final int DEFAULT_SAMPLING_INTERVAL = 100;
private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000;
private static final boolean DEFAULT_ENABLED = true;
+ private static final boolean DEFAULT_TRACK_SCREEN_INTERACTIVE = false;
private final Context mContext;
private final LooperStats mStats;
// Default should be false so that the first call to #setEnabled installed the looper observer.
private boolean mEnabled = false;
+ private boolean mTrackScreenInteractive = false;
private LooperStatsService(Context context, LooperStats stats) {
this.mContext = context;
@@ -79,6 +82,9 @@ public class LooperStatsService extends Binder {
setSamplingInterval(
parser.getInt(SETTINGS_SAMPLING_INTERVAL_KEY, DEFAULT_SAMPLING_INTERVAL));
+ setTrackScreenInteractive(
+ parser.getBoolean(SETTINGS_TRACK_SCREEN_INTERACTIVE_KEY,
+ DEFAULT_TRACK_SCREEN_INTERACTIVE));
// Manually specified value takes precedence over Settings.
setEnabled(SystemProperties.getBoolean(
DEBUG_SYS_LOOPER_STATS_ENABLED,
@@ -155,6 +161,13 @@ public class LooperStatsService extends Binder {
}
}
+ private void setTrackScreenInteractive(boolean enabled) {
+ if (mTrackScreenInteractive != enabled) {
+ mTrackScreenInteractive = enabled;
+ mStats.reset();
+ }
+ }
+
private void setSamplingInterval(int samplingInterval) {
if (samplingInterval > 0) {
mStats.setSamplingInterval(samplingInterval);
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index eaf790bb05c4..8ccb6e20a614 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -328,6 +328,9 @@ public class AdbDebuggingManager {
mConnectedKey = key;
mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
scheduleJobToUpdateAdbKeyStore();
+ // write this key to adb_keys as well so that subsequent connections can
+ // go through the expected SIGNATURE interaction.
+ writeKey(key);
}
logAdbConnectionChanged(key, AdbProtoEnums.USER_ALLOWED, alwaysAllow);
}
@@ -360,20 +363,9 @@ public class AdbDebuggingManager {
}
break;
}
- // Check if the key should be allowed without user interaction.
- if (mAdbKeyStore.isKeyAuthorized(key)) {
- if (mThread != null) {
- mThread.sendResponse("OK");
- mAdbKeyStore.setLastConnectionTime(key, System.currentTimeMillis());
- logAdbConnectionChanged(key, AdbProtoEnums.AUTOMATICALLY_ALLOWED, true);
- mConnectedKey = key;
- scheduleJobToUpdateAdbKeyStore();
- }
- } else {
- logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false);
- mFingerprints = fingerprints;
- startConfirmation(key, mFingerprints);
- }
+ logAdbConnectionChanged(key, AdbProtoEnums.AWAITING_USER_APPROVAL, false);
+ mFingerprints = fingerprints;
+ startConfirmation(key, mFingerprints);
break;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c981e6885a9e..7f6648a3d174 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2072,7 +2072,8 @@ class UserController implements Handler.Callback {
new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
.logDuration("SystemUserUnlock", unlockTime);
} else {
- Slog.d(TAG, "Unlocking user " + id + " took " + unlockTime + " ms");
+ new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
+ .logDuration("User" + id + "Unlock", unlockTime);
}
}
};
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 9cb6eeec2126..8171ad67f2a2 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -387,8 +387,10 @@ public final class ColorDisplayService extends SystemService {
Slog.d(TAG, "Setting saturation level: " + saturationLevel);
if (saturationLevel == 100) {
+ setActivated(false);
Matrix.setIdentityM(mMatrixGlobalSaturation, 0);
} else {
+ setActivated(true);
float saturation = saturationLevel * 0.1f;
float desaturation = 1.0f - saturation;
float[] luminance = {0.231f * desaturation, 0.715f * desaturation,
@@ -674,6 +676,10 @@ public final class ColorDisplayService extends SystemService {
if (mDisplayWhiteBalanceTintController.isAvailable(getContext())) {
mDisplayWhiteBalanceTintController.endAnimator();
}
+
+ if (mGlobalSaturationTintController.isAvailable(getContext())) {
+ mGlobalSaturationTintController.setActivated(null);
+ }
}
private void onNightDisplayAutoModeChanged(int autoMode) {
@@ -1671,6 +1677,20 @@ public final class ColorDisplayService extends SystemService {
}
@Override
+ public boolean isSaturationActivated() {
+ getContext().enforceCallingPermission(
+ Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+ "Permission required to get display saturation level");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return !mGlobalSaturationTintController.isActivatedStateNotSet()
+ && mGlobalSaturationTintController.isActivated();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
public boolean setAppSaturationLevel(String packageName, int level) {
getContext().enforceCallingPermission(
Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index cf84e22e7dd1..1b237949a543 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -187,7 +187,7 @@ public final class FrameworkResourcesServiceNameResolver implements ServiceNameR
@Override
public boolean isDefaultServiceEnabled(int userId) {
synchronized (mLock) {
- return mDefaultServicesDisabled.get(userId);
+ return !mDefaultServicesDisabled.get(userId);
}
}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 1f9b027be030..e7a71b99a213 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -20,6 +20,7 @@ import static android.security.keystore.recovery.KeyChainProtectionParams.TYPE_L
import android.annotation.Nullable;
import android.content.Context;
+import android.os.RemoteException;
import android.security.Scrypt;
import android.security.keystore.recovery.KeyChainProtectionParams;
import android.security.keystore.recovery.KeyChainSnapshot;
@@ -162,7 +163,7 @@ public class KeySyncTask implements Runnable {
}
}
- private void syncKeys() {
+ private void syncKeys() throws RemoteException {
if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
// Application keys for the user will not be available for sync.
Log.w(TAG, "Credentials are not set for user " + mUserId);
@@ -195,7 +196,7 @@ public class KeySyncTask implements Runnable {
&& mCredentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
}
- private void syncKeysForAgent(int recoveryAgentUid) throws IOException {
+ private void syncKeysForAgent(int recoveryAgentUid) throws IOException, RemoteException {
boolean shouldRecreateCurrentVersion = false;
if (!shouldCreateSnapshot(recoveryAgentUid)) {
shouldRecreateCurrentVersion =
@@ -412,7 +413,7 @@ public class KeySyncTask implements Runnable {
private Map<String, Pair<SecretKey, byte[]>> getKeysToSync(int recoveryAgentUid)
throws InsecureUserException, KeyStoreException, UnrecoverableKeyException,
NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
- InvalidKeyException, InvalidAlgorithmParameterException, IOException {
+ InvalidKeyException, InvalidAlgorithmParameterException, IOException, RemoteException {
PlatformDecryptionKey decryptKey = mPlatformKeyManager.getDecryptKey(mUserId);;
Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(
mUserId, recoveryAgentUid, decryptKey.getGenerationId());
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 9ca052b9c9a8..1c187713540a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -18,15 +18,21 @@ package com.android.server.locksettings.recoverablekeystore;
import android.app.KeyguardManager;
import android.content.Context;
+import android.os.RemoteException;
+import android.security.GateKeeper;
import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.service.gatekeeper.IGateKeeperService;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
@@ -34,9 +40,11 @@ import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Locale;
+import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
-import javax.security.auth.DestroyFailedException;
+import javax.crypto.spec.GCMParameterSpec;
/**
* Manages creating and checking the validity of the platform key.
@@ -67,6 +75,10 @@ public class PlatformKeyManager {
private static final String ENCRYPT_KEY_ALIAS_SUFFIX = "encrypt";
private static final String DECRYPT_KEY_ALIAS_SUFFIX = "decrypt";
private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
+ private static final String KEY_WRAP_CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+ private static final int GCM_TAG_LENGTH_BITS = 128;
+ // Only used for checking if a key is usable
+ private static final byte[] GCM_INSECURE_NONCE_BYTES = new byte[12];
private final Context mContext;
private final KeyStoreProxy mKeyStore;
@@ -158,12 +170,14 @@ public class PlatformKeyManager {
* @throws KeyStoreException if there is an error in AndroidKeyStore.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
@VisibleForTesting
void regenerate(int userId)
- throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException {
+ throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException,
+ RemoteException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -190,11 +204,13 @@ public class PlatformKeyManager {
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
- public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ public PlatformEncryptionKey getEncryptKey(int userId)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ InsecureUserException, IOException, RemoteException {
init(userId);
try {
// Try to see if the decryption key is still accessible before using the encryption key.
@@ -243,14 +259,18 @@ public class PlatformKeyManager {
* @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
* @throws InsecureUserException if the user does not have a lock screen set.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
- public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
- UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ public PlatformDecryptionKey getDecryptKey(int userId)
+ throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
+ InsecureUserException, IOException, RemoteException {
init(userId);
try {
- return getDecryptKeyInternal(userId);
+ PlatformDecryptionKey decryptionKey = getDecryptKeyInternal(userId);
+ ensureDecryptionKeyIsValid(userId, decryptionKey);
+ return decryptionKey;
} catch (UnrecoverableKeyException e) {
Log.i(TAG, String.format(Locale.US,
"Regenerating permanently invalid Platform key for user %d.",
@@ -284,6 +304,29 @@ public class PlatformKeyManager {
}
/**
+ * Tries to use the decryption key to make sure it is not permanently invalidated. The exception
+ * {@code KeyPermanentlyInvalidatedException} is thrown only when the key is in use.
+ *
+ * <p>Note that we ignore all other InvalidKeyException exceptions, because such an exception
+ * may be thrown for auth-bound keys if there's no recent unlock event.
+ */
+ private void ensureDecryptionKeyIsValid(int userId, PlatformDecryptionKey decryptionKey)
+ throws UnrecoverableKeyException {
+ try {
+ Cipher.getInstance(KEY_WRAP_CIPHER_ALGORITHM).init(Cipher.UNWRAP_MODE,
+ decryptionKey.getKey(),
+ new GCMParameterSpec(GCM_TAG_LENGTH_BITS, GCM_INSECURE_NONCE_BYTES));
+ } catch (KeyPermanentlyInvalidatedException e) {
+ Log.e(TAG, String.format(Locale.US, "The platform key for user %d became invalid.",
+ userId));
+ throw new UnrecoverableKeyException(e.getMessage());
+ } catch (NoSuchAlgorithmException | InvalidKeyException
+ | InvalidAlgorithmParameterException | NoSuchPaddingException e) {
+ // Ignore all other exceptions
+ }
+ }
+
+ /**
* Initializes the class. If there is no current platform key, and the user has a lock screen
* set, will create the platform key and set the generation ID.
*
@@ -291,11 +334,13 @@ public class PlatformKeyManager {
* @throws KeyStoreException if there was an error in AndroidKeyStore.
* @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*
* @hide
*/
void init(int userId)
- throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException {
+ throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException,
+ RemoteException {
if (!isAvailable(userId)) {
throw new InsecureUserException(String.format(
Locale.US, "%d does not have a lock screen set.", userId));
@@ -372,6 +417,11 @@ public class PlatformKeyManager {
&& mKeyStore.containsAlias(getDecryptAlias(userId, generationId));
}
+ @VisibleForTesting
+ IGateKeeperService getGateKeeperService() {
+ return GateKeeper.getService();
+ }
+
/**
* Generates a new 256-bit AES key, and loads it into AndroidKeyStore with the given
* {@code generationId} determining its aliases.
@@ -380,15 +430,23 @@ public class PlatformKeyManager {
* available since API version 1.
* @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore.
* @throws IOException if there was an issue with local database update.
+ * @throws RemoteException if there was an issue communicating with {@link IGateKeeperService}.
*/
private void generateAndLoadKey(int userId, int generationId)
- throws NoSuchAlgorithmException, KeyStoreException, IOException {
+ throws NoSuchAlgorithmException, KeyStoreException, IOException, RemoteException {
String encryptAlias = getEncryptAlias(userId, generationId);
String decryptAlias = getDecryptAlias(userId, generationId);
// SecretKey implementation doesn't provide reliable way to destroy the secret
// so it may live in memory for some time.
SecretKey secretKey = generateAesKey();
+ long secureUserId = getGateKeeperService().getSecureUserId(userId);
+ // TODO(b/124095438): Propagate this failure instead of silently failing.
+ if (secureUserId == GateKeeper.INVALID_SECURE_USER_ID) {
+ Log.e(TAG, "No SID available for user " + userId);
+ return;
+ }
+
// Store decryption key first since it is more likely to fail.
mKeyStore.setEntry(
decryptAlias,
@@ -399,7 +457,7 @@ public class PlatformKeyManager {
USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .setBoundToSpecificSecureUserId(userId)
+ .setBoundToSpecificSecureUserId(secureUserId)
.build());
mKeyStore.setEntry(
encryptAlias,
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 18e292feba30..7e4365dafbe4 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -119,6 +119,7 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
+ UserManager.DISALLOW_CONTENT_CAPTURE,
UserManager.DISALLOW_USER_SWITCH,
UserManager.DISALLOW_UNIFIED_PASSWORD,
UserManager.DISALLOW_CONFIG_LOCATION,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6c3e1f4ce1c2..00105be87cd4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -188,6 +188,7 @@ import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
@@ -843,7 +844,7 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
synchronized (mGlobalLock) {
SurfaceControl.closeTransaction();
- traceStateLocked(where);
+ mWindowTracing.logState(where);
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -967,7 +968,8 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowPlacerLocked = new WindowSurfacePlacer(this);
mTaskSnapshotController = new TaskSnapshotController(this);
- mWindowTracing = WindowTracing.createDefaultAndStartLooper(context);
+ mWindowTracing = WindowTracing.createDefaultAndStartLooper(this,
+ Choreographer.getInstance());
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -5765,17 +5767,6 @@ public class WindowManagerService extends IWindowManager.Stub
proto.write(LAST_ORIENTATION, defaultDisplayContent.getLastOrientation());
}
- void traceStateLocked(String where) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
- try {
- mWindowTracing.traceStateLocked(where, this);
- } catch (Exception e) {
- Log.wtf(TAG, "Exception while tracing state", e);
- } finally {
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 8b1ffa8387d7..abc474d756b7 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -24,12 +24,14 @@ import static com.android.server.wm.WindowManagerTraceProto.WHERE;
import static com.android.server.wm.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
import android.annotation.Nullable;
-import android.content.Context;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
+
+import com.android.internal.annotations.VisibleForTesting;
import java.io.File;
import java.io.IOException;
@@ -48,6 +50,10 @@ class WindowTracing {
private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
private static final String TAG = "WindowTracing";
+ private final WindowManagerService mService;
+ private final Choreographer mChoreographer;
+ private final WindowManagerGlobalLock mGlobalLock;
+
private final Object mLock = new Object();
private final WindowTraceBuffer.Builder mBufferBuilder;
@@ -57,11 +63,24 @@ class WindowTracing {
private boolean mContinuousMode;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
+ private boolean mScheduled;
+ private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+ log("onFrame" /* where */);
+
+ private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
+ this(file, service, choreographer, service.mGlobalLock);
+ }
- WindowTracing(File file) {
+ @VisibleForTesting
+ WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock) {
mBufferBuilder = new WindowTraceBuffer.Builder()
.setTraceFile(file)
.setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+
+ mChoreographer = choreographer;
+ mService = service;
+ mGlobalLock = globalLock;
}
void startTrace(@Nullable PrintWriter pw) throws IOException {
@@ -111,7 +130,8 @@ class WindowTracing {
}
}
- private void setContinuousMode(boolean continuous, PrintWriter pw) {
+ @VisibleForTesting
+ void setContinuousMode(boolean continuous, PrintWriter pw) {
logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
if (mEnabled) {
@@ -123,21 +143,14 @@ class WindowTracing {
WindowTraceLogLevel.TRIM;
}
- private void appendTraceEntry(ProtoOutputStream proto) {
- if (!mEnabledLockFree) {
- return;
- }
-
- mTraceBuffer.add(proto);
- }
-
boolean isEnabled() {
return mEnabledLockFree;
}
- static WindowTracing createDefaultAndStartLooper(Context context) {
+ static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+ Choreographer choreographer) {
File file = new File("/data/misc/wmtrace/wm_trace.pb");
- return new WindowTracing(file);
+ return new WindowTracing(file, service, choreographer);
}
int onShellCommand(ShellCommand shell) {
@@ -164,28 +177,65 @@ class WindowTracing {
}
}
- void traceStateLocked(String where, WindowManagerService service) {
+ /**
+ * If tracing is enabled, log the current state or schedule the next frame to be logged,
+ * according to {@link #mContinuousMode}.
+ *
+ * @param where Logging point descriptor
+ */
+ void logState(String where) {
if (!isEnabled()) {
return;
}
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToBufferLocked");
+ if (mContinuousMode) {
+ schedule();
+ } else {
+ log(where);
+ }
+ }
+
+ /**
+ * Schedule the log to trace the next frame
+ */
+ private void schedule() {
+ if (mScheduled) {
+ return;
+ }
+
+ mScheduled = true;
+ mChoreographer.postFrameCallback(mFrameCallback);
+ }
+
+ /**
+ * Write the current frame to the buffer
+ *
+ * @param where Logging point descriptor
+ */
+ private void log(String where) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- os.write(WHERE, where);
-
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
- try {
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
- service.writeToProtoLocked(os, mWindowTraceLogLevel);
- os.end(tokenInner);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ synchronized (mGlobalLock) {
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
+ try {
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ mService.writeToProtoLocked(os, mWindowTraceLogLevel);
+ os.end(tokenInner);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ os.end(tokenOuter);
+ mTraceBuffer.add(os);
+
+ mScheduled = false;
}
- os.end(tokenOuter);
- appendTraceEntry(os);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Exception while tracing state", e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index 13436e7f8674..821d97acc230 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -24,14 +24,21 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.testng.Assert.expectThrows;
import android.app.KeyguardManager;
import android.content.Context;
+import android.os.RemoteException;
+import android.security.GateKeeper;
+import android.security.keystore.AndroidKeyStoreSecretKey;
+import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.service.gatekeeper.IGateKeeperService;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -53,6 +60,8 @@ import java.security.KeyStore;
import java.security.UnrecoverableKeyException;
import java.util.List;
+import javax.crypto.KeyGenerator;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PlatformKeyManagerTest {
@@ -60,10 +69,15 @@ public class PlatformKeyManagerTest {
private static final String DATABASE_FILE_NAME = "recoverablekeystore.db";
private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
private static final int USER_ID_FIXTURE = 42;
+ private static final long USER_SID = 4200L;
+ private static final String KEY_ALGORITHM = "AES";
+ private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
+ private static final String TESTING_KEYSTORE_KEY_ALIAS = "testing-key-store-key-alias";
@Mock private Context mContext;
@Mock private KeyStoreProxy mKeyStoreProxy;
@Mock private KeyguardManager mKeyguardManager;
+ @Mock private IGateKeeperService mGateKeeperService;
@Captor private ArgumentCaptor<KeyStore.ProtectionParameter> mProtectionParameterCaptor;
@Captor private ArgumentCaptor<KeyStore.Entry> mEntryArgumentCaptor;
@@ -74,18 +88,19 @@ public class PlatformKeyManagerTest {
private PlatformKeyManager mPlatformKeyManager;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Context context = InstrumentationRegistry.getTargetContext();
mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME);
mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context);
- mPlatformKeyManager = new PlatformKeyManager(
- mContext, mKeyStoreProxy, mRecoverableKeyStoreDb);
+ mPlatformKeyManager = new PlatformKeyManagerTestable(
+ mContext, mKeyStoreProxy, mRecoverableKeyStoreDb, mGateKeeperService);
when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager);
when(mContext.getSystemServiceName(any())).thenReturn("test");
when(mKeyguardManager.isDeviceSecure(USER_ID_FIXTURE)).thenReturn(true);
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenReturn(USER_SID);
}
@After
@@ -192,11 +207,36 @@ public class PlatformKeyManagerTest {
mPlatformKeyManager.init(USER_ID_FIXTURE);
assertEquals(
- USER_ID_FIXTURE,
+ USER_SID,
getDecryptKeyProtection().getBoundToSpecificSecureUserId());
}
@Test
+ public void init_doesNotCreateDecryptKeyIfNoSid() throws Exception {
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE))
+ .thenReturn(GateKeeper.INVALID_SECURE_USER_ID);
+
+ mPlatformKeyManager.init(USER_ID_FIXTURE);
+
+ verify(mKeyStoreProxy, never()).setEntry(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any(),
+ any());
+ }
+
+ @Test
+ public void init_doesNotCreateDecryptKeyOnGateKeeperException() throws Exception {
+ when(mGateKeeperService.getSecureUserId(USER_ID_FIXTURE)).thenThrow(new RemoteException());
+
+ expectThrows(RemoteException.class, () -> mPlatformKeyManager.init(USER_ID_FIXTURE));
+
+ verify(mKeyStoreProxy, never()).setEntry(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any(),
+ any());
+ }
+
+ @Test
public void init_createsBothKeysWithSameMaterial() throws Exception {
mPlatformKeyManager.init(USER_ID_FIXTURE);
@@ -259,6 +299,9 @@ public class PlatformKeyManagerTest {
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ "platform/42/1/encrypt")).thenReturn(true);
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
@@ -281,6 +324,9 @@ public class PlatformKeyManagerTest {
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
+ "platform/42/2/decrypt")).thenReturn(true);
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
@@ -352,6 +398,9 @@ public class PlatformKeyManagerTest {
doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
any());
+ when(mKeyStoreProxy.getKey(
+ eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+ any())).thenReturn(generateAndroidKeyStoreKey());
when(mKeyStoreProxy
.containsAlias("com.android.server.locksettings.recoverablekeystore/"
@@ -536,4 +585,34 @@ public class PlatformKeyManagerTest {
mProtectionParameterCaptor.capture());
return (KeyProtection) mProtectionParameterCaptor.getValue();
}
+
+ private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception {
+ KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ KEY_ALGORITHM,
+ ANDROID_KEY_STORE_PROVIDER);
+ keyGenerator.init(new KeyGenParameterSpec.Builder(TESTING_KEYSTORE_KEY_ALIAS,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build());
+ return (AndroidKeyStoreSecretKey) keyGenerator.generateKey();
+ }
+
+ class PlatformKeyManagerTestable extends PlatformKeyManager {
+ private IGateKeeperService mGateKeeperService;
+
+ PlatformKeyManagerTestable(
+ Context context,
+ KeyStoreProxy keyStoreProxy,
+ RecoverableKeyStoreDb database,
+ IGateKeeperService gateKeeperService) {
+ super(context, keyStoreProxy, database);
+ mGateKeeperService = gateKeeperService;
+ }
+
+ @Override
+ IGateKeeperService getGateKeeperService() {
+ return mGateKeeperService;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 4e43d002d4ae..8caa39dfc9e7 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests {
0L, group.getUsageRemaining());
}
+ /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */
+ @Test
+ public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() {
+ addAppUsageLimitObserver(OBS_ID1, GROUP1, 0);
+ AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
+ assertNotNull("Observer wasn't added", group);
+ assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining());
+ }
+
private void startUsage(String packageName) {
mController.noteUsageStart(packageName, USER_ID);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index e27dd94b1a2c..21a4e8417bab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -72,8 +72,10 @@ import com.android.server.am.PendingIntentController;
import com.android.server.appop.AppOpsService;
import com.android.server.firewall.IntentFirewall;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.utils.MockTracker;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
@@ -88,6 +90,8 @@ import java.util.List;
class ActivityTestsBase {
private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
+ private static MockTracker sMockTracker;
+
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
@@ -107,9 +111,17 @@ class ActivityTestsBase {
@BeforeClass
public static void setUpOnceBase() {
+ sMockTracker = new MockTracker();
+
AttributeCache.init(getInstrumentation().getTargetContext());
}
+ @AfterClass
+ public static void tearDownOnceBase() {
+ sMockTracker.close();
+ sMockTracker = null;
+ }
+
@Before
public void setUpBase() {
mTestInjector.setUp();
@@ -657,12 +669,11 @@ class ActivityTestsBase {
private static WindowManagerService sMockWindowManagerService;
private static WindowManagerService prepareMockWindowManager() {
- if (sMockWindowManagerService != null) {
- return sMockWindowManagerService;
+ if (sMockWindowManagerService == null) {
+ sMockWindowManagerService = mock(WindowManagerService.class);
}
- final WindowManagerService service = mock(WindowManagerService.class);
- service.mRoot = mock(RootWindowContainer.class);
+ sMockWindowManagerService.mRoot = mock(RootWindowContainer.class);
doAnswer((InvocationOnMock invocationOnMock) -> {
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
@@ -670,10 +681,9 @@ class ActivityTestsBase {
runnable.run();
}
return null;
- }).when(service).inSurfaceTransaction(any());
+ }).when(sMockWindowManagerService).inSurfaceTransaction(any());
- sMockWindowManagerService = service;
- return service;
+ return sMockWindowManagerService;
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 67ee4ad91d91..94def2bb7846 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -67,6 +67,7 @@ import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -142,7 +143,8 @@ public class RootActivityContainerTests extends ActivityTestsBase {
private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) {
final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
- assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
+ assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks,
+ stackTasks.size(), tasks != null ? tasks.length : 0);
if (tasks == null) {
return;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index b151fb7a613c..1c1fe29bd7cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -88,6 +88,7 @@ class TestSystemServices {
sPolicy = null;
sMockitoSession.finishMocking();
+ sMockitoSession = null;
}
private static void setUpTestWindowService() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3cb28140e2ea..a83bf2af613e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -50,6 +50,7 @@ import android.view.IWindow;
import android.view.WindowManager;
import com.android.server.AttributeCache;
+import com.android.server.wm.utils.MockTracker;
import org.junit.After;
import org.junit.AfterClass;
@@ -77,6 +78,8 @@ class WindowTestsBase {
private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
static int sNextStackId = 1000;
+ private static MockTracker sMockTracker;
+
/** Non-default display. */
DisplayContent mDisplayContent;
DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -109,11 +112,18 @@ class WindowTestsBase {
TestSystemServices.setUpWindowManagerService();
+ // MockTracker needs to be initialized after TestSystemServices because we don't want to
+ // track static mocks.
+ sMockTracker = new MockTracker();
+
sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
}
@AfterClass
- public static void tearDonwOnceBase() {
+ public static void tearDownOnceBase() {
+ sMockTracker.close();
+ sMockTracker = null;
+
TestSystemServices.tearDownWindowManagerService();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index b6b9a861a282..2970c211e29c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -34,8 +34,8 @@ import android.content.Context;
import android.platform.test.annotations.Presubmit;
import android.testing.DexmakerShareClassLoaderRule;
import android.util.proto.ProtoOutputStream;
+import android.view.Choreographer;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.internal.util.Preconditions;
@@ -74,6 +74,8 @@ public class WindowTracingTest {
@Mock
private WindowManagerService mWmMock;
+ @Mock
+ private Choreographer mChoreographer;
private WindowTracing mWindowTracing;
private File mFile;
@@ -85,7 +87,9 @@ public class WindowTracingTest {
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
- mWindowTracing = new WindowTracing(mFile);
+ mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
+ new WindowManagerGlobalLock());
+ mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
}
@After
@@ -113,15 +117,14 @@ public class WindowTracingTest {
@Test
public void trace_discared_whenNotTracing() {
- mWindowTracing.traceStateLocked("where", mWmMock);
+ mWindowTracing.logState("where");
verifyZeroInteractions(mWmMock);
}
@Test
public void trace_dumpsWindowManagerState_whenTracing() throws Exception {
mWindowTracing.startTrace(mock(PrintWriter.class));
- mWindowTracing.traceStateLocked("where", mWmMock);
-
+ mWindowTracing.logState("where");
verify(mWmMock).writeToProtoLocked(any(), eq(WindowTraceLogLevel.TRIM));
}
@@ -147,7 +150,7 @@ public class WindowTracingTest {
WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
return null;
}).when(mWmMock).writeToProtoLocked(any(), any());
- mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock);
+ mWindowTracing.logState("TEST_WHERE");
mWindowTracing.stopTrace(mock(PrintWriter.class));
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
new file mode 100644
index 000000000000..1ce463bbbd9e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+import android.util.Log;
+
+import org.mockito.Mockito;
+import org.mockito.MockitoFramework;
+import org.mockito.internal.creation.settings.CreationSettings;
+import org.mockito.listeners.MockCreationListener;
+import org.mockito.mock.MockCreationSettings;
+
+import java.lang.reflect.Field;
+import java.util.IdentityHashMap;
+
+/**
+ * An util class used to track mock creation, and reset them when closing. Note only one instance is
+ * allowed at anytime, as Mockito framework throws exception if there is already a listener of the
+ * same type registered.
+ */
+public class MockTracker implements MockCreationListener, AutoCloseable {
+ private static final String TAG = "MockTracker";
+
+ private static final Field SPIED_INSTANCE_FIELD;
+
+ static {
+ try {
+ SPIED_INSTANCE_FIELD = CreationSettings.class.getDeclaredField("spiedInstance");
+ SPIED_INSTANCE_FIELD.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final MockitoFramework mMockitoFramework = Mockito.framework();
+
+ private final IdentityHashMap<Object, Void> mMocks = new IdentityHashMap<>();
+
+ public MockTracker() {
+ mMockitoFramework.addListener(this);
+ }
+
+ @Override
+ public void onMockCreated(Object mock, MockCreationSettings settings) {
+ mMocks.put(mock, null);
+ clearSpiedInstanceIfNeeded(mock, settings);
+ }
+
+ // HACK: Changing Mockito core implementation details.
+ // TODO(b/123984854): Remove this once there is a real fix.
+ private void clearSpiedInstanceIfNeeded(Object mock, MockCreationSettings settings) {
+ if (mock != settings.getSpiedInstance()) {
+ // Not a spyOn instance.
+ return;
+ }
+ if (!(settings instanceof CreationSettings)) {
+ throw new IllegalStateException("Unexpected type of settings: " + settings.getClass());
+ }
+ try {
+ SPIED_INSTANCE_FIELD.set(settings, null);
+ Log.d(TAG, "Setting spiedInstance for " + mock + " to null.");
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void close() {
+ mMockitoFramework.removeListener(this);
+
+ for (final Object mock : mMocks.keySet()) {
+ try {
+ Mockito.reset(mock);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to reset " + mock, e);
+ }
+ }
+ mMocks.clear();
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 873ada05bc27..731cbf42eca7 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -840,7 +840,8 @@ public class AppTimeLimitController {
*/
public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed,
long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) {
- if (timeLimit < getMinTimeLimit()) {
+ // Allow the special case of the limit being 0, but with no callback.
+ if (timeLimit != 0L && timeLimit < getMinTimeLimit()) {
throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
}
synchronized (mLock) {
@@ -858,7 +859,7 @@ public class AppTimeLimitController {
"Too many app usage observers added by uid " + requestingUid);
}
group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit,
- callbackIntent);
+ timeLimit == 0L ? null : callbackIntent);
observerApp.appUsageLimitGroups.append(observerId, group);
if (DEBUG) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index df2f45512465..af5278f222b8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1377,7 +1377,7 @@ public class UsageStatsService extends SystemService implements
if (packages == null || packages.length == 0) {
throw new IllegalArgumentException("Must specify at least one package");
}
- if (callbackIntent == null) {
+ if (callbackIntent == null && timeLimitMs != 0L) {
throw new NullPointerException("callbackIntent can't be null");
}
final int callingUid = Binder.getCallingUid();
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index aac0956d4339..e43b2b715321 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -22,7 +22,6 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -163,9 +162,7 @@ public class DefaultDialerManager {
final Intent dialIntentWithTelScheme = new Intent(Intent.ACTION_DIAL);
dialIntentWithTelScheme.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, "", null));
- packageNames = filterByIntent(context, packageNames, dialIntentWithTelScheme, userId);
- packageNames = requireInCallService(packageNames, userId, context);
- return packageNames;
+ return filterByIntent(context, packageNames, dialIntentWithTelScheme, userId);
}
public static List<String> getInstalledDialerApplications(Context context) {
@@ -223,35 +220,6 @@ public class DefaultDialerManager {
return result;
}
- private static List<String> requireInCallService(List<String> packageNames, int userId,
- Context context) {
- if (packageNames == null || packageNames.isEmpty()) {
- return new ArrayList<>();
- }
-
- final Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
- final List<ResolveInfo> resolveInfoList = context.getPackageManager()
- .queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, userId);
- final List<String> result = new ArrayList<>();
- final int length = resolveInfoList.size();
- for (int i = 0; i < length; i++) {
- final ServiceInfo info = resolveInfoList.get(i).serviceInfo;
- if (info == null || info.metaData == null) {
- continue;
- }
- if (!info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_UI)) {
- continue;
- }
- if (info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI)) {
- continue;
- }
- if (packageNames.contains(info.packageName) && !result.contains(info.packageName)) {
- result.add(info.packageName);
- }
- }
-
- return result;
- }
private static TelecomManager getTelecomManager(Context context) {
return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 068b68eeb73b..0c63b60b030d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2589,6 +2589,16 @@ public class CarrierConfigManager {
}
}
+ /**
+ * An int array containing CDMA enhanced roaming indicator values for Home (non-roaming) network.
+ * The default values come from 3GPP2 C.R1001 table 8.1-1.
+ * Enhanced Roaming Indicator Number Assignments
+ *
+ * @hide
+ */
+ public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY =
+ "cdma_enhanced_roaming_indicator_for_home_network_int_array";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -2966,6 +2976,10 @@ public class CarrierConfigManager {
/* Default value is 10 seconds. */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
sDefaults.putAll(Gps.getDefaults());
+ sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
+ new int[] {
+ 1 /* Roaming Indicator Off */
+ });
}
/**
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index b9ec7bf56370..9d78bf4bfb53 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -334,8 +334,7 @@ public final class TelephonyPermissions {
// settings to individually disable the new restrictions for privileged, preloaded
// non-privileged, and non-preinstalled apps.
if (!isIdentifierCheckDisabled() && (
- (isPrivApp && !relaxPrivDeviceIdentifierCheck)
- || (!isPreinstalled && !relax3PDeviceIdentifierCheck)
+ (!isPreinstalled && !relax3PDeviceIdentifierCheck)
|| (isPreinstalled && !isPrivApp && !relaxNonPrivDeviceIdentifierCheck))) {
// The current package should only be reported in StatsLog if it has not previously been
// reported for the currently invoked device identifier method.
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index 29f10e932e48..b3b5b2903471 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -61,6 +61,7 @@ public class TlvBufferUtils {
public static class TlvConstructor {
private int mTypeSize;
private int mLengthSize;
+ private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
private byte[] mArray;
private int mArrayLength;
@@ -84,6 +85,20 @@ public class TlvBufferUtils {
}
mTypeSize = typeSize;
mLengthSize = lengthSize;
+ mPosition = 0;
+ }
+
+ /**
+ * Configure the TLV constructor to use a particular byte order. Should be
+ * {@link ByteOrder#BIG_ENDIAN} (the default at construction) or
+ * {@link ByteOrder#LITTLE_ENDIAN}.
+ *
+ * @return The constructor to facilitate chaining
+ * {@code ctr.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor setByteOrder(ByteOrder byteOrder) {
+ mByteOrder = byteOrder;
+ return this;
}
/**
@@ -96,6 +111,7 @@ public class TlvBufferUtils {
public TlvConstructor wrap(@Nullable byte[] array) {
mArray = array;
mArrayLength = (array == null) ? 0 : array.length;
+ mPosition = 0;
return this;
}
@@ -109,6 +125,7 @@ public class TlvBufferUtils {
public TlvConstructor allocate(int capacity) {
mArray = new byte[capacity];
mArrayLength = capacity;
+ mPosition = 0;
return this;
}
@@ -155,6 +172,18 @@ public class TlvBufferUtils {
}
/**
+ * Copies a raw byte into the TLV buffer - without a type or a length.
+ *
+ * @param b The byte to be inserted into the structure.
+ * @return The constructor to facilitate chaining {@code cts.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor putRawByte(byte b) {
+ checkRawLength(1);
+ mArray[mPosition++] = b;
+ return this;
+ }
+
+ /**
* Copies a byte array into the TLV with the indicated type. For an LV
* formatted structure (i.e. typeLength=0 in {@link TlvConstructor
* TlvConstructor(int, int)} ) the type field is ignored.
@@ -193,6 +222,22 @@ public class TlvBufferUtils {
}
/**
+ * Copies a byte array into the TLV - without a type or a length.
+ *
+ * @param array The array to be copied (in full) into the TLV structure.
+ * @return The constructor to facilitate chaining
+ * {@code ctr.putXXX(..).putXXX(..)}.
+ */
+ public TlvConstructor putRawByteArray(@Nullable byte[] array) {
+ if (array == null) return this;
+
+ checkRawLength(array.length);
+ System.arraycopy(array, 0, mArray, mPosition, array.length);
+ mPosition += array.length;
+ return this;
+ }
+
+ /**
* Places a zero length element (i.e. Length field = 0) into the TLV.
* For an LV formatted structure (i.e. typeLength=0 in
* {@link TlvConstructor TlvConstructor(int, int)} ) the type field is
@@ -221,7 +266,7 @@ public class TlvBufferUtils {
public TlvConstructor putShort(int type, short data) {
checkLength(2);
addHeader(type, 2);
- Memory.pokeShort(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, data, mByteOrder);
mPosition += 2;
return this;
}
@@ -239,7 +284,7 @@ public class TlvBufferUtils {
public TlvConstructor putInt(int type, int data) {
checkLength(4);
addHeader(type, 4);
- Memory.pokeInt(mArray, mPosition, data, ByteOrder.BIG_ENDIAN);
+ Memory.pokeInt(mArray, mPosition, data, mByteOrder);
mPosition += 4;
return this;
}
@@ -294,18 +339,24 @@ public class TlvBufferUtils {
}
}
+ private void checkRawLength(int dataLength) {
+ if (mPosition + dataLength > mArrayLength) {
+ throw new BufferOverflowException();
+ }
+ }
+
private void addHeader(int type, int length) {
if (mTypeSize == 1) {
mArray[mPosition] = (byte) type;
} else if (mTypeSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) type, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
}
mPosition += mTypeSize;
if (mLengthSize == 1) {
mArray[mPosition] = (byte) length;
} else if (mLengthSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) length, ByteOrder.BIG_ENDIAN);
+ Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
}
mPosition += mLengthSize;
}
@@ -330,13 +381,19 @@ public class TlvBufferUtils {
public int length;
/**
+ * Control of the endianess of the TLV element - true for big-endian, false for little-
+ * endian.
+ */
+ public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
+
+ /**
* The Value (V) field - a raw byte array representing the current TLV
* element where the entry starts at {@link TlvElement#offset}.
*/
- public byte[] refArray;
+ private byte[] mRefArray;
/**
- * The offset to be used into {@link TlvElement#refArray} to access the
+ * The offset to be used into {@link TlvElement#mRefArray} to access the
* raw data representing the current TLV element.
*/
public int offset;
@@ -344,7 +401,7 @@ public class TlvBufferUtils {
private TlvElement(int type, int length, @Nullable byte[] refArray, int offset) {
this.type = type;
this.length = length;
- this.refArray = refArray;
+ mRefArray = refArray;
this.offset = offset;
if (offset + length > refArray.length) {
@@ -353,6 +410,15 @@ public class TlvBufferUtils {
}
/**
+ * Return the raw byte array of the Value (V) field.
+ *
+ * @return The Value (V) field as a byte array.
+ */
+ public byte[] getRawData() {
+ return Arrays.copyOfRange(mRefArray, offset, offset + length);
+ }
+
+ /**
* Utility function to return a byte representation of a TLV element of
* length 1. Note: an attempt to call this function on a TLV item whose
* {@link TlvElement#length} is != 1 will result in an exception.
@@ -364,7 +430,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a byte from a TLV element of length " + length);
}
- return refArray[offset];
+ return mRefArray[offset];
}
/**
@@ -379,7 +445,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a short from a TLV element of length " + length);
}
- return Memory.peekShort(refArray, offset, ByteOrder.BIG_ENDIAN);
+ return Memory.peekShort(mRefArray, offset, byteOrder);
}
/**
@@ -394,7 +460,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing an int from a TLV element of length " + length);
}
- return Memory.peekInt(refArray, offset, ByteOrder.BIG_ENDIAN);
+ return Memory.peekInt(mRefArray, offset, byteOrder);
}
/**
@@ -403,7 +469,7 @@ public class TlvBufferUtils {
* @return String repersentation of the current TLV element.
*/
public String getString() {
- return new String(refArray, offset, length);
+ return new String(mRefArray, offset, length);
}
}
@@ -413,6 +479,7 @@ public class TlvBufferUtils {
public static class TlvIterable implements Iterable<TlvElement> {
private int mTypeSize;
private int mLengthSize;
+ private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
private byte[] mArray;
private int mArrayLength;
@@ -440,6 +507,13 @@ public class TlvBufferUtils {
}
/**
+ * Configure the TLV iterator to use little-endian byte ordering.
+ */
+ public void setByteOrder(ByteOrder byteOrder) {
+ mByteOrder = byteOrder;
+ }
+
+ /**
* Prints out a parsed representation of the TLV-formatted byte array.
* Whenever possible bytes, shorts, and integer are printed out (for
* fields whose length is 1, 2, or 4 respectively).
@@ -486,7 +560,7 @@ public class TlvBufferUtils {
public List<byte[]> toList() {
List<byte[]> list = new ArrayList<>();
for (TlvElement tlv : this) {
- list.add(Arrays.copyOfRange(tlv.refArray, tlv.offset, tlv.offset + tlv.length));
+ list.add(Arrays.copyOfRange(tlv.mRefArray, tlv.offset, tlv.offset + tlv.length));
}
return list;
@@ -516,7 +590,7 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
type = mArray[mOffset];
} else if (mTypeSize == 2) {
- type = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+ type = Memory.peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mTypeSize;
@@ -524,11 +598,12 @@ public class TlvBufferUtils {
if (mLengthSize == 1) {
length = mArray[mOffset];
} else if (mLengthSize == 2) {
- length = Memory.peekShort(mArray, mOffset, ByteOrder.BIG_ENDIAN);
+ length = Memory.peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mLengthSize;
TlvElement tlv = new TlvElement(type, length, mArray, mOffset);
+ tlv.byteOrder = mByteOrder;
mOffset += length;
return tlv;
}
@@ -543,7 +618,8 @@ public class TlvBufferUtils {
/**
* Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
- * fields correctly fill the specified length (and do not overshoot).
+ * fields correctly fill the specified length (and do not overshoot). Uses big-endian
+ * byte ordering.
*
* @param array The (T)LV array to verify.
* @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
@@ -551,6 +627,22 @@ public class TlvBufferUtils {
* @return A boolean indicating whether the array is valid (true) or invalid (false).
*/
public static boolean isValid(@Nullable byte[] array, int typeSize, int lengthSize) {
+ return isValidEndian(array, typeSize, lengthSize, ByteOrder.BIG_ENDIAN);
+ }
+
+ /**
+ * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length
+ * fields correctly fill the specified length (and do not overshoot).
+ *
+ * @param array The (T)LV array to verify.
+ * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2.
+ * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2.
+ * @param byteOrder The endianness of the byte array: {@link ByteOrder#BIG_ENDIAN} or
+ * {@link ByteOrder#LITTLE_ENDIAN}.
+ * @return A boolean indicating whether the array is valid (true) or invalid (false).
+ */
+ public static boolean isValidEndian(@Nullable byte[] array, int typeSize, int lengthSize,
+ ByteOrder byteOrder) {
if (typeSize < 0 || typeSize > 2) {
throw new IllegalArgumentException(
"Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize);
@@ -569,8 +661,7 @@ public class TlvBufferUtils {
if (lengthSize == 1) {
nextTlvIndex += lengthSize + array[nextTlvIndex];
} else {
- nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex,
- ByteOrder.BIG_ENDIAN);
+ nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 83affed0b4e0..971aa8e05df2 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -28,6 +28,7 @@ import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;
+
/**
* Unit test harness for TlvBufferUtils class.
*/
@@ -69,6 +70,24 @@ public class TlvBufferUtilsTest {
}
/**
+ * Validate that re-using a TLV by any of the reallocation method resets it completely.
+ */
+ @Test
+ public void testTlvReuse() {
+ TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);
+
+ tlv.allocate(10);
+ tlv.putByte(0, (byte) 2);
+ tlv.putByte(1, (byte) 104);
+
+ collector.checkThat("initial", tlv.getArray(), equalTo(new byte[]{0, 1, 2, 1, 1, 104}));
+
+ tlv.allocate(8);
+ tlv.putByte(5, (byte) 7);
+ collector.checkThat("re-alloc", tlv.getArray(), equalTo(new byte[]{5, 1, 7}));
+ }
+
+ /**
* Verify that can build a valid TLV from a List of byte[].
*/
@Test
@@ -121,6 +140,23 @@ public class TlvBufferUtilsTest {
List<byte[]> data = new TlvBufferUtils.TlvIterable(0, 1, invalidTlv01).toList();
}
+ /**
+ * Validate the API which places raw bytes into the TLV (without a TL structure).
+ */
+ @Test
+ public void testRawPuts() {
+ TlvBufferUtils.TlvConstructor tlv = new TlvBufferUtils.TlvConstructor(1, 1);
+
+ tlv.allocate(10);
+ tlv.putByte(0, (byte) 2);
+ tlv.putRawByte((byte) 55);
+ tlv.putByte(1, (byte) 104);
+ tlv.putRawByteArray(new byte[]{66, 77});
+
+ collector.checkThat("data", tlv.getArray(),
+ equalTo(new byte[]{0, 1, 2, 55, 1, 1, 104, 66, 77}));
+ }
+
@Test
public void testTlvIterate() {
final String ascii = "ABC";
@@ -163,6 +199,7 @@ public class TlvBufferUtilsTest {
tlv02.putByte(0, (byte) 2);
tlv02.putString(0, ascii);
tlv02.putString(0, nonAscii);
+ tlv02.putByteArray(0, new byte[]{5, 4, 3, 2, 1});
TlvBufferUtils.TlvIterable tlv02It = new TlvBufferUtils.TlvIterable(0, 2, tlv02.getArray());
count = 0;
@@ -181,6 +218,11 @@ public class TlvBufferUtilsTest {
equalTo(nonAscii.getBytes().length));
collector.checkThat("tlv02-correct-iteration-DATA",
tlv.getString().equals(nonAscii), equalTo(true));
+ } else if (count == 3) {
+ collector.checkThat("tlv02-correct-iteration-mLength", tlv.length,
+ equalTo(5));
+ collector.checkThat("tlv02-correct-iteration-DATA", tlv.getRawData(),
+ equalTo(new byte[]{5, 4, 3, 2, 1}));
} else {
collector.checkThat("Invalid number of iterations in loop - tlv02", true,
equalTo(false));
@@ -188,7 +230,7 @@ public class TlvBufferUtilsTest {
++count;
}
collector.checkThat("Invalid number of iterations outside loop - tlv02", count,
- equalTo(3));
+ equalTo(4));
collector.checkThat("tlv22-valid",
TlvBufferUtils.isValid(tlv22.getArray(), 2, 2),