Merge "Delaying populating APEX cache until boot is completed."
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
index e417ca7..c1362dc 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
@@ -60,11 +60,13 @@
if (size == 0) {
return 0f;
}
- Collections.sort(mResults);
+
+ final ArrayList<Long> resultsCopy = new ArrayList<>(mResults);
+ Collections.sort(resultsCopy);
final int idx = size / 2;
return size % 2 == 0
- ? (double) (mResults.get(idx) + mResults.get(idx - 1)) / 2
- : mResults.get(idx);
+ ? (double) (resultsCopy.get(idx) + resultsCopy.get(idx - 1)) / 2
+ : resultsCopy.get(idx);
}
private double standardDeviation() {
diff --git a/api/current.txt b/api/current.txt
index c8f5662..7e0156f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5478,7 +5478,7 @@
method public android.graphics.drawable.Icon getIcon();
method public android.app.PendingIntent getIntent();
method public boolean getSuppressInitialNotification();
- method public CharSequence getTitle();
+ method @Deprecated public CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
}
@@ -5492,7 +5492,7 @@
method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
method public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
- method public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
+ method @Deprecated public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
}
public static class Notification.Builder {
@@ -11375,6 +11375,7 @@
method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getMySessions();
method @Nullable public android.content.pm.PackageInstaller.SessionInfo getSessionInfo(int);
method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getStagedSessions();
+ method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.INSTALL_EXISTING_PACKAGES"}) public void installExistingPackage(@NonNull String, int, @Nullable android.content.IntentSender);
method @NonNull public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException;
method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback);
method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler);
@@ -11475,7 +11476,6 @@
method public void setAppIcon(@Nullable android.graphics.Bitmap);
method public void setAppLabel(@Nullable CharSequence);
method public void setAppPackageName(@Nullable String);
- method public void setInstallAsApex();
method public void setInstallLocation(int);
method public void setInstallReason(int);
method public void setMultiPackage();
@@ -23385,7 +23385,7 @@
}
public static final class AudioPlaybackCaptureConfiguration.Builder {
- ctor public AudioPlaybackCaptureConfiguration.Builder();
+ ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection);
method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes);
method public android.media.AudioPlaybackCaptureConfiguration build();
@@ -29989,7 +29989,7 @@
method @Deprecated public boolean reconnect();
method @Deprecated public boolean removeNetwork(int);
method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
- method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public void removePasspointConfiguration(String);
+ method @Deprecated @RequiresPermission("android.permission.NETWORK_SETTINGS") public void removePasspointConfiguration(String);
method @Deprecated public boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(String, boolean);
@@ -38834,6 +38834,7 @@
field public static final String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
field public static final String ACTION_NIGHT_DISPLAY_SETTINGS = "android.settings.NIGHT_DISPLAY_SETTINGS";
+ field public static final String ACTION_NOTIFICATION_ASSISTANT_SETTINGS = "android.settings.NOTIFICATION_ASSISTANT_SETTINGS";
field public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
@@ -43341,11 +43342,11 @@
public final class CallIdentification implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public String getCallScreeningAppName();
+ method @NonNull public CharSequence getCallScreeningAppName();
method @NonNull public String getCallScreeningPackageName();
- method @Nullable public String getDescription();
- method @Nullable public String getDetails();
- method @Nullable public String getName();
+ method @Nullable public CharSequence getDescription();
+ method @Nullable public CharSequence getDetails();
+ method @Nullable public CharSequence getName();
method public int getNuisanceConfidence();
method @Nullable public android.graphics.drawable.Icon getPhoto();
method public void writeToParcel(android.os.Parcel, int);
@@ -43360,9 +43361,9 @@
public static class CallIdentification.Builder {
ctor public CallIdentification.Builder();
method public android.telecom.CallIdentification build();
- method public android.telecom.CallIdentification.Builder setDescription(@Nullable String);
- method public android.telecom.CallIdentification.Builder setDetails(@Nullable String);
- method public android.telecom.CallIdentification.Builder setName(@Nullable String);
+ method public android.telecom.CallIdentification.Builder setDescription(@Nullable CharSequence);
+ method public android.telecom.CallIdentification.Builder setDetails(@Nullable CharSequence);
+ method public android.telecom.CallIdentification.Builder setName(@Nullable CharSequence);
method public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
method public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index bcc10c1..b580deb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1305,8 +1305,8 @@
}
public abstract class ContentResolver {
- method @Nullable public android.os.Bundle getCache(@NonNull android.net.Uri);
- method public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
+ method @Nullable @RequiresPermission("android.permission.CACHE_CONTENT") public android.os.Bundle getCache(@NonNull android.net.Uri);
+ method @RequiresPermission("android.permission.CACHE_CONTENT") public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
}
public abstract class Context {
@@ -1558,6 +1558,7 @@
method public void setDontKillApp(boolean);
method public void setEnableRollback();
method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
method public void setInstallAsInstantApp(boolean);
method public void setInstallAsVirtualPreload();
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
@@ -1576,6 +1577,7 @@
method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract boolean arePermissionsIndividuallyControlled();
method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+ method public boolean getAppDetailsActivityEnabled(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public android.content.pm.dex.ArtManager getArtManager();
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
@@ -1591,8 +1593,8 @@
method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- method public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public abstract int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method @Deprecated public abstract int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
@@ -1602,6 +1604,7 @@
method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method public void sendDeviceCustomizationReadyBroadcast();
+ method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setAppDetailsActivityEnabled(@NonNull String, boolean);
method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
@@ -4665,7 +4668,10 @@
}
public class WifiInfo implements android.os.Parcelable {
+ method @Nullable public String getFqdn();
+ method @Nullable public String getProviderFriendlyName();
method public boolean isOsuAp();
+ method public boolean isPasspointAp();
}
public class WifiManager {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 4deb8bd..69fbf1f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1200,9 +1200,9 @@
userid_t userId = multiuser_get_user_id(uid);
- bool requiresStaging = options | IStatsManager::FLAG_REQUIRE_STAGING;
- bool rollbackEnabled = options | IStatsManager::FLAG_ROLLBACK_ENABLED;
- bool requiresLowLatencyMonitor = options | IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
+ bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
ProtoOutputStream proto;
for (const auto& expId : experimentIds) {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index c8f7728..28caede 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -56,6 +56,25 @@
class ValueMetricProducerTestHelper {
public:
+ static sp<ValueMetricProducer> createValueProducerNoConditions(
+ sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
+ UidMap uidMap;
+ SimpleAtomMatcher atomMatcher;
+ atomMatcher.set_atom_id(tagId);
+ sp<EventMatcherWizard> eventMatcherWizard =
+ new EventMatcherWizard({new SimpleLogMatchingTracker(
+ atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+ EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+ sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+ kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ return valueProducer;
+ }
+
static sp<ValueMetricProducer> createValueProducerWithCondition(
sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
UidMap uidMap;
@@ -75,6 +94,22 @@
valueProducer->mCondition = ConditionState::kFalse;
return valueProducer;
}
+
+ static ValueMetric createMetric() {
+ ValueMetric metric;
+ metric.set_id(metricId);
+ metric.set_bucket(ONE_MINUTE);
+ metric.mutable_value_field()->set_field(tagId);
+ metric.mutable_value_field()->add_child()->set_field(2);
+ metric.set_max_pull_delay_sec(INT_MAX);
+ return metric;
+ }
+
+ static ValueMetric createMetricWithCondition() {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ metric.set_condition(StringToId("SCREEN_ON"));
+ return metric;
+ }
};
@@ -82,11 +117,7 @@
* Tests that the first bucket works correctly
*/
TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
int64_t startTimeBase = 11;
UidMap uidMap;
@@ -116,11 +147,7 @@
* Tests that the first bucket works correctly
*/
TEST(ValueMetricProducerTest, TestFirstBucket) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -146,23 +173,8 @@
* Tests pulled atoms with no conditions
*/
TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
-
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
@@ -174,9 +186,8 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -186,17 +197,17 @@
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -204,19 +215,19 @@
event->write(23);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(23, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(12, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -224,39 +235,24 @@
event->write(36);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(13, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
- EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second[2].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
}
TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
-
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _))
// Initialize bucket.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -279,9 +275,8 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
// First bucket ends.
vector<shared_ptr<LogEvent>> allData;
@@ -291,14 +286,14 @@
event->write(2);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
// Partial buckets created in 2nd bucket.
- valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
+ valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
// One full bucket and one partial bucket.
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- vector<ValueBucket> buckets = valueProducer.mPastBuckets.begin()->second;
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ vector<ValueBucket> buckets = valueProducer->mPastBuckets.begin()->second;
EXPECT_EQ(2UL, buckets.size());
// Full bucket (2 - 1)
EXPECT_EQ(1, buckets[0].values[0].long_value);
@@ -310,12 +305,7 @@
* Tests pulled atoms with filtering
*/
TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -341,9 +331,10 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+ kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -353,18 +344,18 @@
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
ValueMetricProducer::Interval curInterval =
- valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -372,16 +363,16 @@
event->write(23);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// No new data seen, so data has been cleared.
- EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(8, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -389,46 +380,30 @@
event->write(36);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
// the base was reset
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
}
/*
* Tests pulled atoms with no conditions and take absolute value after reset
*/
TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_use_absolute_value_on_reset(true);
- metric.set_max_pull_delay_sec(INT_MAX);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -438,15 +413,15 @@
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -454,16 +429,16 @@
event->write(10);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -471,45 +446,28 @@
event->write(36);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
- EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+ EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
}
/*
* Tests pulled atoms with no conditions and take zero value after reset
*/
TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
-
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -519,15 +477,15 @@
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -535,14 +493,14 @@
event->write(10);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -550,28 +508,22 @@
event->write(36);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
EXPECT_EQ(26, curInterval.value.long_value);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
}
/*
* Test pulled event with non sliced condition.
*/
TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
@@ -639,11 +591,7 @@
}
TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -687,12 +635,7 @@
}
TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -750,12 +693,7 @@
}
TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_split_bucket_for_app_upgrade(false);
UidMap uidMap;
@@ -790,13 +728,7 @@
}
TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -836,11 +768,7 @@
}
TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -884,11 +812,7 @@
}
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -964,11 +888,7 @@
const int32_t refPeriodSec = 3;
alert.set_refractory_period_secs(refPeriodSec);
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -1045,28 +965,11 @@
// Test value metric no condition, the pull on bucket boundary come in time and too late
TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
-
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
vector<shared_ptr<LogEvent>> allData;
// pull 1
@@ -1077,16 +980,16 @@
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:true sum:0 start:11
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(11, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
// pull 2 at correct time
allData.clear();
@@ -1095,16 +998,16 @@
event->write(23);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// has one slice
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
// tartUpdated:false sum:12
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(23, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
// pull 3 come late.
// The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1116,16 +1019,16 @@
event->write(36);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:false sum:12
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
+ EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
}
/*
@@ -1133,13 +1036,7 @@
* was delivered late.
*/
TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -1207,13 +1104,7 @@
* change to false, and then true again. This is due to alarm delivered late.
*/
TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -1298,11 +1189,7 @@
}
TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::MIN);
UidMap uidMap;
@@ -1347,11 +1234,7 @@
}
TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::MAX);
UidMap uidMap;
@@ -1396,11 +1279,7 @@
}
TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::AVG);
UidMap uidMap;
@@ -1448,11 +1327,7 @@
}
TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::SUM);
UidMap uidMap;
@@ -1497,11 +1372,7 @@
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_aggregation_type(ValueMetric::MIN);
metric.set_use_diff(true);
@@ -1572,11 +1443,7 @@
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_value_field()->add_child()->set_field(3);
metric.set_aggregation_type(ValueMetric::MIN);
metric.set_use_diff(true);
@@ -1682,26 +1549,12 @@
* Tests zero default base.
*/
TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_use_zero_default_base(true);
- metric.set_max_pull_delay_sec(INT_MAX);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
@@ -1713,19 +1566,18 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- auto iter = valueProducer.mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(3, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(true, valueProducer.mHasGlobalBase);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1740,15 +1592,15 @@
allData.push_back(event1);
allData.push_back(event2);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(11, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
- auto it = valueProducer.mCurrentSlicedBucket.begin();
- for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
if (it != iter) {
break;
}
@@ -1761,8 +1613,8 @@
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
- auto iterator = valueProducer.mPastBuckets.begin();
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ auto iterator = valueProducer->mPastBuckets.begin();
EXPECT_EQ(8, iterator->second[0].values[0].long_value);
iterator++;
EXPECT_EQ(4, iterator->second[0].values[0].long_value);
@@ -1772,26 +1624,12 @@
* Tests using zero default base with failed pull.
*/
TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_use_zero_default_base(true);
- metric.set_max_pull_delay_sec(INT_MAX);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
@@ -1803,19 +1641,18 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- auto iter = valueProducer.mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(3, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(true, valueProducer.mHasGlobalBase);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1830,15 +1667,15 @@
allData.push_back(event1);
allData.push_back(event2);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(11, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
- auto it = valueProducer.mCurrentSlicedBucket.begin();
- for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
if (it != iter) {
break;
}
@@ -1850,7 +1687,7 @@
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(4, interval2.value.long_value);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
@@ -1859,16 +1696,16 @@
event1->write(5);
event1->init();
allData.push_back(event1);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval2.hasBase);
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(true, valueProducer.mHasGlobalBase);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
allData.clear();
event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1881,9 +1718,9 @@
event2->write(5);
event2->init();
allData.push_back(event2);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
- EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval2.hasBase);
EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
@@ -1892,33 +1729,19 @@
EXPECT_EQ(13, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
- EXPECT_EQ(true, valueProducer.mHasGlobalBase);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
}
/*
* Tests trim unused dimension key if no new data is seen in an entire bucket.
*/
TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
- metric.set_max_pull_delay_sec(INT_MAX);
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
@@ -1930,18 +1753,17 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- auto iter = valueProducer.mCurrentSlicedBucket.begin();
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ auto iter = valueProducer->mCurrentSlicedBucket.begin();
auto& interval1 = iter->second[0];
EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(3, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
- EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
vector<shared_ptr<LogEvent>> allData;
allData.clear();
@@ -1956,18 +1778,18 @@
allData.push_back(event1);
allData.push_back(event2);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
EXPECT_EQ(true, interval1.hasBase);
EXPECT_EQ(11, interval1.base.long_value);
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
EXPECT_FALSE(interval1.seenNewData);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
- EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+ EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
- auto it = valueProducer.mCurrentSlicedBucket.begin();
- for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
if (it != iter) {
break;
}
@@ -1979,7 +1801,7 @@
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
@@ -1988,17 +1810,17 @@
event1->write(5);
event1->init();
allData.push_back(event1);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
// Only one interval left. One was trimmed.
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
EXPECT_EQ(true, interval2.hasBase);
EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
allData.clear();
event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -2006,28 +1828,22 @@
event1->write(14);
event1->init();
allData.push_back(event1);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
- interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, interval2.hasBase);
EXPECT_EQ(14, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
- auto iterator = valueProducer.mPastBuckets.begin();
+ EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+ auto iterator = valueProducer->mPastBuckets.begin();
EXPECT_EQ(9, iterator->second[0].values[0].long_value);
iterator++;
EXPECT_EQ(8, iterator->second[0].values[0].long_value);
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
// Used by onConditionChanged.
@@ -2063,13 +1879,7 @@
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2108,13 +1918,7 @@
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2147,11 +1951,7 @@
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_condition(StringToId("SCREEN_ON"));
metric.set_max_pull_delay_sec(0);
@@ -2178,13 +1978,7 @@
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -2210,13 +2004,7 @@
}
TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2248,13 +2036,7 @@
}
TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2314,15 +2096,10 @@
}
TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2348,13 +2125,7 @@
}
TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2420,13 +2191,7 @@
}
TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2493,24 +2258,8 @@
}
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
-
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
EXPECT_CALL(*pullerManager, Pull(tagId, _))
// Start bucket.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2523,9 +2272,8 @@
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
// Bucket 2 start.
vector<shared_ptr<LogEvent>> allData;
@@ -2535,29 +2283,23 @@
event->write(110);
event->init();
allData.push_back(event);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+ EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
// Bucket 3 empty.
allData.clear();
shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
event2->init();
allData.push_back(event2);
- valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
// Data has been trimmed.
- EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
- EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+ EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
}
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2597,13 +2339,7 @@
}
TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2666,15 +2402,10 @@
}
TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2721,15 +2452,10 @@
}
TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.mutable_dimensions_in_what()->set_field(tagId);
metric.mutable_dimensions_in_what()->add_child()->set_field(1);
metric.set_condition(StringToId("SCREEN_ON"));
- metric.set_max_pull_delay_sec(INT_MAX);
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _))
@@ -2785,12 +2511,7 @@
}
TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -2832,12 +2553,7 @@
}
TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
@@ -2890,12 +2606,7 @@
}
TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
- ValueMetric metric;
- metric.set_id(metricId);
- metric.set_bucket(ONE_MINUTE);
- metric.mutable_value_field()->set_field(tagId);
- metric.mutable_value_field()->add_child()->set_field(2);
- metric.set_max_pull_delay_sec(INT_MAX);
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 0a26bfb..d2535c9 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -32983,7 +32983,7 @@
HSPLandroid/view/IWindowSession$Stub$Proxy;->getInTouchMode()Z
HSPLandroid/view/IWindowSession$Stub$Proxy;->getWindowId(Landroid/os/IBinder;)Landroid/view/IWindowId;
HSPLandroid/view/IWindowSession$Stub$Proxy;->onRectangleOnScreenRequested(Landroid/os/IBinder;Landroid/graphics/Rect;)V
-HSPLandroid/view/IWindowSession$Stub$Proxy;->performHapticFeedback(Landroid/view/IWindow;IZ)Z
+HSPLandroid/view/IWindowSession$Stub$Proxy;->performHapticFeedback(IZ)Z
HSPLandroid/view/IWindowSession$Stub$Proxy;->pokeDrawLock(Landroid/os/IBinder;)V
HSPLandroid/view/IWindowSession$Stub$Proxy;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIIJLandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
HSPLandroid/view/IWindowSession$Stub$Proxy;->remove(Landroid/view/IWindow;)V
@@ -33007,7 +33007,7 @@
HSPLandroid/view/IWindowSession;->onRectangleOnScreenRequested(Landroid/os/IBinder;Landroid/graphics/Rect;)V
HSPLandroid/view/IWindowSession;->outOfMemory(Landroid/view/IWindow;)Z
HSPLandroid/view/IWindowSession;->performDrag(Landroid/view/IWindow;ILandroid/view/SurfaceControl;IFFFFLandroid/content/ClipData;)Landroid/os/IBinder;
-HSPLandroid/view/IWindowSession;->performHapticFeedback(Landroid/view/IWindow;IZ)Z
+HSPLandroid/view/IWindowSession;->performHapticFeedback(IZ)Z
HSPLandroid/view/IWindowSession;->pokeDrawLock(Landroid/os/IBinder;)V
HSPLandroid/view/IWindowSession;->prepareToReplaceWindows(Landroid/os/IBinder;Z)V
HSPLandroid/view/IWindowSession;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIIJLandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 2abb631..aaff76e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1523,7 +1523,7 @@
Landroid/view/IWindowSession;->finishDrawing(Landroid/view/IWindow;)V
Landroid/view/IWindowSession;->getInTouchMode()Z
Landroid/view/IWindowSession;->performDrag(Landroid/view/IWindow;ILandroid/view/SurfaceControl;IFFFFLandroid/content/ClipData;)Landroid/os/IBinder;
-Landroid/view/IWindowSession;->performHapticFeedback(Landroid/view/IWindow;IZ)Z
+Landroid/view/IWindowSession;->performHapticFeedback(IZ)Z
Landroid/view/IWindowSession;->remove(Landroid/view/IWindow;)V
Landroid/view/IWindowSession;->setInTouchMode(Z)V
Landroid/view/IWindowSession;->setTransparentRegion(Landroid/view/IWindow;Landroid/graphics/Region;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a63350c..91fc188 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2387,8 +2387,8 @@
getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_CANCEL,
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
}
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
}
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_STOP);
mEnterAnimationComplete = false;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 8e5fc30..d3e3507 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2469,6 +2469,33 @@
}
@Override
+ public void setAppDetailsActivityEnabled(String packageName, boolean enabled) {
+ try {
+ ComponentName componentName = new ComponentName(packageName,
+ PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
+ mPM.setComponentEnabledSetting(componentName, enabled
+ ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP, getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public boolean getAppDetailsActivityEnabled(String packageName) {
+ try {
+ ComponentName componentName = new ComponentName(packageName,
+ PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
+ int state = mPM.getComponentEnabledSetting(componentName, getUserId());
+ return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags) {
try {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0166f52..2e7093d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8409,7 +8409,6 @@
private PendingIntent mPendingIntent;
private PendingIntent mDeleteIntent;
- private CharSequence mTitle;
private Icon mIcon;
private int mDesiredHeight;
private int mFlags;
@@ -8438,9 +8437,8 @@
private static final int FLAG_SUPPRESS_INITIAL_NOTIFICATION = 0x00000002;
private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
- CharSequence title, Icon icon, int height) {
+ Icon icon, int height) {
mPendingIntent = expandIntent;
- mTitle = title;
mIcon = icon;
mDesiredHeight = height;
mDeleteIntent = deleteIntent;
@@ -8448,7 +8446,6 @@
private BubbleMetadata(Parcel in) {
mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
- mTitle = in.readCharSequence();
mIcon = Icon.CREATOR.createFromParcel(in);
mDesiredHeight = in.readInt();
mFlags = in.readInt();
@@ -8474,11 +8471,13 @@
/**
* @return the title that will appear along with the app content defined by
* {@link #getIntent()} for this bubble.
+ *
+ * @deprecated titles are no longer required or shown.
*/
+ @Deprecated
public CharSequence getTitle() {
- return mTitle;
+ return "";
}
-
/**
* @return the icon that will be displayed for this bubble when it is collapsed.
*/
@@ -8534,7 +8533,6 @@
@Override
public void writeToParcel(Parcel out, int flags) {
mPendingIntent.writeToParcel(out, 0);
- out.writeCharSequence(mTitle);
mIcon.writeToParcel(out, 0);
out.writeInt(mDesiredHeight);
out.writeInt(mFlags);
@@ -8554,7 +8552,6 @@
public static class Builder {
private PendingIntent mPendingIntent;
- private CharSequence mTitle;
private Icon mIcon;
private int mDesiredHeight;
private int mFlags;
@@ -8583,12 +8580,11 @@
*
* <p>A title is required and should expect to fit on a single line and make sense when
* shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+ *
+ * @deprecated titles are no longer required or shown.
*/
+ @Deprecated
public BubbleMetadata.Builder setTitle(CharSequence title) {
- if (TextUtils.isEmpty(title)) {
- throw new IllegalArgumentException("Bubbles require non-null or empty title");
- }
- mTitle = title;
return this;
}
@@ -8667,13 +8663,10 @@
if (mPendingIntent == null) {
throw new IllegalStateException("Must supply pending intent to bubble");
}
- if (TextUtils.isEmpty(mTitle)) {
- throw new IllegalStateException("Must supply a title for the bubble");
- }
if (mIcon == null) {
throw new IllegalStateException("Must supply an icon for the bubble");
}
- BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent, mTitle,
+ BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent,
mIcon, mDesiredHeight);
data.setFlags(mFlags);
return data;
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 31521a3..7e07446 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -128,7 +128,13 @@
: InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
final long identity = Binder.clearCallingIdentity();
try {
- return InputManager.getInstance().injectInputEvent(event, mode);
+ IWindowManager manager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ try {
+ return manager.injectInputAfterTransactionsApplied(event, mode);
+ } catch (RemoteException e) {
+ }
+ return false;
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index c44520a..1e4b1e7 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3159,6 +3159,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public void putCache(@NonNull Uri key, @Nullable Bundle value) {
try {
getContentService().putCache(mContext.getPackageName(), key, value,
@@ -3178,6 +3179,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public @Nullable Bundle getCache(@NonNull Uri key) {
try {
final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index a251c00..0cf83fd 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -50,5 +50,8 @@
void uninstall(in VersionedPackage versionedPackage, String callerPackageName, int flags,
in IntentSender statusReceiver, int userId);
+ void installExistingPackage(String packageName, int installFlags, int installReason,
+ in IntentSender statusReceiver, int userId);
+
void setPermissionsResult(int sessionId, boolean accepted);
}
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b0d16cd..f87ce82 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -514,7 +514,8 @@
/**
* Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
- * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
+ * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. Result may include
+ * synthesized activities like app details Activity injected by system.
*
* @param packageName The specific package to query. If null, it checks all installed packages
* in the profile.
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8095473..6302071 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -590,6 +590,30 @@
}
}
+ /**
+ * Install the given package, which already exists on the device, for the user for which this
+ * installer was created.
+ *
+ * @param packageName The package to install.
+ * @param installReason Reason for install.
+ * @param statusReceiver Where to deliver the result.
+ */
+ @RequiresPermission(allOf = {
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.INSTALL_EXISTING_PACKAGES})
+ public void installExistingPackage(@NonNull String packageName,
+ @InstallReason int installReason,
+ @Nullable IntentSender statusReceiver) {
+ Preconditions.checkNotNull(packageName, "packageName cannot be null");
+ try {
+ mInstaller.installExistingPackage(packageName, 0, installReason, statusReceiver,
+ mUserId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+
/** {@hide} */
@SystemApi
@RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
@@ -1545,7 +1569,11 @@
/**
* Set this session to be installing an APEX package.
+ *
+ * {@hide}
*/
+ @SystemApi
+ @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
public void setInstallAsApex() {
installFlags |= PackageManager.INSTALL_APEX;
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0041921..5e70ecb 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -33,6 +33,7 @@
import android.annotation.UserIdInt;
import android.annotation.XmlRes;
import android.app.ActivityManager;
+import android.app.AppDetailsActivity;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
import android.app.admin.DevicePolicyManager;
@@ -3030,6 +3031,13 @@
public static final int MASK_PERMISSION_FLAGS = 0xFF;
/**
+ * Injected activity in app that forwards user to setting activity of that app.
+ *
+ * @hide
+ */
+ public static final String APP_DETAILS_ACTIVITY_CLASS_NAME = AppDetailsActivity.class.getName();
+
+ /**
* This is a library that contains components apps can invoke. For
* example, a services for apps to bind to, or standard chooser UI,
* etc. This library is versioned and backwards compatible. Clients
@@ -5114,7 +5122,10 @@
* If there is already an application with the given package name installed
* on the system for other users, also install it for the calling user.
* @hide
+ *
+ * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @Deprecated
@SystemApi
public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
@@ -5122,7 +5133,10 @@
* If there is already an application with the given package name installed
* on the system for other users, also install it for the calling user.
* @hide
+ *
+ * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @Deprecated
@SystemApi
public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
throws NameNotFoundException;
@@ -5131,7 +5145,10 @@
* If there is already an application with the given package name installed
* on the system for other users, also install it for the specified user.
* @hide
+ *
+ * @deprecated use {@link PackageInstaller#installExistingPackage()} instead.
*/
+ @Deprecated
@RequiresPermission(anyOf = {
Manifest.permission.INSTALL_EXISTING_PACKAGES,
Manifest.permission.INSTALL_PACKAGES,
@@ -5792,6 +5809,37 @@
@NonNull ComponentName componentName);
/**
+ * Set the enabled setting for a package app settings activity.
+ *
+ * @param packageName The package name of the app
+ * @param enabled The new enabled state for app details activity
+ *
+ * @hide
+ */
+ @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
+ conditional = true)
+ @SystemApi
+ public void setAppDetailsActivityEnabled(@NonNull String packageName, boolean enabled) {
+ throw new UnsupportedOperationException(
+ "setAppDetailsActivityEnabled not implemented");
+ }
+
+
+ /**
+ * Return the enabled setting for a package app settings activity.
+ *
+ * @param packageName The package name of the app
+ * @return Returns the current enabled state for app settings activity.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean getAppDetailsActivityEnabled(@NonNull String packageName) {
+ throw new UnsupportedOperationException(
+ "getAppDetailsActivityEnabled not implemented");
+ }
+
+ /**
* Set the enabled setting for an application
* This setting will override any enabled state which may have been set by the application in
* its manifest. It also overrides the enabled state set in the manifest for any of the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0f67262..4db7d0a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -48,7 +48,6 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
-import android.app.AppDetailsActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -725,6 +724,9 @@
for (int i = 0; i < N; i++) {
final Activity a = p.activities.get(i);
if (state.isMatch(a.info, flags)) {
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(a.className)) {
+ continue;
+ }
res[num++] = generateActivityInfo(a, flags, state, userId);
}
}
@@ -4311,7 +4313,7 @@
} else {
String outInfoName
= buildClassName(owner.applicationInfo.packageName, name, outError);
- if (AppDetailsActivity.class.getName().equals(outInfoName)) {
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
outError[0] = tag + " invalid android:name";
return false;
}
@@ -4364,13 +4366,14 @@
boolean hardwareAccelerated) {
// Build custom App Details activity info instead of parsing it from xml
- Activity a = new Activity(owner, AppDetailsActivity.class.getName(), new ActivityInfo());
+ Activity a = new Activity(owner, PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
+ new ActivityInfo());
a.owner = owner;
a.setPackageName(owner.packageName);
a.info.theme = android.R.style.Theme_NoDisplay;
a.info.exported = true;
- a.info.name = AppDetailsActivity.class.getName();
+ a.info.name = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
a.info.processName = owner.applicationInfo.processName;
a.info.uiOptions = a.info.applicationInfo.uiOptions;
a.info.taskAffinity = buildTaskAffinityName(owner.packageName, owner.packageName,
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6d195ae..c1bce5e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3147,9 +3147,9 @@
/**
* Called if no network is found in the timeout time specified in
- * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not
- * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
- * without timeout. When this callback is invoked the associated
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the
+ * requested network request cannot be fulfilled (whether or not a timeout was
+ * specified). When this callback is invoked the associated
* {@link NetworkRequest} will have already been removed and released, as if
* {@link #unregisterNetworkCallback(NetworkCallback)} had been called.
*/
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 0dfe7a4..5b1d12c 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -27,11 +27,13 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Protocol;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -113,7 +115,16 @@
*/
private static final int CMD_SET_FILTER = BASE + 3;
+ /**
+ * Sent by NetworkFactory to ConnectivityService to indicate that a request is
+ * unfulfillable.
+ * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest).
+ */
+ public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4;
+
private final Context mContext;
+ private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+ private AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private final SparseArray<NetworkRequestInfo> mNetworkRequests =
@@ -155,6 +166,36 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAsyncChannel != null) {
+ log("Received new connection while already connected!");
+ break;
+ }
+ if (VDBG) log("NetworkFactory fully connected");
+ AsyncChannel ac = new AsyncChannel();
+ ac.connected(null, this, msg.replyTo);
+ ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_SUCCESSFUL);
+ mAsyncChannel = ac;
+ for (Message m : mPreConnectedQueue) {
+ ac.sendMessage(m);
+ }
+ mPreConnectedQueue.clear();
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ if (VDBG) log("CMD_CHANNEL_DISCONNECT");
+ if (mAsyncChannel != null) {
+ mAsyncChannel.disconnect();
+ mAsyncChannel = null;
+ }
+ break;
+ }
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ if (DBG) log("NetworkFactory channel lost");
+ mAsyncChannel = null;
+ break;
+ }
case CMD_REQUEST_NETWORK: {
handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
break;
@@ -355,6 +396,27 @@
});
}
+ /**
+ * Can be called by a factory to release a request as unfulfillable: the request will be
+ * removed, and the caller will get a
+ * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function
+ * returns.
+ *
+ * Note: this should only be called by factory which KNOWS that it is the ONLY factory which
+ * is able to fulfill this request!
+ */
+ protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) {
+ post(() -> {
+ if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r);
+ Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r);
+ if (mAsyncChannel != null) {
+ mAsyncChannel.sendMessage(msg);
+ } else {
+ mPreConnectedQueue.add(msg);
+ }
+ });
+ }
+
// override to do simple mode (request independent)
protected void startNetwork() { }
protected void stopNetwork() { }
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 47b1eef..650d2178 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -664,8 +664,15 @@
.append(abi);
final String paths = sb.toString();
- if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths);
- setDriverPath(paths);
+ final String sphalLibraries =
+ coreSettings.getString(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES);
+
+ if (DEBUG) {
+ Log.v(TAG,
+ "gfx driver package search path: " + paths
+ + ", required sphal libraries: " + sphalLibraries);
+ }
+ setDriverPathAndSphalLibraries(paths, sphalLibraries);
if (driverAppInfo.metaData == null) {
throw new NullPointerException("apk's meta-data cannot be null");
@@ -700,7 +707,7 @@
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDebugLayersGLES(String layers);
- private static native void setDriverPath(String path);
+ private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index cd7bbfd..9d58064 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -519,7 +519,7 @@
}
@Override
- public void scheduleRequest(@NonNull PendingRequest<RemoteService,
+ public void scheduleRequest(@NonNull BasePendingRequest<RemoteService,
IPermissionController> pendingRequest) {
super.scheduleRequest(pendingRequest);
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index f63c0adb..44adc1c 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -783,7 +783,7 @@
String postDialDigits, String viaNumber, int presentation, int callType,
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
- boolean isRead, int callBlockReason, String callScreeningAppName,
+ boolean isRead, int callBlockReason, CharSequence callScreeningAppName,
String callScreeningComponentName, CallIdentification callIdentification) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
@@ -836,15 +836,19 @@
}
values.put(BLOCK_REASON, callBlockReason);
- values.put(CALL_SCREENING_APP_NAME, callScreeningAppName);
+ values.put(CALL_SCREENING_APP_NAME, charSequenceToString(callScreeningAppName));
values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
if (callIdentification != null) {
values.put(CALL_ID_PACKAGE_NAME, callIdentification.getCallScreeningPackageName());
- values.put(CALL_ID_APP_NAME, callIdentification.getCallScreeningAppName());
- values.put(CALL_ID_NAME, callIdentification.getName());
- values.put(CALL_ID_DESCRIPTION, callIdentification.getDescription());
- values.put(CALL_ID_DETAILS, callIdentification.getDetails());
+ values.put(CALL_ID_APP_NAME,
+ charSequenceToString(callIdentification.getCallScreeningAppName()));
+ values.put(CALL_ID_NAME,
+ charSequenceToString(callIdentification.getName()));
+ values.put(CALL_ID_DESCRIPTION,
+ charSequenceToString(callIdentification.getDescription()));
+ values.put(CALL_ID_DETAILS,
+ charSequenceToString(callIdentification.getDetails()));
values.put(CALL_ID_NUISANCE_CONFIDENCE, callIdentification.getNuisanceConfidence());
} else {
values.putNull(CALL_ID_PACKAGE_NAME);
@@ -987,6 +991,10 @@
return result;
}
+ private static String charSequenceToString(CharSequence sequence) {
+ return sequence == null ? null : sequence.toString();
+ }
+
/** @hide */
public static boolean shouldHaveSharedCallLogEntries(Context context,
UserManager userManager, int userId) {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f6a8388..868a36b 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -169,7 +169,7 @@
*
* @hide for internal use only
*/
- String BLASTULA_POOL_SIZE_MIN = "blastula_pool_size_max";
+ String BLASTULA_POOL_SIZE_MIN = "blastula_pool_size_min";
/**
* The threshold used to determine if the pool should be refilled.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1530626..1588718 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1204,6 +1204,21 @@
public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
/**
+ * Activity Action: Show Notification assistant settings.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ * @see android.service.notification.NotificationAssistantService
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_NOTIFICATION_ASSISTANT_SETTINGS =
+ "android.settings.NOTIFICATION_ASSISTANT_SETTINGS";
+
+ /**
* Activity Action: Show Notification listener settings.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -13047,6 +13062,15 @@
*/
public static final String LTE_SERVICE_FORCED = "lte_service_forced";
+
+ /**
+ * Specifies the behaviour the lid triggers when closed
+ * <p>
+ * See WindowManagerPolicy.WindowManagerFuncs
+ * @hide
+ */
+ public static final String LID_BEHAVIOR = "lid_behavior";
+
/**
* Ephemeral app cookie max size in bytes.
* <p>
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 2ef7c4b..5dc54a5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -582,4 +582,13 @@
* display should be re-parented to.
*/
void reparentDisplayContent(int displayId, in SurfaceControl sc);
+
+ /**
+ * Waits for transactions to get applied before injecting input.
+ * This includes waiting for the input windows to get sent to InputManager.
+ *
+ * This is needed for testing since the system add windows and injects input
+ * quick enough that the windows don't have time to get sent to InputManager.
+ */
+ boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode);
}
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 658f06a..240aad5 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -148,7 +148,7 @@
void setInTouchMode(boolean showFocus);
boolean getInTouchMode();
- boolean performHapticFeedback(IWindow window, int effectId, boolean always);
+ boolean performHapticFeedback(int effectId, boolean always);
/**
* Initiate the drag operation itself
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 89c6703..be6b56c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6996,7 +6996,7 @@
@Override
public boolean performHapticFeedback(int effectId, boolean always) {
try {
- return mWindowSession.performHapticFeedback(mWindow, effectId, always);
+ return mWindowSession.performHapticFeedback(effectId, always);
} catch (RemoteException e) {
return false;
}
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 5d59e42..87e18b7 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -424,28 +424,20 @@
*
* @param nodes The nodes in the hosting window.
* @param rootNodeId The id of the root to evict.
- *
- * @return {@code true} if the cache was cleared
*/
- private boolean clearSubTreeRecursiveLocked(LongSparseArray<AccessibilityNodeInfo> nodes,
+ private void clearSubTreeRecursiveLocked(LongSparseArray<AccessibilityNodeInfo> nodes,
long rootNodeId) {
AccessibilityNodeInfo current = nodes.get(rootNodeId);
if (current == null) {
- // The node isn't in the cache, but its descendents might be.
- clear();
- return true;
+ return;
}
nodes.remove(rootNodeId);
final int childCount = current.getChildCount();
for (int i = 0; i < childCount; i++) {
final long childNodeId = current.getChildId(i);
- if (clearSubTreeRecursiveLocked(nodes, childNodeId)) {
- current.recycle();
- return true;
- }
+ clearSubTreeRecursiveLocked(nodes, childNodeId);
}
current.recycle();
- return false;
}
/**
diff --git a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java b/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
index 8faae1f..d4b7e85 100644
--- a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
+++ b/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
@@ -40,8 +40,15 @@
final Class<InspectionCompanion<T>> companionClass =
(Class<InspectionCompanion<T>>) cls.getClassLoader().loadClass(companionName);
return companionClass.newInstance();
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ } catch (ClassNotFoundException e) {
return null;
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InstantiationException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) throw (RuntimeException) cause;
+ if (cause instanceof Error) throw (Error) cause;
+ throw new RuntimeException(cause);
}
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0fbd4dc..89e3d6b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -381,6 +381,8 @@
final long systemCost = mChooserShownTime - intentReceivedTime;
getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
+ .setSubtype(isWorkProfile() ? MetricsEvent.MANAGED_PROFILE :
+ MetricsEvent.PARENT_PROFILE)
.addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
.addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
@@ -418,6 +420,16 @@
}
/**
+ * Check if the profile currently used is a work profile.
+ * @return true if it is work profile, false if it is parent profile (or no work profile is
+ * set up)
+ */
+ protected boolean isWorkProfile() {
+ return ((UserManager) getSystemService(Context.USER_SERVICE))
+ .getUserInfo(UserHandle.myUserId()).isManagedProfile();
+ }
+
+ /**
* Override method to add content preview area, specific to the chooser activity.
*/
@Override
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index d13bcf2..64f0010 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -31,6 +31,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -39,6 +40,8 @@
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.Arrays;
import java.util.HashSet;
@@ -66,6 +69,8 @@
private Injector mInjector;
+ private MetricsLogger mMetricsLogger;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -78,9 +83,17 @@
if (className.equals(FORWARD_INTENT_TO_PARENT)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
targetUserId = getProfileParent();
+
+ getMetricsLogger().write(
+ new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
+ .setSubtype(MetricsEvent.PARENT_PROFILE));
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
targetUserId = getManagedProfile();
+
+ getMetricsLogger().write(
+ new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
+ .setSubtype(MetricsEvent.MANAGED_PROFILE));
} else {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessageId = -1;
@@ -257,6 +270,13 @@
intent.setComponent(null);
}
+ protected MetricsLogger getMetricsLogger() {
+ if (mMetricsLogger == null) {
+ mMetricsLogger = new MetricsLogger();
+ }
+ return mMetricsLogger;
+ }
+
@VisibleForTesting
protected Injector createInjector() {
return new InjectorImpl();
diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index 26cf180..293ffd3 100644
--- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -39,7 +39,7 @@
private final int mInitialCapacity;
- protected ArrayList<PendingRequest<S, I>> mPendingRequests;
+ protected ArrayList<BasePendingRequest<S, I>> mPendingRequests;
public AbstractMultiplePendingRequestsRemoteService(@NonNull Context context,
@NonNull String serviceInterface, @NonNull ComponentName componentName, int userId,
@@ -85,7 +85,7 @@
}
@Override // from AbstractRemoteService
- void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S, I> pendingRequest) {
+ void handlePendingRequestWhileUnBound(@NonNull BasePendingRequest<S, I> pendingRequest) {
if (mPendingRequests == null) {
mPendingRequests = new ArrayList<>(mInitialCapacity);
}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index a937aa7..732553b 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -95,7 +95,7 @@
private long mNextUnbind;
/** Requests that have been scheduled, but that are not finished yet */
- private final ArrayList<PendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
+ private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
/**
* Callback called when the service dies.
@@ -183,8 +183,15 @@
/**
* Defines how long after we make a remote request to a fill service we timeout.
+ *
+ * <p>Just need to be overridden by subclasses that uses sync {@link PendingRequest}s.
+ *
+ * @throws UnsupportedOperationException if called when not overridden.
+ *
*/
- protected abstract long getRemoteRequestMillis();
+ protected long getRemoteRequestMillis() {
+ throw new UnsupportedOperationException("not implemented by " + getClass());
+ }
/**
* Gets the currently registered service interface or {@code null} if the service is not
@@ -243,7 +250,7 @@
pw.append(prefix).append(tab).append("destroyed=")
.append(String.valueOf(mDestroyed)).println();
pw.append(prefix).append(tab).append("numUnfinishedRequests=")
- .append(String.valueOf(mUnfinishedRequests.size()));
+ .append(String.valueOf(mUnfinishedRequests.size())).println();
final boolean bound = handleIsBound();
pw.append(prefix).append(tab).append("bound=")
.append(String.valueOf(bound));
@@ -260,9 +267,13 @@
pw.println();
pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
pw.append(prefix).append("idleTimeout=")
- .append(Long.toString(idleTimeout / 1000)).append("s").println();
- pw.append(prefix).append("requestTimeout=")
- .append(Long.toString(getRemoteRequestMillis() / 1000)).append("s").println();
+ .append(Long.toString(idleTimeout / 1000)).append("s\n");
+ pw.append(prefix).append("requestTimeout=");
+ try {
+ pw.append(Long.toString(getRemoteRequestMillis() / 1000)).append("s\n");
+ } catch (UnsupportedOperationException e) {
+ pw.append("not supported\n");
+ }
pw.println();
}
@@ -273,7 +284,7 @@
* othewise it will trigger a {@link PendingRequest#onTimeout(AbstractRemoteService)} if the
* service doesn't respond.
*/
- protected void scheduleRequest(@NonNull PendingRequest<S, I> pendingRequest) {
+ protected void scheduleRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
mHandler.sendMessage(obtainMessage(
AbstractRemoteService::handlePendingRequest, this, pendingRequest));
}
@@ -283,12 +294,12 @@
*
* @param finshedRequest The request that is finished
*/
- void finishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+ void finishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
mHandler.sendMessage(
obtainMessage(AbstractRemoteService::handleFinishRequest, this, finshedRequest));
}
- private void handleFinishRequest(@NonNull PendingRequest<S, I> finshedRequest) {
+ private void handleFinishRequest(@NonNull BasePendingRequest<S, I> finshedRequest) {
mUnfinishedRequests.remove(finshedRequest);
if (mUnfinishedRequests.isEmpty()) {
@@ -361,7 +372,7 @@
* Handles a request, either processing it right now when bound, or saving it to be handled when
* bound.
*/
- protected final void handlePendingRequest(@NonNull PendingRequest<S, I> pendingRequest) {
+ protected final void handlePendingRequest(@NonNull BasePendingRequest<S, I> pendingRequest) {
if (checkIfDestroyed() || mCompleted) return;
if (!handleIsBound()) {
@@ -384,7 +395,8 @@
/**
* Defines what to do with a request that arrives while not bound to the service.
*/
- abstract void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S, I> pendingRequest);
+ abstract void handlePendingRequestWhileUnBound(
+ @NonNull BasePendingRequest<S, I> pendingRequest);
private boolean handleIsBound() {
return mService != null;
@@ -471,50 +483,28 @@
/**
* Base class for the requests serviced by the remote service.
*
- * <p><b>NOTE: </b> this class is typically used when the service needs to use a callback to
- * communicate back with the system server. For cases where that's not needed, you should use
- * {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} instead.
+ * <p><b>NOTE: </b> this class is not used directly, you should either override
+ * {@link com.android.internal.infra.AbstractRemoteService.PendingRequest} for sync requests, or
+ * use {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} for async requests.
*
* @param <S> the remote service class
* @param <I> the interface of the binder service
*/
- public abstract static class PendingRequest<S extends AbstractRemoteService<S, I>,
+ public abstract static class BasePendingRequest<S extends AbstractRemoteService<S, I>,
I extends IInterface> implements Runnable {
protected final String mTag = getClass().getSimpleName();
protected final Object mLock = new Object();
- private final WeakReference<S> mWeakService;
- private final Runnable mTimeoutTrigger;
- private final Handler mServiceHandler;
+ final WeakReference<S> mWeakService;
@GuardedBy("mLock")
- private boolean mCancelled;
+ boolean mCancelled;
@GuardedBy("mLock")
- private boolean mCompleted;
+ boolean mCompleted;
- protected PendingRequest(@NonNull S service) {
+ BasePendingRequest(@NonNull S service) {
mWeakService = new WeakReference<>(service);
- mServiceHandler = service.mHandler;
- mTimeoutTrigger = () -> {
- synchronized (mLock) {
- if (mCancelled) {
- return;
- }
- mCompleted = true;
- }
-
- final S remoteService = mWeakService.get();
- if (remoteService != null) {
- // TODO(b/117779333): we should probably ignore it if service is destroyed.
- Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
- onTimeout(remoteService);
- } else {
- Slog.w(mTag, "timed out (no service)");
- }
- };
- mServiceHandler.postAtTime(mTimeoutTrigger,
- SystemClock.uptimeMillis() + service.getRemoteRequestMillis());
}
/**
@@ -543,10 +533,13 @@
service.finishRequest(this);
}
- mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ onFinished();
+
return true;
}
+ void onFinished() { }
+
/**
* Checks whether this request was cancelled.
*/
@@ -568,15 +561,11 @@
mCancelled = true;
}
- mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ onCancel();
return true;
}
- /**
- * Called by the self-destruct timeout when the remote service didn't reply to the
- * request on time.
- */
- protected abstract void onTimeout(S remoteService);
+ void onCancel() {}
/**
* Checks whether this request leads to a final state where no other requests can be made.
@@ -587,6 +576,67 @@
}
/**
+ * Base class for the requests serviced by the remote service.
+ *
+ * <p><b>NOTE: </b> this class is typically used when the service needs to use a callback to
+ * communicate back with the system server. For cases where that's not needed, you should use
+ * {@link AbstractRemoteService#scheduleAsyncRequest(AsyncRequest)} instead.
+ *
+ * <p><b>NOTE: </b> you must override {@link AbstractRemoteService#getRemoteRequestMillis()},
+ * otherwise the constructor will throw an {@link UnsupportedOperationException}.
+ *
+ * @param <S> the remote service class
+ * @param <I> the interface of the binder service
+ */
+ public abstract static class PendingRequest<S extends AbstractRemoteService<S, I>,
+ I extends IInterface> extends BasePendingRequest<S, I> {
+
+ private final Runnable mTimeoutTrigger;
+ private final Handler mServiceHandler;
+
+ protected PendingRequest(S service) {
+ super(service);
+ mServiceHandler = service.mHandler;
+
+ mTimeoutTrigger = () -> {
+ synchronized (mLock) {
+ if (mCancelled) {
+ return;
+ }
+ mCompleted = true;
+ }
+
+ final S remoteService = mWeakService.get();
+ if (remoteService != null) {
+ // TODO(b/117779333): we should probably ignore it if service is destroyed.
+ Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
+ onTimeout(remoteService);
+ } else {
+ Slog.w(mTag, "timed out (no service)");
+ }
+ };
+ mServiceHandler.postAtTime(mTimeoutTrigger,
+ SystemClock.uptimeMillis() + service.getRemoteRequestMillis());
+ }
+
+ @Override
+ final void onFinished() {
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ }
+
+ @Override
+ final void onCancel() {
+ mServiceHandler.removeCallbacks(mTimeoutTrigger);
+ }
+
+ /**
+ * Called by the self-destruct timeout when the remote service didn't reply to the
+ * request on time.
+ */
+ protected abstract void onTimeout(S remoteService);
+ }
+
+ /**
* Represents a request that does not expect a callback from the remote service.
*
* @param <I> the interface of the binder service
@@ -600,7 +650,7 @@
}
private static final class MyAsyncPendingRequest<S extends AbstractRemoteService<S, I>,
- I extends IInterface> extends PendingRequest<S, I> {
+ I extends IInterface> extends BasePendingRequest<S, I> {
private static final String TAG = MyAsyncPendingRequest.class.getSimpleName();
private final AsyncRequest<I> mRequest;
@@ -623,12 +673,5 @@
finish();
}
}
-
- @Override
- protected void onTimeout(S remoteService) {
- // TODO(b/117779333): should not happen because we called finish() on run(), although
- // currently it might be called if the service is destroyed while showing it.
- Slog.w(TAG, "AsyncPending requested timed out");
- }
}
}
diff --git a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
index f0c2233..3e92a0b 100644
--- a/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
@@ -38,7 +38,7 @@
extends AbstractSinglePendingRequestRemoteService<S, I>, I extends IInterface>
extends AbstractRemoteService<S, I> {
- protected PendingRequest<S, I> mPendingRequest;
+ protected BasePendingRequest<S, I> mPendingRequest;
public AbstractSinglePendingRequestRemoteService(@NonNull Context context,
@NonNull String serviceInterface, @NonNull ComponentName componentName, int userId,
@@ -51,7 +51,7 @@
@Override // from AbstractRemoteService
void handlePendingRequests() {
if (mPendingRequest != null) {
- final PendingRequest<S, I> pendingRequest = mPendingRequest;
+ final BasePendingRequest<S, I> pendingRequest = mPendingRequest;
mPendingRequest = null;
handlePendingRequest(pendingRequest);
}
@@ -73,7 +73,7 @@
}
@Override // from AbstractRemoteService
- void handlePendingRequestWhileUnBound(@NonNull PendingRequest<S, I> pendingRequest) {
+ void handlePendingRequestWhileUnBound(@NonNull BasePendingRequest<S, I> pendingRequest) {
if (mPendingRequest != null) {
if (mVerbose) {
Slog.v(mTag, "handlePendingRequestWhileUnBound(): cancelling " + mPendingRequest
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index d9d3cdf..72e3d349 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -27,9 +27,12 @@
return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
}
-void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {
+void setDriverPathAndSphalLibraries_native(JNIEnv* env, jobject clazz, jstring path,
+ jstring sphalLibraries) {
ScopedUtfChars pathChars(env, path);
- android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
+ ScopedUtfChars sphalLibrariesChars(env, sphalLibraries);
+ android::GraphicsEnv::getInstance().setDriverPathAndSphalLibraries(pathChars.c_str(),
+ sphalLibrariesChars.c_str());
}
void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName,
@@ -84,7 +87,7 @@
const JNINativeMethod g_methods[] = {
{ "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
- { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
+ { "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native) },
{ "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 15ceca9..73e6789 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -572,214 +572,246 @@
}
static int UnmountTree(const char* path) {
- size_t path_len = strlen(path);
+ size_t path_len = strlen(path);
- FILE* fp = setmntent("/proc/mounts", "r");
- if (fp == nullptr) {
- ALOGE("Error opening /proc/mounts: %s", strerror(errno));
- return -errno;
- }
+ FILE* fp = setmntent("/proc/mounts", "r");
+ if (fp == nullptr) {
+ ALOGE("Error opening /proc/mounts: %s", strerror(errno));
+ return -errno;
+ }
- // Some volumes can be stacked on each other, so force unmount in
- // reverse order to give us the best chance of success.
- std::list<std::string> toUnmount;
- mntent* mentry;
- while ((mentry = getmntent(fp)) != nullptr) {
- if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
- toUnmount.push_front(std::string(mentry->mnt_dir));
- }
+ // Some volumes can be stacked on each other, so force unmount in
+ // reverse order to give us the best chance of success.
+ std::list<std::string> to_unmount;
+ mntent* mentry;
+ while ((mentry = getmntent(fp)) != nullptr) {
+ if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
+ to_unmount.push_front(std::string(mentry->mnt_dir));
}
- endmntent(fp);
+ }
+ endmntent(fp);
- for (const auto& path : toUnmount) {
- if (umount2(path.c_str(), MNT_DETACH)) {
- ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
- }
+ for (const auto& path : to_unmount) {
+ if (umount2(path.c_str(), MNT_DETACH)) {
+ ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
}
- return 0;
+ }
+ return 0;
}
static void CreateDir(const std::string& dir,
mode_t mode, uid_t uid, gid_t gid,
fail_fn_t fail_fn) {
- if (TEMP_FAILURE_RETRY(access(dir.c_str(), F_OK)) == 0) {
- return;
- } else if (errno != ENOENT) {
- fail_fn(CREATE_ERROR("Failed to stat %s: %s", dir.c_str(), strerror(errno)));
- }
- if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
- dir.c_str(), strerror(errno)));
- }
+ if (TEMP_FAILURE_RETRY(access(dir.c_str(), F_OK)) == 0) {
+ return;
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to stat %s: %s", dir.c_str(), strerror(errno)));
+ }
+ if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
+ fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
+ dir.c_str(), strerror(errno)));
+ }
}
-static void CreatePkgSandboxTarget(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
- // Create /mnt/user/0/package/<package-name>
- userid_t user_id = multiuser_get_user_id(uid);
- std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
- CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
+static void CreatePkgSandboxTarget(userid_t user_id, fail_fn_t fail_fn) {
+ // Create /mnt/user/0/package
+ std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
+ CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
- StringAppendF(&pkg_sandbox_dir, "/package");
- CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
-
- StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
- CreateDir(pkg_sandbox_dir, 0755, uid, uid, fail_fn);
+ StringAppendF(&pkg_sandbox_dir, "/package");
+ CreateDir(pkg_sandbox_dir, 0755, AID_ROOT, AID_ROOT, fail_fn);
}
-static void BindMount(const std::string& sourceDir, const std::string& targetDir,
+static void BindMount(const std::string& source_dir, const std::string& target_dir,
fail_fn_t fail_fn) {
- if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(), nullptr,
- MS_BIND, nullptr)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
- sourceDir.c_str(), targetDir.c_str(), strerror(errno)));
- }
+ if (TEMP_FAILURE_RETRY(mount(source_dir.c_str(), target_dir.c_str(), nullptr,
+ MS_BIND, nullptr)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
+ source_dir.c_str(), target_dir.c_str(), strerror(errno)));
+ }
}
-static void MountPkgSpecificDir(const std::string& mntSourceRoot,
- const std::string& mntTargetRoot,
- const std::string& packageName,
+static void MountPkgSpecificDir(const std::string& mnt_source_root,
+ const std::string& mnt_target_root,
+ const std::string& package_name,
uid_t uid,
- const char* dirName,
+ const char* dir_name,
fail_fn_t fail_fn) {
- std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
- mntSourceRoot.c_str(), dirName, packageName.c_str());
+ std::string mnt_source_dir = StringPrintf("%s/Android/%s/%s",
+ mnt_source_root.c_str(), dir_name, package_name.c_str());
- std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
- mntTargetRoot.c_str(), dirName, packageName.c_str());
+ std::string mnt_target_dir = StringPrintf("%s/Android/%s/%s",
+ mnt_target_root.c_str(), dir_name, package_name.c_str());
- BindMount(mntSourceDir, mntTargetDir, fail_fn);
+ BindMount(mnt_source_dir, mnt_target_dir, fail_fn);
}
-static void CreateSubDirs(int dirfd, const std::string& parentDirPath,
- const std::vector<std::string>& subDirs,
+static void CreateSubDirs(int parent_fd, const std::string& parent_path,
+ const std::vector<std::string>& sub_dirs,
fail_fn_t fail_fn) {
- for (auto& dirName : subDirs) {
- struct stat sb;
- if (TEMP_FAILURE_RETRY(fstatat(dirfd, dirName.c_str(), &sb, 0)) == 0) {
- if (S_ISDIR(sb.st_mode)) {
- continue;
- } else if (TEMP_FAILURE_RETRY(unlinkat(dirfd, dirName.c_str(), 0)) == -1) {
- fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s",
- parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
- }
- } else if (errno != ENOENT) {
- fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s",
- parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
- }
- if (TEMP_FAILURE_RETRY(mkdirat(dirfd, dirName.c_str(), 0700)) == -1 && errno != EEXIST) {
- fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s",
- parentDirPath.c_str(), dirName.c_str(), strerror(errno)));
- }
+ for (auto& dir_name : sub_dirs) {
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(fstatat(parent_fd, dir_name.c_str(), &sb, 0)) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ continue;
+ } else if (TEMP_FAILURE_RETRY(unlinkat(parent_fd, dir_name.c_str(), 0)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s",
+ parent_path.c_str(), dir_name.c_str(), strerror(errno)));
+ }
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s",
+ parent_path.c_str(), dir_name.c_str(), strerror(errno)));
}
+ if (TEMP_FAILURE_RETRY(mkdirat(parent_fd, dir_name.c_str(), 0700)) == -1 && errno != EEXIST) {
+ fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s",
+ parent_path.c_str(), dir_name.c_str(), strerror(errno)));
+ }
+ }
}
static void EnsurePkgSpecificDirs(const std::string& path,
- const std::vector<std::string>& packageNames,
- bool createSandboxDir,
+ const std::vector<std::string>& package_names,
+ bool create_sandbox_dir,
fail_fn_t fail_fn) {
- std::string androidDir = StringPrintf("%s/Android", path.c_str());
- android::base::unique_fd androidFd(
- open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (androidFd.get() < 0) {
- if (errno == ENOENT || errno == ENOTDIR) {
- if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(androidDir.c_str())) == -1) {
- fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
- androidDir.c_str(), strerror(errno)));
- }
- if (TEMP_FAILURE_RETRY(mkdir(androidDir.c_str(), 0700)) == -1
- && errno != EEXIST) {
- fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
- androidDir.c_str(), strerror(errno)));
- }
- androidFd.reset(open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- }
-
- if (androidFd.get() < 0) {
- fail_fn(CREATE_ERROR("Failed to open %s: %s", androidDir.c_str(), strerror(errno)));
- }
- }
-
- std::vector<std::string> dataMediaObbDirs = {"data", "media", "obb"};
- if (createSandboxDir) {
- dataMediaObbDirs.push_back("sandbox");
- }
- CreateSubDirs(androidFd.get(), androidDir, dataMediaObbDirs, fail_fn);
- if (createSandboxDir) {
- dataMediaObbDirs.pop_back();
- }
- for (auto& dirName : dataMediaObbDirs) {
- std::string dataDir = StringPrintf("%s/%s", androidDir.c_str(), dirName.c_str());
- android::base::unique_fd dataFd(
- openat(androidFd, dirName.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (dataFd.get() < 0) {
- fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s",
- androidDir.c_str(), dirName.c_str(), strerror(errno)));
- }
- CreateSubDirs(dataFd.get(), dataDir, packageNames, fail_fn);
- }
-}
-
-static void CreatePkgSandboxSource(const std::string& sandboxSource, fail_fn_t fail_fn) {
-
- struct stat sb;
- if (TEMP_FAILURE_RETRY(stat(sandboxSource.c_str(), &sb)) == 0) {
- if (S_ISDIR(sb.st_mode)) {
- return;
- } else if (TEMP_FAILURE_RETRY(unlink(sandboxSource.c_str())) == -1) {
- fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
- sandboxSource.c_str(), strerror(errno)));
- }
- } else if (errno != ENOENT) {
- fail_fn(CREATE_ERROR("Failed to stat %s: %s",
- sandboxSource.c_str(), strerror(errno)));
- }
- if (TEMP_FAILURE_RETRY(mkdir(sandboxSource.c_str(), 0700)) == -1 && errno != EEXIST) {
+ std::string android_dir = StringPrintf("%s/Android", path.c_str());
+ android::base::unique_fd android_fd(open(android_dir.c_str(),
+ O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (android_fd.get() < 0) {
+ if (errno == ENOENT || errno == ENOTDIR) {
+ if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(android_dir.c_str())) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+ android_dir.c_str(), strerror(errno)));
+ }
+ if (TEMP_FAILURE_RETRY(mkdir(android_dir.c_str(), 0700)) == -1
+ && errno != EEXIST) {
fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
- sandboxSource.c_str(), strerror(errno)));
+ android_dir.c_str(), strerror(errno)));
+ }
+ android_fd.reset(open(android_dir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
}
+
+ if (android_fd.get() < 0) {
+ fail_fn(CREATE_ERROR("Failed to open %s: %s", android_dir.c_str(), strerror(errno)));
+ }
+ }
+
+ std::vector<std::string> data_media_obb_dirs = {"data", "media", "obb"};
+ if (create_sandbox_dir) {
+ data_media_obb_dirs.push_back("sandbox");
+ }
+ CreateSubDirs(android_fd.get(), android_dir, data_media_obb_dirs, fail_fn);
+ if (create_sandbox_dir) {
+ data_media_obb_dirs.pop_back();
+ }
+ for (auto& dir_name : data_media_obb_dirs) {
+ std::string data_dir = StringPrintf("%s/%s", android_dir.c_str(), dir_name.c_str());
+ android::base::unique_fd data_fd(openat(android_fd, dir_name.c_str(),
+ O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (data_fd.get() < 0) {
+ fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s",
+ android_dir.c_str(), dir_name.c_str(), strerror(errno)));
+ }
+ CreateSubDirs(data_fd.get(), data_dir, package_names, fail_fn);
+ }
}
-static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames,
- const std::vector<std::string>& volumeLabels,
- bool mountAllObbs, const std::string& sandboxId,
- userid_t userId, uid_t uid, fail_fn_t fail_fn) {
- for (auto& label : volumeLabels) {
- std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
- std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
- if (label == "emulated") {
- StringAppendF(&mntSource, "/%d", userId);
- StringAppendF(&mntTarget, "/%d", userId);
- }
+static void CreatePkgSandboxSource(const std::string& sandbox_source, fail_fn_t fail_fn) {
- if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) == -1) {
- ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno));
- continue;
- }
-
- // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb}
- EnsurePkgSpecificDirs(mntSource, packageNames, true, fail_fn);
-
- std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
- mntSource.c_str(), sandboxId.c_str());
- CreatePkgSandboxSource(sandboxSource, fail_fn);
- BindMount(sandboxSource, mntTarget, fail_fn);
-
- // Ensure /storage/emulated/0/Android/{data,media,obb}
- EnsurePkgSpecificDirs(mntTarget, packageNames, false, fail_fn);
- for (auto& package : packageNames) {
- MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn);
- MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn);
- if (!mountAllObbs) {
- MountPkgSpecificDir(mntSource, mntTarget, package, uid, "obb", fail_fn);
- }
- }
-
- if (mountAllObbs) {
- StringAppendF(&mntSource, "/Android/obb");
- StringAppendF(&mntTarget, "/Android/obb");
- BindMount(mntSource, mntTarget, fail_fn);
- }
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(stat(sandbox_source.c_str(), &sb)) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ return;
+ } else if (TEMP_FAILURE_RETRY(unlink(sandbox_source.c_str())) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+ sandbox_source.c_str(), strerror(errno)));
}
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to stat %s: %s",
+ sandbox_source.c_str(), strerror(errno)));
+ }
+ if (TEMP_FAILURE_RETRY(mkdir(sandbox_source.c_str(), 0700)) == -1 && errno != EEXIST) {
+ fail_fn(CREATE_ERROR("Failed to mkdir %s: %s",
+ sandbox_source.c_str(), strerror(errno)));
+ }
+}
+
+static void PreparePkgSpecificDirs(const std::vector<std::string>& package_names,
+ const std::vector<std::string>& volume_labels,
+ bool mount_all_obbs, const std::string& sandbox_id,
+ userid_t user_id, uid_t uid, fail_fn_t fail_fn) {
+ for (auto& label : volume_labels) {
+ std::string mnt_source = StringPrintf("/mnt/runtime/write/%s", label.c_str());
+ std::string mnt_target = StringPrintf("/storage/%s", label.c_str());
+ if (label == "emulated") {
+ StringAppendF(&mnt_source, "/%d", user_id);
+ StringAppendF(&mnt_target, "/%d", user_id);
+ }
+
+ if (TEMP_FAILURE_RETRY(access(mnt_source.c_str(), F_OK)) == -1) {
+ ALOGE("Can't access %s: %s", mnt_source.c_str(), strerror(errno));
+ continue;
+ } else if (TEMP_FAILURE_RETRY(access(mnt_target.c_str(), F_OK)) == -1) {
+ ALOGE("Can't access %s: %s", mnt_target.c_str(), strerror(errno));
+ continue;
+ }
+
+ // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb}
+ EnsurePkgSpecificDirs(mnt_source, package_names, true, fail_fn);
+
+ std::string sandbox_source = StringPrintf("%s/Android/sandbox/%s",
+ mnt_source.c_str(), sandbox_id.c_str());
+ CreatePkgSandboxSource(sandbox_source, fail_fn);
+ BindMount(sandbox_source, mnt_target, fail_fn);
+
+ // Ensure /storage/emulated/0/Android/{data,media,obb}
+ EnsurePkgSpecificDirs(mnt_target, package_names, false, fail_fn);
+ for (auto& package : package_names) {
+ MountPkgSpecificDir(mnt_source, mnt_target, package, uid, "data", fail_fn);
+ MountPkgSpecificDir(mnt_source, mnt_target, package, uid, "media", fail_fn);
+ if (!mount_all_obbs) {
+ MountPkgSpecificDir(mnt_source, mnt_target, package, uid, "obb", fail_fn);
+ }
+ }
+
+ if (mount_all_obbs) {
+ StringAppendF(&mnt_source, "/Android/obb");
+ StringAppendF(&mnt_target, "/Android/obb");
+ BindMount(mnt_source, mnt_target, fail_fn);
+ }
+ }
+}
+
+static void HandleMountModeInstaller(int mount_mode,
+ userid_t user_id,
+ const std::string& sandbox_id,
+ fail_fn_t fail_fn) {
+ std::string obb_mount_dir = StringPrintf("/mnt/user/%d/obb_mount", user_id);
+ std::string obb_mount_file = StringPrintf("%s/%s", obb_mount_dir.c_str(), sandbox_id.c_str());
+ if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
+ if (TEMP_FAILURE_RETRY(access(obb_mount_file.c_str(), F_OK)) != -1) {
+ return;
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to access %s: %s", obb_mount_file.c_str(), strerror(errno)));
+ }
+ if (fs_prepare_dir(obb_mount_dir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ fail_fn(CREATE_ERROR("Failed to fs_prepare_dir %s: %s",
+ obb_mount_dir.c_str(), strerror(errno)));
+ }
+ const android::base::unique_fd fd(TEMP_FAILURE_RETRY(
+ open(obb_mount_file.c_str(), O_RDWR | O_CREAT, 0600)));
+ if (fd.get() < 0) {
+ fail_fn(CREATE_ERROR("Failed to create %s: %s", obb_mount_file.c_str(), strerror(errno)));
+ }
+ } else {
+ if (TEMP_FAILURE_RETRY(access(obb_mount_file.c_str(), F_OK)) != -1) {
+ if (TEMP_FAILURE_RETRY(unlink(obb_mount_file.c_str())) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unlink %s: %s",
+ obb_mount_dir.c_str(), strerror(errno)));
+ }
+ } else if (errno != ENOENT) {
+ fail_fn(CREATE_ERROR("Failed to access %s: %s", obb_mount_file.c_str(), strerror(errno)));
+ }
+ }
}
// Create a private mount namespace and bind mount appropriate emulated
@@ -789,126 +821,97 @@
const std::vector<std::string>& packages_for_uid,
const std::vector<std::string>& visible_vol_ids, const std::string& sandbox_id,
fail_fn_t fail_fn) {
- // See storage config details at http://source.android.com/tech/storage/
+ // See storage config details at http://source.android.com/tech/storage/
- String8 storageSource;
- if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
- storageSource = "/mnt/runtime/default";
- } else if (mount_mode == MOUNT_EXTERNAL_READ) {
- storageSource = "/mnt/runtime/read";
- } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
- storageSource = "/mnt/runtime/write";
- } else if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
- // Sane default of no storage visible
- return;
- }
+ String8 storage_source;
+ if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
+ storage_source = "/mnt/runtime/default";
+ } else if (mount_mode == MOUNT_EXTERNAL_READ) {
+ storage_source = "/mnt/runtime/read";
+ } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
+ storage_source = "/mnt/runtime/write";
+ } else if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
+ // Sane default of no storage visible
+ return;
+ }
- // Create a second private mount namespace for our process
- if (unshare(CLONE_NEWNS) == -1) {
- fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
- }
+ // Create a second private mount namespace for our process
+ if (unshare(CLONE_NEWNS) == -1) {
+ fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
+ }
- // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
- if (mount_mode == MOUNT_EXTERNAL_NONE) {
- return;
- }
+ // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return;
+ }
- if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true))) {
- if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
- storageSource = (mount_mode == MOUNT_EXTERNAL_FULL)
- ? "/mnt/runtime/full" : "/mnt/runtime/write";
- if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
- NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
- storageSource.string(),
- strerror(errno)));
- }
+ if (GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true))) {
+ if (mount_mode == MOUNT_EXTERNAL_FULL || mount_mode == MOUNT_EXTERNAL_LEGACY) {
+ storage_source = (mount_mode == MOUNT_EXTERNAL_FULL)
+ ? "/mnt/runtime/full" : "/mnt/runtime/write";
+ if (TEMP_FAILURE_RETRY(mount(storage_source.string(), "/storage",
+ NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+ storage_source.string(),
+ strerror(errno)));
+ }
- // Mount user-specific symlink helper into place
- userid_t user_id = multiuser_get_user_id(uid);
- const String8 userSource(String8::format("/mnt/user/%d", user_id));
- if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s (%s)",
- userSource.string(), strerror(errno)));
- }
+ // Mount user-specific symlink helper into place
+ userid_t user_id = multiuser_get_user_id(uid);
+ const String8 user_source(String8::format("/mnt/user/%d", user_id));
+ if (fs_prepare_dir(user_source.string(), 0751, 0, 0) == -1) {
+ fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s (%s)",
+ user_source.string(), strerror(errno)));
+ }
- if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self", nullptr, MS_BIND,
- nullptr)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
- userSource.string(),
- strerror(errno)));
- }
- } else {
- if (package_name.empty() || sandbox_id.empty()) {
- return;
- }
-
- userid_t user_id = multiuser_get_user_id(uid);
- std::string pkgSandboxDir =
- StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str());
- bool sandboxAlreadyCreated = true;
- if (TEMP_FAILURE_RETRY(access(pkgSandboxDir.c_str(), F_OK)) == -1) {
- if (errno == ENOENT) {
- ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str());
- sandboxAlreadyCreated = false;
- CreatePkgSandboxTarget(uid, package_name, fail_fn);
- } else {
- fail_fn(CREATE_ERROR("Failed to access %s: %s",
- pkgSandboxDir.c_str(), strerror(errno)));
- }
- }
-
- if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",
- nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
- pkgSandboxDir.c_str(), strerror(errno)));
- }
-
- if (TEMP_FAILURE_RETRY(access("/storage/obb_mount", F_OK)) == 0) {
- if (mount_mode != MOUNT_EXTERNAL_INSTALLER) {
- remove("/storage/obb_mount");
- }
- } else {
- if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
- int fd =
- TEMP_FAILURE_RETRY(open("/storage/obb_mount", O_RDWR | O_CREAT, 0660));
- if (fd == -1) {
- fail_fn(CREATE_ERROR("Couldn't create /storage/obb_mount: %s",
- strerror(errno)));
- }
- close(fd);
- }
- }
- // If the sandbox was already created by vold, only then set up the bind mounts for
- // pkg specific directories. Otherwise, leave as is and bind mounts will be taken
- // care of by vold later.
- if (sandboxAlreadyCreated) {
- PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
- mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn);
- }
- }
+ if (TEMP_FAILURE_RETRY(mount(user_source.string(), "/storage/self", nullptr, MS_BIND,
+ nullptr)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+ user_source.string(),
+ strerror(errno)));
+ }
} else {
- if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage", nullptr,
- MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
- storageSource.string(),
- strerror(errno)));
- }
+ if (package_name.empty() || sandbox_id.empty()) {
+ return;
+ }
- // Mount user-specific symlink helper into place
- userid_t user_id = multiuser_get_user_id(uid);
- const String8 userSource(String8::format("/mnt/user/%d", user_id));
- if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
- fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s",
- userSource.string()));
- }
+ userid_t user_id = multiuser_get_user_id(uid);
+ CreatePkgSandboxTarget(user_id, fail_fn);
- if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
- nullptr, MS_BIND, nullptr)) == -1) {
- fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
- userSource.string(), strerror(errno)));
- }
+ std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package", user_id);
+ if (TEMP_FAILURE_RETRY(mount(pkgSandboxDir.c_str(), "/storage",
+ nullptr, MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+ pkgSandboxDir.c_str(), strerror(errno)));
+ }
+
+ HandleMountModeInstaller(mount_mode, user_id, sandbox_id, fail_fn);
+
+ PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
+ mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn);
}
+ } else {
+ if (TEMP_FAILURE_RETRY(mount(storage_source.string(), "/storage", nullptr,
+ MS_BIND | MS_REC | MS_SLAVE, nullptr)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to /storage: %s",
+ storage_source.string(),
+ strerror(errno)));
+ }
+
+ // Mount user-specific symlink helper into place
+ userid_t user_id = multiuser_get_user_id(uid);
+ const String8 userSource(String8::format("/mnt/user/%d", user_id));
+ if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+ fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s",
+ userSource.string()));
+ }
+
+ if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+ nullptr, MS_BIND, nullptr)) == -1) {
+ fail_fn(CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+ userSource.string(), strerror(errno)));
+ }
+ }
}
static bool NeedsNoRandomizeWorkaround() {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 5497b86..f74fc21 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -1622,6 +1622,10 @@
// OPEN: Settings > Apps > Default Apps > Default sms
DEFAULT_SMS_PICKER = 789;
+ // OPEN: Settings > Apps > Notification > Notification Assistant
+ DEFAULT_NOTIFICATION_ASSISTANT = 790;
+
+
// OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6571cd2..eb69535 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2673,11 +2673,6 @@
</string-array>
- <!-- Flag indicating that this device does not rotate and will always remain in its default
- orientation. Activities that desire to run in a non-compatible orientation will be run
- from an emulated display within the physical display. -->
- <bool name="config_forceDefaultOrientation">false</bool>
-
<!-- Default Gravity setting for the system Toast view. Equivalent to: Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM -->
<integer name="config_toastDefaultGravity">0x00000051</integer>
diff --git a/core/res/res/values/styles_car.xml b/core/res/res/values/styles_car.xml
index f6ff1b6..2129734 100644
--- a/core/res/res/values/styles_car.xml
+++ b/core/res/res/values/styles_car.xml
@@ -59,7 +59,7 @@
<style name="CarAction1">
<item name="textStyle">bold</item>
<item name="textSize">@dimen/car_action1_size</item>
- <item name="textColor">@color/car_highlight</item>
+ <item name="textColor">@color/control_default_material</item>
</style>
<style name="CarAction1.Dark">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 93068ea9..3c7b36d 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -38,6 +38,8 @@
<style name="Widget.DeviceDefault.Button.Inset" parent="Widget.Material.Button.Inset"/>
<style name="Widget.DeviceDefault.Button.Toggle" parent="Widget.Material.Button.Toggle"/>
<style name="Widget.DeviceDefault.Button.Colored" parent="Widget.Material.Button.Colored">
+ <item name="outlineAmbientShadowColor">@color/btn_colored_background_material</item>
+ <item name="outlineSpotShadowColor">@color/btn_colored_background_material</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="textColor">@color/btn_colored_text_material</item>
</style>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4ae239e..8df0e19 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -347,7 +347,6 @@
<java-symbol type="bool" name="config_requireRadioPowerOffOnSimRefreshReset" />
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
<java-symbol type="bool" name="config_useFixedVolume" />
- <java-symbol type="bool" name="config_forceDefaultOrientation" />
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
<java-symbol type="bool" name="config_wifi_softap_acs_supported" />
<java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 3a1a4fc..23cd963 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -319,6 +319,7 @@
Settings.Global.LOW_POWER_MODE_STICKY,
Settings.Global.LOW_POWER_MODE_SUGGESTION_PARAMS,
Settings.Global.LTE_SERVICE_FORCED,
+ Settings.Global.LID_BEHAVIOR,
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY,
Settings.Global.MDC_INITIAL_MAX_RETRY,
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
index a88968b..e3852e1 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityCacheTest.java
@@ -301,26 +301,6 @@
}
@Test
- public void subTreeChangeEventFromUncachedNode_clearsNodeInCache() {
- AccessibilityNodeInfo nodeInfo = getNodeWithA11yAndWindowId(CHILD_VIEW_ID, WINDOW_ID_1);
- long id = nodeInfo.getSourceNodeId();
- mAccessibilityCache.add(nodeInfo);
- nodeInfo.recycle();
-
- AccessibilityEvent event = AccessibilityEvent
- .obtain(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
- event.setSource(getMockViewWithA11yAndWindowIds(PARENT_VIEW_ID, WINDOW_ID_1));
-
- mAccessibilityCache.onAccessibilityEvent(event);
- AccessibilityNodeInfo shouldBeNull = mAccessibilityCache.getNode(WINDOW_ID_1, id);
- if (shouldBeNull != null) {
- shouldBeNull.recycle();
- }
- assertNull(shouldBeNull);
- }
-
- @Test
public void scrollEvent_clearsNodeAndChild() {
AccessibilityEvent event = AccessibilityEvent
.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index f27f3f9..9fbc166 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -57,7 +57,7 @@
import com.android.internal.R;
import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import org.junit.Before;
import org.junit.Rule;
@@ -524,15 +524,45 @@
waitForIdle();
verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+ is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
assertThat(logMakerCaptor
.getAllValues().get(0)
- .getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+ .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
is(notNullValue()));
assertThat(logMakerCaptor
.getAllValues().get(0)
- .getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+ .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
is("TestType"));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getSubtype(),
+ is(MetricsEvent.PARENT_PROFILE));
+ }
+
+ @Test
+ public void testOnCreateLoggingFromWorkProfile() {
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+ sOverrides.alternateProfileSetting = MetricsEvent.MANAGED_PROFILE;
+ MetricsLogger mockLogger = sOverrides.metricsLogger;
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
+ waitForIdle();
+ verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
+ assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+ is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+ is(notNullValue()));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+ is("TestType"));
+ assertThat(logMakerCaptor
+ .getAllValues().get(0)
+ .getSubtype(),
+ is(MetricsEvent.MANAGED_PROFILE));
}
@Test
@@ -547,7 +577,7 @@
verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+ is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
}
@Test
@@ -569,7 +599,7 @@
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
is(CONTENT_PREVIEW_TEXT));
}
@@ -599,11 +629,11 @@
verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
// First invocation is from onCreate
assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
is(CONTENT_PREVIEW_IMAGE));
assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
- is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+ is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
is(CONTENT_PREVIEW_IMAGE));
}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 57c84ff..a8dd69a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -28,6 +28,7 @@
import android.util.Size;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.util.function.Function;
@@ -112,6 +113,14 @@
return super.queryResolver(resolver, uri);
}
+ @Override
+ protected boolean isWorkProfile() {
+ if (sOverrides.alternateProfileSetting != 0) {
+ return sOverrides.alternateProfileSetting == MetricsEvent.MANAGED_PROFILE;
+ }
+ return super.isWorkProfile();
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -128,6 +137,7 @@
public boolean resolverForceException;
public Bitmap previewThumbnail;
public MetricsLogger metricsLogger;
+ public int alternateProfileSetting;
public void reset() {
onSafelyStartCallback = null;
@@ -139,6 +149,7 @@
resolverForceException = false;
resolverListController = mock(ResolverListController.class);
metricsLogger = mock(MetricsLogger.class);
+ alternateProfileSetting = 0;
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index 9b13af2..abfb4fb 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -25,6 +25,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -51,6 +53,9 @@
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -70,6 +75,11 @@
"android",
IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
);
+ private static final ComponentName FORWARD_TO_PARENT_COMPONENT_NAME =
+ new ComponentName(
+ "android",
+ IntentForwarderActivity.FORWARD_INTENT_TO_PARENT
+ );
private static final String TYPE_PLAIN_TEXT = "text/plain";
private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
@@ -522,6 +532,60 @@
verify(sInjector).showToast(anyInt(), anyInt());
}
+ @Test
+ public void forwardToManagedProfile_LoggingTest() throws Exception {
+ sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+
+ // Intent can be forwarded.
+ when(mIPm.canForwardTo(
+ any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
+
+ // Managed profile exists.
+ List<UserInfo> profiles = new ArrayList<>();
+ profiles.add(CURRENT_USER_INFO);
+ profiles.add(MANAGED_PROFILE_INFO);
+ when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
+ intent.setAction(Intent.ACTION_SEND);
+ intent.setType(TYPE_PLAIN_TEXT);
+ IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
+
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
+ assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
+ logMakerCaptor.getValue().getCategory());
+ assertEquals(MetricsEvent.MANAGED_PROFILE,
+ logMakerCaptor.getValue().getSubtype());
+ }
+
+ @Test
+ public void forwardToParent_LoggingTest() throws Exception {
+ sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
+
+ // Intent can be forwarded.
+ when(mIPm.canForwardTo(
+ any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
+
+ // Managed profile exists.
+ List<UserInfo> profiles = new ArrayList<>();
+ profiles.add(CURRENT_USER_INFO);
+ profiles.add(MANAGED_PROFILE_INFO);
+ when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+
+ Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
+ intent.setAction(Intent.ACTION_SEND);
+ intent.setType(TYPE_PLAIN_TEXT);
+ IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
+
+ ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+ verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
+ assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
+ logMakerCaptor.getValue().getCategory());
+ assertEquals(MetricsEvent.PARENT_PROFILE,
+ logMakerCaptor.getValue().getSubtype());
+ }
+
private void setupShouldSkipDisclosureTest() throws RemoteException {
sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
sActivityName = "MyTestActivity";
@@ -541,6 +605,7 @@
private Intent mStartActivityIntent;
private int mUserIdActivityLaunchedIn;
+ private MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -559,6 +624,11 @@
mStartActivityIntent = intent;
mUserIdActivityLaunchedIn = userId;
}
+
+ @Override
+ protected MetricsLogger getMetricsLogger() {
+ return mMetricsLogger;
+ }
}
public class TestInjector implements IntentForwarderActivity.Injector {
diff --git a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
deleted file mode 100644
index ae5ca40..0000000
--- a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.location;
-
-import android.os.Parcel;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Unit tests for {@link GnssMeasurementCorrections}. */
-public class GnssMeasurementCorrectionsTest extends TestCase {
- public void testDescribeContents() {
- GnssMeasurementCorrections measurementCorrections =
- new GnssMeasurementCorrections.Builder().build();
- measurementCorrections.describeContents();
- }
-
- public void testWriteToParcel() {
- GnssMeasurementCorrections.Builder measurementCorrections =
- new GnssMeasurementCorrections.Builder();
- setTestValues(measurementCorrections);
- Parcel parcel = Parcel.obtain();
- measurementCorrections.build().writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- GnssMeasurementCorrections newMeasurementCorrection =
- GnssMeasurementCorrections.CREATOR.createFromParcel(parcel);
- verifyTestValues(newMeasurementCorrection);
- parcel.recycle();
- }
-
- private static void verifyTestValues(GnssMeasurementCorrections measurementCorrections) {
- assertEquals(37.386051, measurementCorrections.getLatitudeDegrees());
- assertEquals(-122.083855, measurementCorrections.getLongitudeDegrees());
- assertEquals(32.0, measurementCorrections.getAltitudeMeters());
- assertEquals(9.25, measurementCorrections.getHorizontalPositionUncertaintyMeters());
- assertEquals(2.3, measurementCorrections.getVerticalPositionUncertaintyMeters());
- assertEquals(604000000000000L, measurementCorrections.getToaGpsNanosecondsOfWeek());
-
- GnssSingleSatCorrection singleSatCorrection =
- measurementCorrections.getSingleSatelliteCorrectionList().get(0);
- GnssSingleSatCorrectionsTest.verifyTestValues(singleSatCorrection);
-
- singleSatCorrection = measurementCorrections.getSingleSatelliteCorrectionList().get(1);
- assertEquals(15, singleSatCorrection.getSingleSatelliteCorrectionFlags());
- assertEquals(GnssStatus.CONSTELLATION_GPS, singleSatCorrection.getConstellationType());
- assertEquals(11, singleSatCorrection.getSatelliteId());
- assertEquals(1575430000f, singleSatCorrection.getCarrierFrequencyHz());
- assertEquals(0.9f, singleSatCorrection.getProbabilityLineOfSight());
- assertEquals(50.0f, singleSatCorrection.getExcessPathLengthMeters());
- assertEquals(55.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
- GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
- assertEquals(37.386054, reflectingPlane.getLatitudeDegrees());
- assertEquals(-122.083855, reflectingPlane.getLongitudeDegrees());
- assertEquals(120.0, reflectingPlane.getAltitudeMeters());
- assertEquals(153.0, reflectingPlane.getAzimuthDegrees());
- }
-
- private static void setTestValues(GnssMeasurementCorrections.Builder measurementCorrections) {
- measurementCorrections
- .setLatitudeDegrees(37.386051)
- .setLongitudeDegrees(-122.083855)
- .setAltitudeMeters(32)
- .setHorizontalPositionUncertaintyMeters(9.25)
- .setVerticalPositionUncertaintyMeters(2.3)
- .setToaGpsNanosecondsOfWeek(604000000000000L);
- List<GnssSingleSatCorrection> singleSatCorrectionList = new ArrayList<>();
- singleSatCorrectionList.add(GnssSingleSatCorrectionsTest.generateTestSingleSatCorrection());
- singleSatCorrectionList.add(generateTestSingleSatCorrection());
- measurementCorrections.setSingleSatelliteCorrectionList(singleSatCorrectionList);
- }
-
- private static GnssSingleSatCorrection generateTestSingleSatCorrection() {
- GnssSingleSatCorrection.Builder singleSatCorrection = new GnssSingleSatCorrection.Builder();
- singleSatCorrection
- .setSingleSatelliteCorrectionFlags(8)
- .setConstellationType(GnssStatus.CONSTELLATION_GPS)
- .setSatelliteId(11)
- .setCarrierFrequencyHz(1575430000f)
- .setProbabilityLineOfSight(0.9f)
- .setExcessPathLengthMeters(50.0f)
- .setExcessPathLengthUncertaintyMeters(55.0f)
- .setReflectingPlane(generateTestReflectingPlane());
- return singleSatCorrection.build();
- }
-
- private static GnssReflectingPlane generateTestReflectingPlane() {
- GnssReflectingPlane.Builder reflectingPlane =
- new GnssReflectingPlane.Builder()
- .setLatitudeDegrees(37.386054)
- .setLongitudeDegrees(-122.083855)
- .setAltitudeMeters(120.0)
- .setAzimuthDegrees(153);
- return reflectingPlane.build();
- }
-}
diff --git a/location/tests/locationtests/src/android/location/GnssReflectingPlaneTest.java b/location/tests/locationtests/src/android/location/GnssReflectingPlaneTest.java
deleted file mode 100644
index d7a3378..0000000
--- a/location/tests/locationtests/src/android/location/GnssReflectingPlaneTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.location;
-
-import android.os.Parcel;
-
-import junit.framework.TestCase;
-
-/** Unit tests for {@link GnssReflectingPlane}. */
-public class GnssReflectingPlaneTest extends TestCase {
- public void testDescribeContents() {
- GnssReflectingPlane reflectingPlane = new GnssReflectingPlane.Builder().build();
- reflectingPlane.describeContents();
- }
-
- public void testWriteToParcel() {
- GnssReflectingPlane.Builder reflectingPlane = new GnssReflectingPlane.Builder();
- setTestValues(reflectingPlane);
- Parcel parcel = Parcel.obtain();
- reflectingPlane.build().writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- GnssReflectingPlane newReflectingPlane =
- GnssReflectingPlane.CREATOR.createFromParcel(parcel);
- verifyTestValues(newReflectingPlane);
- parcel.recycle();
- }
-
- public static void verifyTestValues(GnssReflectingPlane reflectingPlane) {
- assertEquals(37.386052, reflectingPlane.getLatitudeDegrees());
- assertEquals(-122.083853, reflectingPlane.getLongitudeDegrees());
- assertEquals(100.0, reflectingPlane.getAltitudeMeters());
- assertEquals(123.0, reflectingPlane.getAzimuthDegrees());
- }
-
- private static void setTestValues(GnssReflectingPlane.Builder reflectingPlane) {
- GnssReflectingPlane refPlane = generateTestReflectingPlane();
- reflectingPlane
- .setLatitudeDegrees(refPlane.getLatitudeDegrees())
- .setLongitudeDegrees(refPlane.getLongitudeDegrees())
- .setAltitudeMeters(refPlane.getAltitudeMeters())
- .setAzimuthDegrees(refPlane.getAzimuthDegrees());
- }
-
- public static GnssReflectingPlane generateTestReflectingPlane() {
- GnssReflectingPlane.Builder reflectingPlane =
- new GnssReflectingPlane.Builder()
- .setLatitudeDegrees(37.386052)
- .setLongitudeDegrees(-122.083853)
- .setAltitudeMeters(100.0)
- .setAzimuthDegrees(123.0);
- return reflectingPlane.build();
- }
-}
diff --git a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
deleted file mode 100644
index 60f33f0..0000000
--- a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.location;
-
-import android.os.Parcel;
-
-import junit.framework.TestCase;
-
-/** Unit tests for {@link GnssSingleSatCorrection}. */
-public class GnssSingleSatCorrectionsTest extends TestCase {
- public void testDescribeContents() {
- GnssSingleSatCorrection singleSatCorrection = new GnssSingleSatCorrection.Builder().build();
- singleSatCorrection.describeContents();
- }
-
- public void testWriteToParcel() {
- GnssSingleSatCorrection.Builder singleSatCorrection = new GnssSingleSatCorrection.Builder();
- setTestValues(singleSatCorrection);
- Parcel parcel = Parcel.obtain();
- singleSatCorrection.build().writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- GnssSingleSatCorrection newSingleSatCorrection =
- GnssSingleSatCorrection.CREATOR.createFromParcel(parcel);
- verifyTestValues(newSingleSatCorrection);
- parcel.recycle();
- }
-
- public static void verifyTestValues(GnssSingleSatCorrection singleSatCorrection) {
- assertEquals(15, singleSatCorrection.getSingleSatelliteCorrectionFlags());
- assertEquals(GnssStatus.CONSTELLATION_GALILEO, singleSatCorrection.getConstellationType());
- assertEquals(12, singleSatCorrection.getSatelliteId());
- assertEquals(1575420000f, singleSatCorrection.getCarrierFrequencyHz());
- assertEquals(0.1f, singleSatCorrection.getProbabilityLineOfSight());
- assertEquals(10.0f, singleSatCorrection.getExcessPathLengthMeters());
- assertEquals(5.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
- GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
- GnssReflectingPlaneTest.verifyTestValues(reflectingPlane);
- }
-
- private static void setTestValues(GnssSingleSatCorrection.Builder singleSatCorrection) {
- GnssSingleSatCorrection singleSatCor = generateTestSingleSatCorrection();
- singleSatCorrection
- .setSingleSatelliteCorrectionFlags(singleSatCor.getSingleSatelliteCorrectionFlags())
- .setConstellationType(singleSatCor.getConstellationType())
- .setSatelliteId(singleSatCor.getSatelliteId())
- .setCarrierFrequencyHz(singleSatCor.getCarrierFrequencyHz())
- .setProbabilityLineOfSight(singleSatCor.getProbabilityLineOfSight())
- .setExcessPathLengthMeters(singleSatCor.getExcessPathLengthMeters())
- .setExcessPathLengthUncertaintyMeters(
- singleSatCor.getExcessPathLengthUncertaintyMeters())
- .setReflectingPlane(singleSatCor.getReflectingPlane());
- }
-
- public static GnssSingleSatCorrection generateTestSingleSatCorrection() {
- GnssSingleSatCorrection.Builder singleSatCorrection =
- new GnssSingleSatCorrection.Builder()
- .setSingleSatelliteCorrectionFlags(15)
- .setConstellationType(GnssStatus.CONSTELLATION_GALILEO)
- .setSatelliteId(12)
- .setCarrierFrequencyHz(1575420000f)
- .setProbabilityLineOfSight(0.1f)
- .setExcessPathLengthMeters(10.0f)
- .setExcessPathLengthUncertaintyMeters(5.0f)
- .setReflectingPlane(GnssReflectingPlaneTest.generateTestReflectingPlane());
- return singleSatCorrection.build();
- }
-}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7de7f8f..bd828ee 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
+import android.media.projection.MediaProjection;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionLegacyHelper;
@@ -3197,8 +3198,10 @@
}
final IAudioService service = getService();
try {
+ MediaProjection projection = policy.getMediaProjection();
String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
- policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController());
+ policy.hasFocusListener(), policy.isFocusPolicy(), policy.isVolumeController(),
+ projection == null ? null : projection.getProjection());
if (regId == null) {
return ERROR;
} else {
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 22f14ae..d714dc7 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -19,34 +19,52 @@
import android.annotation.NonNull;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioMixingRule;
+import android.media.projection.MediaProjection;
+import android.os.RemoteException;
import com.android.internal.util.Preconditions;
/**
* Configuration for capturing audio played by other apps.
*
+ * For privacy and copyright reason, only the following audio can be captured:
+ * - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable.
+ * - audio attributes MUST NOT have the FLAG_NO_CAPTURE
+ * - played by apps that MUST be in the same user profile as the capturing app
+ * (eg work profile can not capture user profile apps and vice-versa).
+ * - played by apps that MUST NOT have in their manifest.xml the application
+ * attribute android:allowPlaybackCapture="false"
+ * - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q).
+ *
* <p>An example for creating a capture configuration for capturing all media playback:
*
* <pre>
+ * MediaProjection mediaProjection;
+ * // Retrieve a audio capable projection from the MediaProjectionManager
* AudioAttributes mediaAttr = new AudioAttributes.Builder()
* .setUsage(AudioAttributes.USAGE_MEDIA)
* .build();
- * AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder()
+ * AudioPlaybackCaptureConfiguration config =
+ * new AudioPlaybackCaptureConfiguration.Builder(mediaProjection)
* .addMatchingUsage(mediaAttr)
* .build();
* AudioRecord record = new AudioRecord.Builder()
- * .setPlaybackCaptureConfig(config)
+ * .setAudioPlaybackCaptureConfig(config)
* .build();
* </pre>
*
- * @see AudioRecord.Builder#setPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration)
+ * @see MediaProjectionManager#getMediaProjection(int, Intent)
+ * @see AudioRecord.Builder#setAudioPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration)
*/
public final class AudioPlaybackCaptureConfiguration {
private final AudioMixingRule mAudioMixingRule;
+ private final MediaProjection mProjection;
- private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule) {
+ private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule,
+ MediaProjection projection) {
mAudioMixingRule = audioMixingRule;
+ mProjection = projection;
}
/**
@@ -60,6 +78,9 @@
.setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER)
.build();
}
+ MediaProjection getMediaProjection() {
+ return mProjection;
+ }
/** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */
public static final class Builder {
@@ -70,12 +91,26 @@
private static final String ERROR_MESSAGE_MISMATCHED_RULES =
"Inclusive and exclusive usage rules cannot be combined";
+ private static final String ERROR_MESSAGE_START_ACTIVITY_FAILED =
+ "startActivityForResult failed";
+ private static final String ERROR_MESSAGE_NON_AUDIO_PROJECTION =
+ "MediaProjection can not project audio";
private final AudioMixingRule.Builder mAudioMixingRuleBuilder;
+ private final MediaProjection mProjection;
private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED;
private int mUidMatchType = MATCH_TYPE_UNSPECIFIED;
- public Builder() {
+ /** @param projection A MediaProjection that supports audio projection. */
+ public Builder(@NonNull MediaProjection projection) {
+ Preconditions.checkNotNull(projection);
+ try {
+ Preconditions.checkArgument(projection.getProjection().canProjectAudio(),
+ ERROR_MESSAGE_NON_AUDIO_PROJECTION);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mProjection = projection;
mAudioMixingRuleBuilder = new AudioMixingRule.Builder();
}
@@ -155,7 +190,8 @@
* @throws UnsupportedOperationException if the parameters set are incompatible.
*/
public AudioPlaybackCaptureConfiguration build() {
- return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build());
+ return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build(),
+ mProjection);
}
}
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4f2de23..ec1a854 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -26,6 +26,7 @@
import android.app.ActivityThread;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioPolicy;
+import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -648,7 +649,9 @@
private AudioRecord buildAudioPlaybackCaptureRecord() {
AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
+ MediaProjection projection = mAudioPlaybackCaptureConfiguration.getMediaProjection();
AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
+ .setMediaProjection(projection)
.addMix(audioMix).build();
AudioRecord record = audioPolicy.createAudioRecordSink(audioMix);
record.unregisterAudioPolicyOnRelease(audioPolicy);
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f5aeca7..571e67e 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -34,6 +34,7 @@
import android.media.VolumePolicy;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.IAudioPolicyCallback;
+import android.media.projection.IMediaProjection;
/**
* {@hide}
@@ -176,7 +177,7 @@
String registerAudioPolicy(in AudioPolicyConfig policyConfig,
in IAudioPolicyCallback pcb, boolean hasFocusListener, boolean isFocusPolicy,
- boolean isVolumeController);
+ boolean isVolumeController, in IMediaProjection projection);
oneway void unregisterAudioPolicyAsync(in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index cf5711d..a9e33fd 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -19,9 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
-import android.hardware.cas.V1_1.ICas;
+import android.hardware.cas.V1_0.ICas;
+import android.hardware.cas.V1_0.IMediaCasService;
import android.hardware.cas.V1_1.ICasListener;
-import android.hardware.cas.V1_1.IMediaCasService;
import android.media.MediaCasException.*;
import android.os.Bundle;
import android.os.Handler;
@@ -99,23 +99,35 @@
public final class MediaCas implements AutoCloseable {
private static final String TAG = "MediaCas";
private ICas mICas;
+ private android.hardware.cas.V1_1.ICas mICasV11;
private EventListener mListener;
private HandlerThread mHandlerThread;
private EventHandler mEventHandler;
- private static final Singleton<IMediaCasService> gDefault =
- new Singleton<IMediaCasService>() {
+ private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
@Override
protected IMediaCasService create() {
try {
- return IMediaCasService.getService(true /*wait*/);
- } catch (RemoteException e) {}
+ Log.d(TAG, "Tried to get cas@1.1 service");
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
+ if (serviceV11 != null) {
+ return serviceV11;
+ }
+ } catch (Exception eV1_1) {
+ try {
+ Log.d(TAG, "Tried to get cas@1.0 service");
+ return IMediaCasService.getService(true /*wait*/);
+ } catch (Exception eV1_0) {
+ Log.d(TAG, "Failed to get cas@1.0 service");
+ }
+ }
return null;
}
};
static IMediaCasService getService() {
- return gDefault.get();
+ return sService.get();
}
private void validateInternalStates() {
@@ -126,11 +138,12 @@
private void cleanupAndRethrowIllegalState() {
mICas = null;
+ mICasV11 = null;
throw new IllegalStateException();
}
- private class EventHandler extends Handler
- {
+ private class EventHandler extends Handler {
+
private static final int MSG_CAS_EVENT = 0;
private static final int MSG_CAS_SESSION_EVENT = 1;
private static final String SESSION_KEY = "sessionId";
@@ -164,7 +177,7 @@
}
@Override
public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
- int event, int arg, @Nullable ArrayList<Byte> data)
+ int event, int arg, @Nullable ArrayList<Byte> data)
throws RemoteException {
Message msg = mEventHandler.obtainMessage();
msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
@@ -177,7 +190,6 @@
mEventHandler.sendMessage(msg);
}
};
-
/**
* Describe a CAS plugin with its CA_system_ID and string name.
*
@@ -338,9 +350,14 @@
throws MediaCasException {
validateInternalStates();
+ if (mICasV11 == null) {
+ Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
+ throw new UnsupportedCasException("Send Session Event is not supported");
+ }
+
try {
MediaCasException.throwExceptionIfNeeded(
- mICas.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
+ mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
@@ -427,7 +444,16 @@
*/
public MediaCas(int CA_system_id) throws UnsupportedCasException {
try {
- mICas = getService().createPluginExt(CA_system_id, mBinder);
+ IMediaCasService service = getService();
+ android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+ android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
+ if (serviceV11 == null) {
+ Log.d(TAG, "Used cas@1_0 interface to create plugin");
+ mICas = service.createPlugin(CA_system_id, mBinder);
+ } else {
+ Log.d(TAG, "Used cas@1.1 interface to create plugin");
+ mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
+ }
} catch(Exception e) {
Log.e(TAG, "Failed to create plugin: " + e);
mICas = null;
@@ -528,7 +554,7 @@
}
}
- private class OpenSessionCallback implements ICas.openSessionCallback {
+ private class OpenSessionCallback implements android.hardware.cas.V1_1.ICas.openSessionCallback{
public Session mSession;
public int mStatus;
@Override
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 761b625..6fd6298 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -133,7 +133,8 @@
}
- int getRouteFlags() {
+ /** @hide */
+ public int getRouteFlags() {
return mRouteFlags;
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 49867ab..445edd1 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.ActivityManager;
import android.content.Context;
@@ -31,6 +32,7 @@
import android.media.AudioTrack;
import android.media.IAudioService;
import android.media.MediaRecorder;
+import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -94,6 +96,8 @@
private AudioPolicyConfig mConfig;
+ private final MediaProjection mProjection;
+
/** @hide */
public AudioPolicyConfig getConfig() { return mConfig; }
/** @hide */
@@ -102,13 +106,17 @@
public boolean isFocusPolicy() { return mIsFocusPolicy; }
/** @hide */
public boolean isVolumeController() { return mVolCb != null; }
+ /** @hide */
+ public @Nullable MediaProjection getMediaProjection() {
+ return mProjection;
+ }
/**
* The parameter is guaranteed non-null through the Builder
*/
private AudioPolicy(AudioPolicyConfig config, Context context, Looper looper,
AudioPolicyFocusListener fl, AudioPolicyStatusListener sl, boolean isFocusPolicy,
- AudioPolicyVolumeCallback vc) {
+ AudioPolicyVolumeCallback vc, @Nullable MediaProjection projection) {
mConfig = config;
mStatus = POLICY_STATUS_UNREGISTERED;
mContext = context;
@@ -125,6 +133,7 @@
mStatusListener = sl;
mIsFocusPolicy = isFocusPolicy;
mVolCb = vc;
+ mProjection = projection;
}
/**
@@ -139,6 +148,7 @@
private AudioPolicyStatusListener mStatusListener;
private boolean mIsFocusPolicy = false;
private AudioPolicyVolumeCallback mVolCb;
+ private MediaProjection mProjection;
/**
* Constructs a new Builder with no audio mixes.
@@ -223,6 +233,23 @@
}
/**
+ * Set a media projection obtained through createMediaProjection().
+ *
+ * A MediaProjection that can project audio allows to register an audio
+ * policy LOOPBACK|RENDER without the MODIFY_AUDIO_ROUTING permission.
+ *
+ * @hide
+ */
+ public Builder setMediaProjection(@NonNull MediaProjection projection) {
+ if (projection == null) {
+ throw new IllegalArgumentException("Invalid null volume callback");
+ }
+ mProjection = projection;
+ return this;
+
+ }
+
+ /**
* Combines all of the attributes that have been set on this {@code Builder} and returns a
* new {@link AudioPolicy} object.
* @return a new {@code AudioPolicy} object.
@@ -242,7 +269,7 @@
+ "an AudioPolicyFocusListener");
}
return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
- mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb);
+ mFocusListener, mStatusListener, mIsFocusPolicy, mVolCb, mProjection);
}
}
@@ -423,15 +450,35 @@
return false;
}
}
- if (!(PackageManager.PERMISSION_GRANTED == checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
+
+ // Loopback|capture only need an audio projection, everything else need MODIFY_AUDIO_ROUTING
+ boolean canModifyAudioRouting = PackageManager.PERMISSION_GRANTED
+ == checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING);
+
+ boolean canProjectAudio;
+ try {
+ canProjectAudio = mProjection != null && mProjection.getProjection().canProjectAudio();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to check if MediaProjection#canProjectAudio");
+ throw e.rethrowFromSystemServer();
+ }
+
+ if (!((isLoopbackRenderPolicy() && canProjectAudio) || canModifyAudioRouting)) {
Slog.w(TAG, "Cannot use AudioPolicy for pid " + Binder.getCallingPid() + " / uid "
- + Binder.getCallingUid() + ", needs MODIFY_AUDIO_ROUTING");
+ + Binder.getCallingUid() + ", needs MODIFY_AUDIO_ROUTING or "
+ + "MediaProjection that can project audio.");
return false;
}
return true;
}
+ private boolean isLoopbackRenderPolicy() {
+ synchronized (mLock) {
+ return mConfig.mMixes.stream().allMatch(mix -> mix.getRouteFlags()
+ == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
+ }
+ }
+
/**
* Returns {@link PackageManager#PERMISSION_GRANTED} if the caller has the given permission.
*/
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index e591ea9..93d2b67 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -81,9 +81,9 @@
<com.android.systemui.statusbar.car.CarFacetButton
android:id="@+id/phone_nav"
style="@style/NavigationBarButton"
- systemui:componentNames="com.android.car.dialer/.TelecomActivity"
systemui:icon="@drawable/car_ic_phone"
- systemui:intent="intent:#Intent;component=com.android.car.dialer/.TelecomActivity;launchFlags=0x14000000;end"
+ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end"
+ systemui:packages="com.android.car.dialer"
systemui:selectedIcon="@drawable/car_ic_phone_selected"
systemui:useMoreIcon="false"
/>
diff --git a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
index 28b05396..82e33cc 100644
--- a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
+++ b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
@@ -46,8 +46,6 @@
import java.net.MalformedURLException;
import java.net.URL;
-
-
/**
* Online Sign Up Login Web View launched during Provision Process of Hotspot 2.0 rel2.
*/
@@ -64,6 +62,7 @@
private WebView mWebView;
private SwipeRefreshLayout mSwipeRefreshLayout;
private ProgressBar mProgressBar;
+ private boolean mForceDisconnect = true;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -141,6 +140,7 @@
if (DBG) {
Log.d(TAG, "Lost for the current Network, close the browser");
}
+ mForceDisconnect = false; // It is already disconnected.
if (mNetwork.equals(network)) {
finishAndRemoveTask();
}
@@ -193,12 +193,6 @@
mWebView.goBack();
return true;
}
-
- // In case of back key, it needs to disconnect current connection with OSU AP to
- // abort current Provisioning flow.
- if (mWifiManager != null) {
- mWifiManager.disconnect();
- }
}
return super.onKeyDown(keyCode, event);
}
@@ -207,6 +201,11 @@
protected void onDestroy() {
if (mNetworkCallback != null) {
mCm.unregisterNetworkCallback(mNetworkCallback);
+ mNetworkCallback = null;
+ }
+ if (mWifiManager != null && mForceDisconnect) {
+ mWifiManager.disconnect();
+ mWifiManager = null;
}
super.onDestroy();
}
@@ -232,6 +231,7 @@
private class OsuWebViewClient extends WebViewClient {
boolean mPageError = false;
+ boolean mRedirectResponseReceived = false;
@Override
public void onPageStarted(WebView view, String urlString, Bitmap favicon) {
@@ -247,6 +247,10 @@
// Do not show the page error on UI.
if (mPageError) {
+ if (mRedirectResponseReceived) {
+ // Do not disconnect current connection while provisioning is in progress.
+ mForceDisconnect = false;
+ }
finishAndRemoveTask();
}
}
@@ -255,6 +259,7 @@
public void onReceivedError(WebView view, WebResourceRequest request,
WebResourceError error) {
if (request.getUrl().toString().startsWith("http://127.0.0.1")) {
+ mRedirectResponseReceived = true;
view.stopLoading();
}
@@ -266,5 +271,4 @@
}
}
}
-
}
diff --git a/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
index 330049f..6e95a0e 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
+++ b/packages/SettingsLib/EntityHeaderWidgets/src/com/android/settingslib/widget/AppEntitiesHeaderController.java
@@ -90,6 +90,7 @@
private int mHeaderTitleRes;
private int mHeaderDetailsRes;
private int mHeaderEmptyRes;
+ private CharSequence mHeaderDetails;
private View.OnClickListener mDetailsOnClickListener;
/**
@@ -148,6 +149,14 @@
}
/**
+ * Set the text for app entities header details.
+ */
+ public AppEntitiesHeaderController setHeaderDetails(CharSequence detailsText) {
+ mHeaderDetails = detailsText;
+ return this;
+ }
+
+ /**
* Register a callback to be invoked when header details view is clicked.
*/
public AppEntitiesHeaderController setHeaderDetailsClickListener(
@@ -232,11 +241,13 @@
}
private void bindHeaderDetailsView() {
- CharSequence detailsText = "";
- try {
- detailsText = mContext.getText(mHeaderDetailsRes);
- } catch (Resources.NotFoundException e) {
- Log.e(TAG, "Resource of header details can't not be found!", e);
+ CharSequence detailsText = mHeaderDetails;
+ if (TextUtils.isEmpty(detailsText)) {
+ try {
+ detailsText = mContext.getText(mHeaderDetailsRes);
+ } catch (Resources.NotFoundException e) {
+ Log.e(TAG, "Resource of header details can't not be found!", e);
+ }
}
mHeaderDetailsView.setText(detailsText);
mHeaderDetailsView.setVisibility(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
index 63a958e..9a07ca8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
@@ -85,6 +85,23 @@
}
@Test
+ public void setHeaderDetails_onlyDetailsTextSet_shouldSetToDetailsView() {
+ mController.setHeaderDetails(TITLE).apply();
+ final TextView view = mAppEntitiesHeaderView.findViewById(R.id.header_details);
+
+ assertThat(view.getText()).isEqualTo(TITLE);
+ }
+
+ @Test
+ public void setHeaderDetails_detailsTextAndResBothSet_shouldSetTextToDetailsView() {
+ mController.setHeaderDetailsRes(R.string.expand_button_title);
+ mController.setHeaderDetails(TITLE).apply();
+ final TextView view = mAppEntitiesHeaderView.findViewById(R.id.header_details);
+
+ assertThat(view.getText()).isEqualTo(TITLE);
+ }
+
+ @Test
public void setHeaderDetailsClickListener_setClickListener_detailsViewAttachClickListener() {
mController.setHeaderDetailsClickListener(v -> {
}).apply();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index ef90dc9..0ee16a9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -23,6 +23,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
@@ -2440,6 +2441,7 @@
private void loadGlobalSettings(SQLiteDatabase db) {
SQLiteStatement stmt = null;
+ final Resources res = mContext.getResources();
try {
stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
+ " VALUES(?,?);");
@@ -2468,7 +2470,7 @@
loadSetting(stmt, Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
("1".equals(SystemProperties.get("ro.kernel.qemu")) ||
- mContext.getResources().getBoolean(R.bool.def_stay_on_while_plugged_in))
+ res.getBoolean(R.bool.def_stay_on_while_plugged_in))
? 1 : 0);
loadIntegerSetting(stmt, Settings.Global.WIFI_SLEEP_POLICY,
@@ -2505,14 +2507,14 @@
loadBooleanSetting(stmt, Settings.Global.DEVICE_PROVISIONED,
R.bool.def_device_provisioned);
- final int maxBytes = mContext.getResources().getInteger(
+ final int maxBytes = res.getInteger(
R.integer.def_download_manager_max_bytes_over_mobile);
if (maxBytes > 0) {
loadSetting(stmt, Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
Integer.toString(maxBytes));
}
- final int recommendedMaxBytes = mContext.getResources().getInteger(
+ final int recommendedMaxBytes = res.getInteger(
R.integer.def_download_manager_recommended_max_bytes_over_mobile);
if (recommendedMaxBytes > 0) {
loadSetting(stmt, Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
@@ -2609,6 +2611,20 @@
loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
+ // Set default lid/cover behaviour according to legacy device config
+ final int defaultLidBehavior;
+ if (res.getBoolean(com.android.internal.R.bool.config_lidControlsSleep)) {
+ // WindowManagerFuncs.LID_BEHAVIOR_SLEEP
+ defaultLidBehavior = 1;
+ } else if (res.getBoolean(com.android.internal.R.bool.config_lidControlsScreenLock)) {
+ // WindowManagerFuncs.LID_BEHAVIOR_LOCK
+ defaultLidBehavior = 2;
+ } else {
+ // WindowManagerFuncs.LID_BEHAVIOR_NONE
+ defaultLidBehavior = 0;
+ }
+ loadSetting(stmt, Settings.Global.LID_BEHAVIOR, defaultLidBehavior);
+
/*
* IMPORTANT: Do not add any more upgrade steps here as the global,
* secure, and system settings are no longer stored in a database
diff --git a/packages/SystemUI/res/layout/bubble_permission_view.xml b/packages/SystemUI/res/layout/bubble_permission_view.xml
index 7fbb78a..c9d8a91 100644
--- a/packages/SystemUI/res/layout/bubble_permission_view.xml
+++ b/packages/SystemUI/res/layout/bubble_permission_view.xml
@@ -17,7 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="@dimen/bubble_permission_height"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:paddingStart="@dimen/bubble_expanded_header_horizontal_padding"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1f6e3c2..536bc4e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1045,4 +1045,8 @@
<dimen name="bubble_header_icon_size">48dp</dimen>
<!-- Size of the app icon shown in the bubble permission view -->
<dimen name="bubble_permission_icon_size">24dp</dimen>
+ <!-- Space between the pointer triangle and the bubble expanded view -->
+ <dimen name="bubble_pointer_margin">8dp</dimen>
+ <!-- Height of the permission prompt shown with bubbles -->
+ <dimen name="bubble_permission_height">120dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index c5dc324..3827e44 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -34,6 +34,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
import androidx.annotation.VisibleForTesting;
@@ -241,6 +242,7 @@
// Draw clock view hierarchy to canvas.
Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
+ dispatchVisibilityAggregated(clockView, true);
clockView.measure(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
clockView.layout(0, 0, mWidth, mHeight);
@@ -250,6 +252,24 @@
return bitmap;
}
+ private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+ // Similar to View.dispatchVisibilityAggregated implementation.
+ final boolean thisVisible = view.getVisibility() == View.VISIBLE;
+ if (thisVisible || !isVisible) {
+ view.onVisibilityAggregated(isVisible);
+ }
+
+ if (view instanceof ViewGroup) {
+ isVisible = thisVisible && isVisible;
+ ViewGroup vg = (ViewGroup) view;
+ int count = vg.getChildCount();
+
+ for (int i = 0; i < count; i++) {
+ dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
+ }
+ }
+ }
+
private void notifyClockChanged(ClockPlugin plugin) {
for (int i = 0; i < mListeners.size(); i++) {
// It probably doesn't make sense to supply the same plugin instances to multiple
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 4eea9f8..471619e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -80,16 +80,21 @@
// Enables some subset of notifs to automatically become bubbles
private static final boolean DEBUG_ENABLE_AUTO_BUBBLE = false;
- // Secure settings flags
- // Feature level flag
+ /** Flag to enable or disable the entire feature */
private static final String ENABLE_BUBBLES = "experiment_enable_bubbles";
- // Auto bubble flags set whether different notification types should be presented as a bubble
+ /** Auto bubble flags set whether different notif types should be presented as a bubble */
private static final String ENABLE_AUTO_BUBBLE_MESSAGES = "experiment_autobubble_messaging";
private static final String ENABLE_AUTO_BUBBLE_ONGOING = "experiment_autobubble_ongoing";
private static final String ENABLE_AUTO_BUBBLE_ALL = "experiment_autobubble_all";
- // Use an activity view for an auto-bubbled notification if it has an appropriate content intent
+
+ /** Use an activityView for an auto-bubbled notifs if it has an appropriate content intent */
private static final String ENABLE_BUBBLE_CONTENT_INTENT = "experiment_bubble_content_intent";
+ /** Whether the row of bubble circles are anchored to the top or bottom of the screen. */
+ private static final String ENABLE_BUBBLES_AT_TOP = "experiment_enable_top_bubbles";
+ /** Flag to position the header below the activity view */
+ private static final String ENABLE_BUBBLE_FOOTER = "experiment_enable_bubble_footer";
+
private final Context mContext;
private final NotificationEntryManager mNotificationEntryManager;
private final IActivityTaskManager mActivityTaskManager;
@@ -548,6 +553,22 @@
ENABLE_BUBBLES, 1) != 0;
}
+ /**
+ * Whether bubbles should be positioned at the top of the screen or not.
+ */
+ public static boolean showBubblesAtTop(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ ENABLE_BUBBLES_AT_TOP, 0) != 0;
+ }
+
+ /**
+ * Whether the bubble chrome should display as a footer or not (in which case it's a header).
+ */
+ public static boolean useFooter(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ ENABLE_BUBBLE_FOOTER, 0) != 0;
+ }
+
/** PinnedStackListener that dispatches IME visibility updates to the stack. */
private class BubblesImeListener extends IPinnedStackListener.Stub {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 7884800..b635033 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -70,8 +70,13 @@
public class BubbleExpandedView extends LinearLayout implements View.OnClickListener {
private static final String TAG = "BubbleExpandedView";
+ // Configurable via bubble settings; just for testing
+ private boolean mUseFooter;
+ private boolean mShowOnTop;
+
// The triangle pointing to the expanded view
private View mPointerView;
+ private int mPointerMargin;
// Header
private View mHeaderView;
@@ -90,6 +95,8 @@
private int mMinHeight;
private int mHeaderHeight;
+ private int mBubbleHeight;
+ private int mPermissionHeight;
private NotificationEntry mEntry;
private PackageManager mPm;
@@ -150,6 +157,7 @@
mPm = context.getPackageManager();
mMinHeight = getResources().getDimensionPixelSize(
R.dimen.bubble_expanded_default_height);
+ mPointerMargin = getResources().getDimensionPixelSize(R.dimen.bubble_pointer_margin);
try {
mNotificationManagerService = INotificationManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
@@ -172,8 +180,11 @@
int bgColor = ta.getColor(0, Color.WHITE);
ta.recycle();
+ mShowOnTop = BubbleController.showBubblesAtTop(getContext());
+ mUseFooter = BubbleController.useFooter(getContext());
+
ShapeDrawable triangleDrawable = new ShapeDrawable(
- TriangleShape.create(width, height, true /* pointUp */));
+ TriangleShape.create(width, height, mShowOnTop /* pointUp */));
triangleDrawable.setTint(bgColor);
mPointerView.setBackground(triangleDrawable);
@@ -195,6 +206,8 @@
mHeaderHeight = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_expanded_header_height);
+ mPermissionHeight = getContext().getResources().getDimensionPixelSize(
+ R.dimen.bubble_permission_height);
mHeaderView = findViewById(R.id.header_layout);
mDeepLinkIcon = findViewById(R.id.deep_link_button);
mSettingsIcon = findViewById(R.id.settings_button);
@@ -226,6 +239,15 @@
activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
return view.onApplyWindowInsets(insets);
});
+
+ if (!mShowOnTop) {
+ removeView(mPointerView);
+ if (mUseFooter) {
+ removeView(viewWrapper);
+ addView(viewWrapper);
+ }
+ addView(mPointerView);
+ }
}
/**
@@ -332,7 +354,11 @@
// Use notification view
mNotifRow = mEntry.getRow();
- addView(mNotifRow);
+ if (mShowOnTop) {
+ addView(mNotifRow);
+ } else {
+ addView(mNotifRow, mUseFooter ? 0 : 1);
+ }
}
updateView();
}
@@ -345,6 +371,17 @@
return true;
}
+ /**
+ * @return total height that the expanded view occupies.
+ */
+ int getExpandedSize() {
+ int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
+ ? mHeaderHeight
+ : mPermissionHeight;
+ return mBubbleHeight + mPointerView.getHeight() + mPointerMargin
+ + chromeHeight;
+ }
+
void updateHeight() {
if (usingActivityView()) {
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
@@ -358,12 +395,19 @@
? data.getDesiredHeight()
: mMinHeight;
}
- int max = mStackView.getMaxExpandedHeight() - mHeaderHeight;
+ int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
+ ? mHeaderHeight
+ : mPermissionHeight;
+ int max = mStackView.getMaxExpandedHeight() - chromeHeight - mPointerView.getHeight()
+ - mPointerMargin;
int height = Math.min(desiredHeight, max);
height = Math.max(height, mMinHeight);
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
lp.height = height;
+ mBubbleHeight = height;
mActivityView.setLayoutParams(lp);
+ } else {
+ mBubbleHeight = mNotifRow != null ? mNotifRow.getIntrinsicHeight() : mMinHeight;
}
}
@@ -412,6 +456,7 @@
} else if (mOnBubbleBlockedListener != null) {
mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
}
+ mStackView.onExpandedHeightChanged();
logBubbleClickEvent(mEntry.notification,
allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e20be8e..167bf47 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -173,7 +173,7 @@
int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation);
mStackAnimationController = new StackAnimationController();
- mExpandedAnimationController = new ExpandedAnimationController();
+ mExpandedAnimationController = new ExpandedAnimationController(mDisplaySize);
mBubbleContainer = new PhysicsAnimationLayout(context);
mBubbleContainer.setMaxRenderedChildren(
@@ -513,8 +513,7 @@
final float yStart = Math.min(
mStackAnimationController.getStackPosition().y,
mExpandedAnimateYDistance);
- final float yDest = getStatusBarHeight()
- + mExpandedBubble.iconView.getHeight() + mBubblePadding;
+ final float yDest = getYPositionForExpandedView();
if (shouldExpand) {
mExpandedViewContainer.setTranslationX(xStart);
@@ -668,13 +667,39 @@
* y position when the bubbles are expanded as well as the bounds of the dismiss target.
*/
int getMaxExpandedHeight() {
+ boolean showOnTop = BubbleController.showBubblesAtTop(getContext());
int expandedY = (int) mExpandedAnimationController.getExpandedY();
- int bubbleContainerHeight = mBubbleContainer.getChildAt(0) != null
- ? mBubbleContainer.getChildAt(0).getHeight()
- : 0;
- // PIP dismiss view uses FLAG_LAYOUT_IN_SCREEN so we need to subtract the bottom inset
- int pipDismissHeight = mPipDismissHeight - getBottomInset();
- return mDisplaySize.y - expandedY - mBubbleSize - pipDismissHeight;
+ if (showOnTop) {
+ // PIP dismiss view uses FLAG_LAYOUT_IN_SCREEN so we need to subtract the bottom inset
+ int pipDismissHeight = mPipDismissHeight - getBottomInset();
+ return mDisplaySize.y - expandedY - mBubbleSize - pipDismissHeight;
+ } else {
+ return expandedY - getStatusBarHeight();
+ }
+ }
+
+ /**
+ * Calculates the y position of the expanded view when it is expanded.
+ */
+ float getYPositionForExpandedView() {
+ boolean showOnTop = BubbleController.showBubblesAtTop(getContext());
+ if (showOnTop) {
+ return getStatusBarHeight() + mBubbleSize + mBubblePadding;
+ } else {
+ return mExpandedAnimationController.getExpandedY()
+ - mExpandedBubble.expandedView.getExpandedSize() - mBubblePadding;
+ }
+ }
+
+ /**
+ * Called when the height of the currently expanded view has changed (not via an
+ * update to the bubble's desired height but for some other reason, e.g. permission view
+ * goes away).
+ */
+ void onExpandedHeightChanged() {
+ if (mIsExpanded) {
+ requestUpdate();
+ }
}
/**
@@ -751,6 +776,8 @@
mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
if (mIsExpanded) {
+ final float y = getYPositionForExpandedView();
+ mExpandedViewContainer.setTranslationY(y);
mExpandedBubble.expandedView.updateView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index f0d9be1..f7896b0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -17,6 +17,7 @@
package com.android.systemui.bubbles.animation;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
import android.view.View;
import android.view.WindowInsets;
@@ -25,6 +26,7 @@
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleController;
import com.google.android.collect.Sets;
@@ -61,6 +63,14 @@
private float mBubbleSizePx;
/** Height of the status bar. */
private float mStatusBarHeight;
+ /** Size of display. */
+ private Point mDisplaySize;
+ /** Size of dismiss target at bottom of screen. */
+ private float mPipDismissHeight;
+
+ public ExpandedAnimationController(Point displaySize) {
+ mDisplaySize = displaySize;
+ }
/**
* Whether the individual bubble has been dragged out of the row of bubbles far enough to cause
@@ -88,6 +98,7 @@
mBubbleSizePx = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
mStatusBarHeight =
res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mPipDismissHeight = res.getDimensionPixelSize(R.dimen.pip_dismiss_gradient_height);
}
/**
@@ -204,16 +215,19 @@
/** The Y value of the row of expanded bubbles. */
public float getExpandedY() {
+ boolean showOnTop = mLayout != null
+ && BubbleController.showBubblesAtTop(mLayout.getContext());
final WindowInsets insets = mLayout != null ? mLayout.getRootWindowInsets() : null;
- if (insets != null) {
+ if (showOnTop && insets != null) {
return mBubblePaddingPx + Math.max(
mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
+ } else {
+ int bottomInset = insets != null ? insets.getSystemWindowInsetBottom() : 0;
+ return mDisplaySize.y - mBubbleSizePx - (mPipDismissHeight - bottomInset);
}
-
- return mBubblePaddingPx;
}
/** Runs the given Runnable after all translation-related animations have ended. */
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 7312cbc..e27c25e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -27,7 +27,6 @@
import android.database.ContentObserver;
import android.os.BatteryManager;
import android.os.Handler;
-import android.os.HardwarePropertiesManager;
import android.os.IBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -70,7 +69,6 @@
final Receiver mReceiver = new Receiver();
private PowerManager mPowerManager;
- private HardwarePropertiesManager mHardwarePropertiesManager;
private WarningsUI mWarnings;
private final Configuration mLastConfiguration = new Configuration();
private long mTimeRemaining = Long.MAX_VALUE;
@@ -96,8 +94,6 @@
public void start() {
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mHardwarePropertiesManager = (HardwarePropertiesManager)
- mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
mWarnings = Dependency.get(WarningsUI.class);
mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
index 3bd582f..b4059c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PointF;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -40,7 +41,8 @@
public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestCase {
@Spy
- private ExpandedAnimationController mExpandedController = new ExpandedAnimationController();
+ private ExpandedAnimationController mExpandedController =
+ new ExpandedAnimationController(new Point(500, 1000) /* displaySize */);
private int mStackOffset;
private float mBubblePadding;
@@ -167,7 +169,7 @@
assertEquals(mBubblePadding + (i * (mBubbleSize + mBubblePadding)),
mLayout.getChildAt(i).getTranslationX(),
2f);
- assertEquals(mBubblePadding + mCutoutInsetSize,
+ assertEquals(mExpandedController.getExpandedY(),
mLayout.getChildAt(i).getTranslationY(), 2f);
if (i < mMaxRenderedBubbles) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 4a4e247..0aed63d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.content.Intent;
import android.os.BatteryManager;
-import android.os.HardwarePropertiesManager;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.PowerManager;
@@ -76,7 +75,6 @@
private static final int OLD_BATTERY_LEVEL_NINE = 9;
private static final int OLD_BATTERY_LEVEL_10 = 10;
private static final long VERY_BELOW_SEVERE_HYBRID_THRESHOLD = TimeUnit.MINUTES.toMillis(15);
- private HardwarePropertiesManager mHardProps;
private WarningsUI mMockWarnings;
private PowerUI mPowerUI;
private EnhancedEstimates mEnhancedEstimates;
@@ -90,10 +88,8 @@
MockitoAnnotations.initMocks(this);
mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
mEnhancedEstimates = mDependency.injectMockDependency(EnhancedEstimates.class);
- mHardProps = mock(HardwarePropertiesManager.class);
mContext.putComponent(StatusBar.class, mock(StatusBar.class));
- mContext.addMockSystemService(Context.HARDWARE_PROPERTIES_SERVICE, mHardProps);
mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
createPowerUi();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index e4da859..f72d411 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -38,6 +38,7 @@
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
+import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -251,6 +252,7 @@
assertScrimTint(mScrimBehind, false /* tinted */);
}
+ @FlakyTest(bugId = 124858892)
@Test
public void transitionToUnlocked() {
mScrimController.setPanelExpansion(0f);
@@ -295,6 +297,7 @@
Assert.assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED);
}
+ @FlakyTest(bugId = 124858892)
@Test
public void panelExpansion() {
mScrimController.setPanelExpansion(0f);
@@ -317,6 +320,7 @@
mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
}
+ @FlakyTest(bugId = 124858892)
@Test
public void panelExpansionAffectsAlpha() {
mScrimController.setPanelExpansion(0f);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 4584306..b3e5f69 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -247,6 +247,12 @@
LOCATION_GONE = 6; // the view isn't laid out at all
}
+ // Subtypes for profile logging
+ enum ActiveUserProfile {
+ PARENT_PROFILE = 1;
+ MANAGED_PROFILE = 2;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -3589,7 +3595,7 @@
// OPEN: Settings > Apps > Default Apps > Default sms
DEFAULT_SMS_PICKER = 789;
- // OPEN: Settings > Apps > Default Apps > Default notification assistant
+ // OPEN: Settings > Apps > Notification > Notification Assistant
DEFAULT_NOTIFICATION_ASSISTANT = 790;
// OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
@@ -7007,6 +7013,10 @@
// Different display can have different orientations, so need to log display id
FIELD_DISPLAY_ID = 1660;
+ // ACTION: Changing from work to parent profile or vice versa
+ // OS: Q
+ ACTION_SWITCH_SHARE_PROFILE = 1661;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/art-profile b/services/art-profile
index e750380..7892fcb 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -2942,7 +2942,7 @@
HSPLcom/android/server/policy/WindowManagerPolicy;->onKeyguardOccludedChangedLw(Z)V
HSPLcom/android/server/policy/WindowManagerPolicy;->onLockTaskStateChangedLw(I)V
HSPLcom/android/server/policy/WindowManagerPolicy;->onSystemUiStarted()V
-HSPLcom/android/server/policy/WindowManagerPolicy;->performHapticFeedbackLw(Lcom/android/server/policy/WindowManagerPolicy$WindowState;IZ)Z
+HSPLcom/android/server/policy/WindowManagerPolicy;->performHapticFeedback(ILjava/lang/String;IZ)Z
HSPLcom/android/server/policy/WindowManagerPolicy;->prepareAddWindowLw(Lcom/android/server/policy/WindowManagerPolicy$WindowState;Landroid/view/WindowManager$LayoutParams;)I
HSPLcom/android/server/policy/WindowManagerPolicy;->registerShortcutKey(JLcom/android/internal/policy/IShortcutService;)V
HSPLcom/android/server/policy/WindowManagerPolicy;->removeWindowLw(Lcom/android/server/policy/WindowManagerPolicy$WindowState;)V
@@ -15736,7 +15736,7 @@
PLcom/android/server/policy/PhoneWindowManager;->onKeyguardOccludedChangedLw(Z)V
PLcom/android/server/policy/PhoneWindowManager;->onOverlayChangedLw()V
PLcom/android/server/policy/PhoneWindowManager;->onSystemUiStarted()V
-PLcom/android/server/policy/PhoneWindowManager;->performHapticFeedbackLw(Lcom/android/server/policy/WindowManagerPolicy$WindowState;IZ)Z
+PLcom/android/server/policy/PhoneWindowManager;->performHapticFeedback(ILjava/lang/String;IZ)Z
PLcom/android/server/policy/PhoneWindowManager;->powerPress(JZI)V
PLcom/android/server/policy/PhoneWindowManager;->prepareAddWindowLw(Lcom/android/server/policy/WindowManagerPolicy$WindowState;Landroid/view/WindowManager$LayoutParams;)I
PLcom/android/server/policy/PhoneWindowManager;->readCameraLensCoverState()V
@@ -18331,7 +18331,7 @@
PLcom/android/server/wm/Session;->killSessionLocked()V
PLcom/android/server/wm/Session;->onRectangleOnScreenRequested(Landroid/os/IBinder;Landroid/graphics/Rect;)V
PLcom/android/server/wm/Session;->onWindowSurfaceVisibilityChanged(Lcom/android/server/wm/WindowSurfaceController;ZI)V
-PLcom/android/server/wm/Session;->performHapticFeedback(Landroid/view/IWindow;IZ)Z
+PLcom/android/server/wm/Session;->performHapticFeedback(IZ)Z
PLcom/android/server/wm/Session;->relayout(Landroid/view/IWindow;ILandroid/view/WindowManager$LayoutParams;IIIIJLandroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/graphics/Rect;Landroid/view/DisplayCutout$ParcelableWrapper;Landroid/util/MergedConfiguration;Landroid/view/Surface;)I
PLcom/android/server/wm/Session;->remove(Landroid/view/IWindow;)V
PLcom/android/server/wm/Session;->sendWallpaperCommand(Landroid/os/IBinder;Ljava/lang/String;IIILandroid/os/Bundle;Z)Landroid/os/Bundle;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 364e537..2e99654 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1085,6 +1085,7 @@
if (remoteService != null) {
remoteService.destroy();
}
+ mRemoteAugmentedAutofillService = null;
}
}, mMaster.isInstantServiceAllowed(), mMaster.verbose);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index de9896e..f9fda64 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -26,7 +26,6 @@
import android.service.contentcapture.IContentCaptureService;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
-import android.text.format.DateUtils;
import android.util.Slog;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.UserDataRemovalRequest;
@@ -38,8 +37,6 @@
extends AbstractMultiplePendingRequestsRemoteService<RemoteContentCaptureService,
IContentCaptureService> {
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
-
private final IBinder mServerCallback;
RemoteContentCaptureService(Context context, String serviceInterface,
@@ -65,12 +62,6 @@
return PERMANENT_BOUND_TIMEOUT_MS;
}
- @Override // from AbstractRemoteService
- protected long getRemoteRequestMillis() {
- // TODO(b/111276913): read from Settings so it can be changed in the field
- return TIMEOUT_REMOTE_REQUEST_MILLIS;
- }
-
@Override // from RemoteService
protected void handleOnConnectedStateChanged(boolean state) {
if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 915c131..ed459db 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1060,7 +1060,8 @@
handleRegisterNetworkRequest(new NetworkRequestInfo(
null, networkRequest, new Binder()));
} else {
- handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID);
+ handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
+ /* callOnUnavailable */ false);
}
}
@@ -2641,11 +2642,25 @@
return true;
}
+ private boolean maybeHandleNetworkFactoryMessage(Message msg) {
+ switch (msg.what) {
+ default:
+ return false;
+ case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid,
+ /* callOnUnavailable */ true);
+ break;
+ }
+ }
+ return true;
+ }
+
@Override
public void handleMessage(Message msg) {
- if (!maybeHandleAsyncChannelMessage(msg) &&
- !maybeHandleNetworkMonitorMessage(msg) &&
- !maybeHandleNetworkAgentInfoMessage(msg)) {
+ if (!maybeHandleAsyncChannelMessage(msg)
+ && !maybeHandleNetworkMonitorMessage(msg)
+ && !maybeHandleNetworkAgentInfoMessage(msg)
+ && !maybeHandleNetworkFactoryMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
}
@@ -2787,6 +2802,9 @@
if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
if (VDBG) log("NetworkFactory connected");
+ // Finish setting up the full connection
+ mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
+ AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
@@ -2957,7 +2975,8 @@
if (existingRequest != null) { // remove the existing request.
if (DBG) log("Replacing " + existingRequest.request + " with "
+ nri.request + " because their intents matched.");
- handleReleaseNetworkRequest(existingRequest.request, getCallingUid());
+ handleReleaseNetworkRequest(existingRequest.request, getCallingUid(),
+ /* callOnUnavailable */ false);
}
handleRegisterNetworkRequest(nri);
}
@@ -2983,7 +3002,7 @@
int callingUid) {
NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
if (nri != null) {
- handleReleaseNetworkRequest(nri.request, callingUid);
+ handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false);
}
}
@@ -3066,7 +3085,8 @@
callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
}
- private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
+ private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid,
+ boolean callOnUnavailable) {
final NetworkRequestInfo nri =
getNriForAppRequest(request, callingUid, "release NetworkRequest");
if (nri == null) {
@@ -3076,6 +3096,9 @@
log("releasing " + nri.request + " (release request)");
}
handleRemoveNetworkRequest(nri);
+ if (callOnUnavailable) {
+ callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
+ }
}
private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
@@ -3507,7 +3530,8 @@
break;
}
case EVENT_RELEASE_NETWORK_REQUEST: {
- handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
+ handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
+ /* callOnUnavailable */ false);
break;
}
case EVENT_SET_ACCEPT_UNVALIDATED: {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cd9d84c..a5eab85 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2811,6 +2811,7 @@
@Override
public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
+ Slog.d(TAG, "unlockUserKey: " + userId);
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
@@ -4056,6 +4057,11 @@
@Override
public String[] getVisibleVolumesForUser(int userId) {
+ synchronized (mLock) {
+ if (!ArrayUtils.contains(mSystemUnlockedUsers, userId)) {
+ return EmptyArray.STRING;
+ }
+ }
final ArrayList<String> visibleVolsForUser = new ArrayList<>();
for (int i = mVisibleVols.size() - 1; i >= 0; --i) {
final VolumeInfo vol = mVisibleVols.get(i);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d902201..afdfbe3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -89,6 +89,8 @@
import android.media.audiopolicy.AudioPolicy;
import android.media.audiopolicy.AudioPolicyConfig;
import android.media.audiopolicy.IAudioPolicyCallback;
+import android.media.projection.IMediaProjection;
+import android.media.projection.IMediaProjectionManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -99,6 +101,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -453,6 +456,8 @@
// Broadcast receiver for device connections intent broadcasts
private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
+ private IMediaProjectionManager mProjectionService; // to validate projection token
+
/** Interface for UserManagerService. */
private final UserManagerInternal mUserManagerInternal;
private final ActivityManagerInternal mActivityManagerInternal;
@@ -6186,22 +6191,21 @@
// Audio policy management
//==========================================================================================
public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
- boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
+ boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController,
+ IMediaProjection projection) {
AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
- String regId = null;
- // error handling
- boolean hasPermissionForPolicy =
- (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
- android.Manifest.permission.MODIFY_AUDIO_ROUTING));
- if (!hasPermissionForPolicy) {
- Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
- + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
+ if (!isPolicyRegisterAllowed(policyConfig, projection)) {
+ Slog.w(TAG, "Permission denied to register audio policy for pid "
+ + Binder.getCallingPid() + " / uid " + Binder.getCallingUid()
+ + ", need MODIFY_AUDIO_ROUTING or MediaProjection that can project audio");
return null;
}
mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for "
+ pcb.asBinder() + " with config:" + policyConfig)).printLog(TAG));
+
+ String regId = null;
synchronized (mAudioPolicies) {
try {
if (mAudioPolicies.containsKey(pcb.asBinder())) {
@@ -6223,6 +6227,76 @@
return regId;
}
+ /**
+ * Apps with MODIFY_AUDIO_ROUTING can register any policy.
+ * Apps with an audio capable MediaProjection are allowed to register a RENDER|LOOPBACK policy
+ * as those policy do not modify the audio routing.
+ */
+ private boolean isPolicyRegisterAllowed(AudioPolicyConfig policyConfig,
+ IMediaProjection projection) {
+
+ boolean isLoopbackRenderPolicy = policyConfig.getMixes().stream().allMatch(
+ mix -> mix.getRouteFlags() == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
+
+ // Policy that do not modify the audio routing only need an audio projection
+ if (isLoopbackRenderPolicy && canProjectAudio(projection)) {
+ return true;
+ }
+
+ boolean hasPermissionModifyAudioRouting =
+ (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING));
+ if (hasPermissionModifyAudioRouting) {
+ return true;
+ }
+ return false;
+ }
+
+ /** @return true if projection is a valid MediaProjection that can project audio. */
+ private boolean canProjectAudio(IMediaProjection projection) {
+ if (projection == null) {
+ return false;
+ }
+
+ IMediaProjectionManager projectionService = getProjectionService();
+ if (projectionService == null) {
+ Log.e(TAG, "Can't get service IMediaProjectionManager");
+ return false;
+ }
+
+ try {
+ if (!projectionService.isValidMediaProjection(projection)) {
+ Log.w(TAG, "App passed invalid MediaProjection token");
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call .isValidMediaProjection() on IMediaProjectionManager"
+ + projectionService.asBinder(), e);
+ return false;
+ }
+
+ try {
+ if (!projection.canProjectAudio()) {
+ Log.w(TAG, "App passed MediaProjection that can not project audio");
+ return false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call .canProjectAudio() on valid IMediaProjection"
+ + projection.asBinder(), e);
+ return false;
+ }
+
+ return true;
+ }
+
+ private IMediaProjectionManager getProjectionService() {
+ if (mProjectionService == null) {
+ IBinder b = ServiceManager.getService(Context.MEDIA_PROJECTION_SERVICE);
+ mProjectionService = IMediaProjectionManager.Stub.asInterface(b);
+ }
+ return mProjectionService;
+ }
+
public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for "
+ pcb.asBinder()).printLog(TAG)));
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index bfa7f9d..4e4b15f 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accounts.Account;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
@@ -1174,6 +1175,7 @@
}
@Override
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public void putCache(String packageName, Uri key, Bundle value, int userId) {
Bundle.setDefusable(value, true);
enforceCrossUserPermission(userId, TAG);
@@ -1196,6 +1198,7 @@
}
@Override
+ @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
public Bundle getCache(String packageName, Uri key, int userId) {
enforceCrossUserPermission(userId, TAG);
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 6899c3f..647727f 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -62,6 +62,7 @@
private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
private final Context mContext;
@@ -162,6 +163,25 @@
}
}
+ private static void assetToSettingsGlobal(Context context, Context driverContext,
+ String fileName, String settingsGlobal, CharSequence delimiter) {
+ try {
+ final BufferedReader reader = new BufferedReader(
+ new InputStreamReader(driverContext.getAssets().open(fileName)));
+ final ArrayList<String> assetStrings = new ArrayList<>();
+ for (String assetString; (assetString = reader.readLine()) != null; ) {
+ assetStrings.add(assetString);
+ }
+ Settings.Global.putString(context.getContentResolver(),
+ settingsGlobal,
+ String.join(delimiter, assetStrings));
+ } catch (IOException e) {
+ if (DEBUG) {
+ Slog.w(TAG, "Failed to load " + fileName + ", abort.");
+ }
+ }
+ }
+
private void fetchGameDriverPackageProperties() {
final ApplicationInfo driverInfo;
try {
@@ -186,29 +206,25 @@
// Reset the whitelist.
Settings.Global.putString(mContentResolver,
Settings.Global.GAME_DRIVER_WHITELIST, "");
+ // Reset the sphal libraries
+ Settings.Global.putString(mContentResolver,
+ Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, "");
mGameDriverVersionCode = driverInfo.longVersionCode;
try {
final Context driverContext = mContext.createPackageContext(mDriverPackageName,
Context.CONTEXT_RESTRICTED);
- final BufferedReader reader = new BufferedReader(
- new InputStreamReader(driverContext.getAssets()
- .open(GAME_DRIVER_WHITELIST_FILENAME)));
- final ArrayList<String> whitelistedPackageNames = new ArrayList<>();
- for (String packageName; (packageName = reader.readLine()) != null; ) {
- whitelistedPackageNames.add(packageName);
- }
- Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_WHITELIST,
- String.join(",", whitelistedPackageNames));
+
+ assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_WHITELIST_FILENAME,
+ Settings.Global.GAME_DRIVER_WHITELIST, ",");
+
+ assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_SPHAL_LIBRARIES_FILENAME,
+ Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, ":");
+
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
Slog.w(TAG, "driver package '" + mDriverPackageName + "' not installed");
}
- } catch (IOException e) {
- if (DEBUG) {
- Slog.w(TAG, "Failed to load whitelist driver package, abort.");
- }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3557fcf..e8c402c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -594,8 +594,6 @@
mConditionProviders.migrateToXml();
handleSavePolicyFile();
}
-
- mAssistants.ensureAssistant();
}
private void loadPolicyFile() {
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 2aaa1ed..26cc0c1 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -16,6 +16,7 @@
package com.android.server.notification;
+import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -49,12 +50,12 @@
private static final String USAGE =
"usage: cmd notification SUBCMD [args]\n\n"
+ "SUBCMDs:\n"
- + " allow_listener COMPONENT [user_id]\n"
- + " disallow_listener COMPONENT [user_id]\n"
- + " allow_assistant COMPONENT\n"
- + " remove_assistant COMPONENT\n"
- + " allow_dnd PACKAGE\n"
- + " disallow_dnd PACKAGE\n"
+ + " allow_listener COMPONENT [user_id (current user if not specified)]\n"
+ + " disallow_listener COMPONENT [user_id (current user if not specified)]\n"
+ + " allow_assistant COMPONENT [user_id (current user if not specified)]\n"
+ + " remove_assistant COMPONENT [user_id (current user if not specified)]\n"
+ + " allow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ + " disallow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ " suspend_package PACKAGE\n"
+ " unsuspend_package PACKAGE\n"
+ " post [--help | flags] TAG TEXT";
@@ -109,14 +110,24 @@
try {
switch (cmd.replace('-', '_')) {
case "allow_dnd": {
- mBinderService.setNotificationPolicyAccessGranted(
- getNextArgRequired(), true);
+ String packageName = getNextArgRequired();
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
+ }
+ mBinderService.setNotificationPolicyAccessGrantedForUser(
+ packageName, userId, true);
}
break;
case "disallow_dnd": {
- mBinderService.setNotificationPolicyAccessGranted(
- getNextArgRequired(), false);
+ String packageName = getNextArgRequired();
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
+ }
+ mBinderService.setNotificationPolicyAccessGrantedForUser(
+ packageName, userId, false);
}
break;
case "allow_listener": {
@@ -125,13 +136,11 @@
pw.println("Invalid listener - must be a ComponentName");
return -1;
}
- String userId = getNextArg();
- if (userId == null) {
- mBinderService.setNotificationListenerAccessGranted(cn, true);
- } else {
- mBinderService.setNotificationListenerAccessGrantedForUser(
- cn, Integer.parseInt(userId), true);
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
}
+ mBinderService.setNotificationListenerAccessGrantedForUser(cn, userId, true);
}
break;
case "disallow_listener": {
@@ -140,13 +149,11 @@
pw.println("Invalid listener - must be a ComponentName");
return -1;
}
- String userId = getNextArg();
- if (userId == null) {
- mBinderService.setNotificationListenerAccessGranted(cn, false);
- } else {
- mBinderService.setNotificationListenerAccessGrantedForUser(
- cn, Integer.parseInt(userId), false);
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
}
+ mBinderService.setNotificationListenerAccessGrantedForUser(cn, userId, false);
}
break;
case "allow_assistant": {
@@ -155,7 +162,11 @@
pw.println("Invalid assistant - must be a ComponentName");
return -1;
}
- mBinderService.setNotificationAssistantAccessGranted(cn, true);
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
+ }
+ mBinderService.setNotificationAssistantAccessGrantedForUser(cn, userId, true);
}
break;
case "disallow_assistant": {
@@ -164,7 +175,11 @@
pw.println("Invalid assistant - must be a ComponentName");
return -1;
}
- mBinderService.setNotificationAssistantAccessGranted(cn, false);
+ int userId = ActivityManager.getCurrentUser();
+ if (peekNextArg() != null) {
+ userId = Integer.parseInt(getNextArgRequired());
+ }
+ mBinderService.setNotificationAssistantAccessGrantedForUser(cn, userId, false);
}
break;
case "suspend_package": {
@@ -176,6 +191,7 @@
// only use for testing
mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
}
+ break;
case "distract_package": {
// only use for testing
// Flag values are in
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 62c4815..9e912843 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -20,7 +20,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.AppDetailsActivity;
import android.app.AppGlobals;
import android.app.IApplicationThread;
import android.app.PendingIntent;
@@ -367,7 +366,8 @@
private ResolveInfo getHiddenAppActivityInfo(String packageName, int callingUid,
UserHandle user) {
Intent intent = new Intent();
- intent.setComponent(new ComponentName(packageName, AppDetailsActivity.class.getName()));
+ intent.setComponent(new ComponentName(packageName,
+ PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME));
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f79da28..cced0f4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -485,11 +485,12 @@
}
}
- if (params.isStaged) {
+ boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
+ if (params.isStaged || isApex) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
}
- if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ if (isApex) {
if (!mApexManager.isApexSupported()) {
throw new IllegalArgumentException(
"This device doesn't support the installation of APEX files");
@@ -823,6 +824,13 @@
}
@Override
+ public void installExistingPackage(String packageName, int installFlags, int installReason,
+ IntentSender statusReceiver, int userId) {
+ mPm.installExistingPackageAsUser(packageName, userId, installFlags, installReason,
+ statusReceiver);
+ }
+
+ @Override
public void setPermissionsResult(int sessionId, boolean accepted) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 56ef33a..65d8150d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1491,12 +1491,12 @@
// Inherit base if not overridden
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
- mResolvedInheritedFiles.add(mResolvedBaseFile);
+ resolveInheritedFile(mResolvedBaseFile);
// Inherit the dex metadata if present.
final File baseDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
if (baseDexMetadataFile != null) {
- mResolvedInheritedFiles.add(baseDexMetadataFile);
+ resolveInheritedFile(baseDexMetadataFile);
}
baseApk = existingBase;
}
@@ -1508,12 +1508,12 @@
final File splitFile = new File(existing.splitCodePaths[i]);
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
- mResolvedInheritedFiles.add(splitFile);
+ resolveInheritedFile(splitFile);
// Inherit the dex metadata if present.
final File splitDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(splitFile);
if (splitDexMetadataFile != null) {
- mResolvedInheritedFiles.add(splitDexMetadataFile);
+ resolveInheritedFile(splitDexMetadataFile);
}
}
}
@@ -1627,6 +1627,17 @@
mResolvedStagedFiles.add(stagedSignature);
}
+ private void resolveInheritedFile(File origFile) {
+ mResolvedInheritedFiles.add(origFile);
+
+ // Inherit the fsverity signature file if present.
+ final File fsveritySignatureFile = new File(
+ VerityUtils.getFsveritySignatureFilePath(origFile.getPath()));
+ if (fsveritySignatureFile.exists()) {
+ mResolvedInheritedFiles.add(fsveritySignatureFile);
+ }
+ }
+
@GuardedBy("mLock")
private void assertApkConsistentLocked(String tag, ApkLite apk)
throws PackageManagerException {
@@ -1886,7 +1897,7 @@
}
@Override
- public void addChildSessionId(int childSessionId) {
+ public void addChildSessionId(int childSessionId) throws RemoteException {
final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
if (childSession == null) {
throw new RemoteException("Unable to add child.",
@@ -1901,7 +1912,7 @@
new PackageManagerException("Child session " + childSessionId
+ " and parent session " + this.sessionId + " do not have consistent"
+ " staging session settings."),
- false, true).rethrowAsRuntimeException();
+ false, true);
}
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
@@ -2018,6 +2029,7 @@
mStagedSessionErrorMessage = errorMessage;
Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage);
}
+ cleanStageDir();
mCallback.onStagedSessionChanged(this);
}
@@ -2029,7 +2041,9 @@
mStagedSessionFailed = false;
mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR;
mStagedSessionErrorMessage = "";
+ Slog.d(TAG, "Marking session " + sessionId + " as applied");
}
+ cleanStageDir();
mCallback.onStagedSessionChanged(this);
}
@@ -2084,6 +2098,19 @@
}
}
+ private void cleanStageDir() {
+ if (isMultiPackage()) {
+ for (int childSessionId : getChildSessionIds()) {
+ mSessionProvider.getSession(childSessionId).cleanStageDir();
+ }
+ } else {
+ try {
+ mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
+ } catch (InstallerException ignored) {
+ }
+ }
+ }
+
void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
dumpLocked(pw);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 95a9359..e7e3e83 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -121,7 +121,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.AppDetailsActivity;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.IActivityManager;
@@ -630,6 +629,7 @@
final boolean mIsUpgrade;
final boolean mIsPreNUpgrade;
final boolean mIsPreNMR1Upgrade;
+ final boolean mIsPreQUpgrade;
@GuardedBy("mPackages")
private boolean mDexOptDialogShown;
@@ -1303,12 +1303,14 @@
// Recordkeeping of restore-after-install operations that are currently in flight
// between the Package Manager and the Backup Manager
static class PostInstallData {
- public InstallArgs args;
- public PackageInstalledInfo res;
+ public final InstallArgs args;
+ public final PackageInstalledInfo res;
+ public final Runnable mPostInstallRunnable;
- PostInstallData(InstallArgs _a, PackageInstalledInfo _r) {
+ PostInstallData(InstallArgs _a, PackageInstalledInfo _r, Runnable postInstallRunnable) {
args = _a;
res = _r;
+ mPostInstallRunnable = postInstallRunnable;
}
}
@@ -1440,7 +1442,9 @@
final boolean didRestore = (msg.arg2 != 0);
mRunningInstalls.delete(msg.arg1);
- if (data != null) {
+ if (data != null && data.mPostInstallRunnable != null) {
+ data.mPostInstallRunnable.run();
+ } else if (data != null) {
InstallArgs args = data.args;
PackageInstalledInfo parentRes = data.res;
@@ -2396,6 +2400,7 @@
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
+ mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
int preUpgradeSdkVersion = ver.sdkVersion;
@@ -3022,6 +3027,21 @@
ver.fingerprint = Build.FINGERPRINT;
}
+ // Grandfather existing (installed before Q) non-system apps to hide
+ // their icons in launcher.
+ if (!onlyCore && mIsPreQUpgrade) {
+ Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
+ int size = mSettings.mPackages.size();
+ for (int i = 0; i < size; i++) {
+ final PackageSetting ps = mSettings.mPackages.valueAt(i);
+ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ continue;
+ }
+ ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
+ UserHandle.USER_SYSTEM);
+ }
+ }
+
// clear only after permissions and other defaults have been updated
mExistingSystemPackages.clear();
mPromoteSystemApps = false;
@@ -12767,6 +12787,11 @@
@Override
public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
int installReason) {
+ return installExistingPackageAsUser(packageName, userId, installFlags, installReason, null);
+ }
+
+ int installExistingPackageAsUser(String packageName, int userId, int installFlags,
+ int installReason, IntentSender intentSender) {
if (DEBUG_INSTALL) {
Log.v(TAG, "installExistingPackageAsUser package=" + packageName + " userId=" + userId
+ " installFlags=" + installFlags + " installReason=" + installReason);
@@ -12846,7 +12871,11 @@
PackageInstalledInfo res =
createPackageInstalledInfo(PackageManager.INSTALL_SUCCEEDED);
res.pkg = pkgSetting.pkg;
- restoreAndPostInstall(userId, res, null);
+ res.newUsers = new int[]{ userId };
+ PostInstallData postInstallData = intentSender == null ? null :
+ new PostInstallData(null, res, () -> onRestoreComplete(res.returnCode,
+ mContext, intentSender));
+ restoreAndPostInstall(userId, res, postInstallData);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -12855,6 +12884,16 @@
return PackageManager.INSTALL_SUCCEEDED;
}
+ static void onRestoreComplete(int returnCode, Context context, IntentSender target) {
+ Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.installStatusToPublicStatus(returnCode));
+ try {
+ target.sendIntent(context, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+
static void setInstantAppForUser(PackageSetting pkgSetting, int userId,
boolean instantApp, boolean fullApp) {
// no state specified; do nothing
@@ -12951,8 +12990,14 @@
"setPackagesSuspendedAsUser");
final int callingUid = Binder.getCallingUid();
- if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
- && getPackageUid(callingPackage, 0, userId) != callingUid) {
+ final int packageUid = getPackageUid(callingPackage, 0, userId);
+ final boolean allowedCallingUid = callingUid == Process.ROOT_UID
+ || callingUid == Process.SYSTEM_UID;
+ final boolean allowedPackageUid = packageUid == callingUid;
+ final boolean allowedShell = callingUid == SHELL_UID
+ && UserHandle.isSameApp(packageUid, callingUid);
+
+ if (!allowedCallingUid && !allowedShell && !allowedPackageUid) {
throw new SecurityException("Calling package " + callingPackage + " in user "
+ userId + " does not belong to calling uid " + callingUid);
}
@@ -13811,7 +13856,7 @@
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
- new PostInstallData(request.args, request.installResult));
+ new PostInstallData(request.args, request.installResult, null));
}
});
}
@@ -17125,7 +17170,7 @@
if (!legacyMode) {
// fs-verity is optional for now. Only set up if signature is provided.
- if (new File(signaturePath).exists()) {
+ if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
try {
VerityUtils.setUpFsverity(filePath, signaturePath);
} catch (IOException | DigestException | NoSuchAlgorithmException
@@ -20191,13 +20236,9 @@
}
// Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
// app details activity
- if (AppDetailsActivity.class.getName().equals(className)) {
- if (mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- Slog.e(TAG, "Cannot disable a protected component: " + packageName);
- return;
- }
+ if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)
+ && !allowedByPermission) {
+ throw new SecurityException("Cannot disable a system-generated component");
}
synchronized (mPackages) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2eb762b..5216967 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1114,6 +1114,7 @@
int userId = UserHandle.USER_SYSTEM;
int installFlags = 0;
String opt;
+ boolean waitTillComplete = false;
while ((opt = getNextOption()) != null) {
switch (opt) {
case "--user":
@@ -1128,6 +1129,9 @@
installFlags &= ~PackageManager.INSTALL_INSTANT_APP;
installFlags |= PackageManager.INSTALL_FULL_APP;
break;
+ case "--wait":
+ waitTillComplete = true;
+ break;
default:
pw.println("Error: Unknown option: " + opt);
return 1;
@@ -1140,9 +1144,23 @@
return 1;
}
+ int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
try {
+ if (waitTillComplete) {
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ final IPackageInstaller installer = mInterface.getPackageInstaller();
+ pw.println("Installing package " + packageName + " for user: " + userId);
+ installer.installExistingPackage(packageName, installFlags, installReason,
+ receiver.getIntentSender(), userId);
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ pw.println("Received intent for package install");
+ return status == PackageInstaller.STATUS_SUCCESS ? 0 : 1;
+ }
+
final int res = mInterface.installExistingPackageAsUser(packageName, userId,
- installFlags, PackageManager.INSTALL_REASON_UNKNOWN);
+ installFlags, installReason);
if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
throw new NameNotFoundException("Package " + packageName + " doesn't exist");
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 9dfd477..a38c836 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -419,7 +419,12 @@
if (apkChildSession == null) {
return false;
}
- apkParentSession.addChildSessionId(apkChildSession.sessionId);
+ try {
+ apkParentSession.addChildSessionId(apkChildSession.sessionId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
+ return false;
+ }
}
return commitApkSession(apkParentSession, session.sessionId);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 68dab34..0759419 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -86,6 +86,9 @@
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_BEHAVIOR_LOCK;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_BEHAVIOR_NONE;
+import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_BEHAVIOR_SLEEP;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
@@ -473,8 +476,6 @@
int mLidKeyboardAccessibility;
int mLidNavigationAccessibility;
- boolean mLidControlsScreenLock;
- boolean mLidControlsSleep;
private boolean mLidControlsDisplayFold;
int mShortPressOnPowerBehavior;
int mLongPressOnPowerBehavior;
@@ -808,7 +809,7 @@
public void onWakeUp() {
synchronized (mLock) {
if (shouldEnableWakeGestureLp()) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
PowerManager.WAKE_REASON_GESTURE, "android.policy:GESTURE");
@@ -1195,6 +1196,11 @@
}
}
+ private int getLidBehavior() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.LID_BEHAVIOR, LID_BEHAVIOR_NONE);
+ }
+
private int getMaxMultiPressPowerCount() {
if (mTriplePressOnPowerBehavior != MULTI_PRESS_POWER_NOTHING) {
return 3;
@@ -1212,21 +1218,21 @@
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Global Actions");
showGlobalActionsInternal();
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Shut Off");
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Long Press - Go To Voice Assist");
final boolean keyguardActive = mKeyguardDelegate == null
? false
@@ -1249,7 +1255,7 @@
break;
case VERY_LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Power - Very Long Press - Show Global Actions");
showGlobalActionsInternal();
break;
@@ -1400,7 +1406,7 @@
@Override
public void run() {
mEndCallKeyHandled = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"End Call - Long Press - Show Global Actions");
showGlobalActionsInternal();
}
@@ -1667,7 +1673,7 @@
return;
}
mHomeConsumed = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Home - Long Press");
switch (mLongPressOnHomeBehavior) {
case LONG_PRESS_HOME_ALL_APPS:
@@ -1796,10 +1802,6 @@
com.android.internal.R.integer.config_lidKeyboardAccessibility);
mLidNavigationAccessibility = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lidNavigationAccessibility);
- mLidControlsScreenLock = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_lidControlsScreenLock);
- mLidControlsSleep = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_lidControlsSleep);
mLidControlsDisplayFold = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_lidControlsDisplayFold);
@@ -2040,7 +2042,8 @@
private boolean shouldEnableWakeGestureLp() {
return mWakeGestureEnabledSetting && !mDefaultDisplayPolicy.isAwake()
- && (!mLidControlsSleep || mDefaultDisplayPolicy.getLidState() != LID_CLOSED)
+ && (getLidBehavior() != LID_BEHAVIOR_SLEEP
+ || mDefaultDisplayPolicy.getLidState() != LID_CLOSED)
&& mWakeGestureListener.isSupported();
}
@@ -3277,7 +3280,7 @@
}
private void launchAssistLongPressAction() {
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false,
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false,
"Assist - Long Press");
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
@@ -3546,7 +3549,7 @@
if (lidOpen) {
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch,
PowerManager.WAKE_REASON_LID, "android.policy:LID");
- } else if (!mLidControlsSleep) {
+ } else if (getLidBehavior() != LID_BEHAVIOR_SLEEP) {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}
@@ -4039,7 +4042,7 @@
}
if (useHapticFeedback) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Virtual Key - Press");
}
@@ -4760,7 +4763,7 @@
public void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
if (safeMode) {
- performHapticFeedbackLw(null, HapticFeedbackConstants.SAFE_MODE_ENABLED, true,
+ performHapticFeedback(HapticFeedbackConstants.SAFE_MODE_ENABLED, true,
"Safe Mode Enabled");
}
}
@@ -5041,11 +5044,22 @@
final int lidState = mDefaultDisplayPolicy.getLidState();
if (mLidControlsDisplayFold && mDisplayFoldController != null) {
mDisplayFoldController.requestDeviceFolded(lidState == LID_CLOSED);
- } else if (lidState == LID_CLOSED && mLidControlsSleep) {
- goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
- PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
- } else if (lidState == LID_CLOSED && mLidControlsScreenLock) {
- mWindowManagerFuncs.lockDeviceNow();
+ } else if (lidState == LID_CLOSED) {
+ int lidBehavior = getLidBehavior();
+ switch (lidBehavior) {
+ case LID_BEHAVIOR_LOCK:
+ mWindowManagerFuncs.lockDeviceNow();
+ break;
+ case LID_BEHAVIOR_SLEEP:
+ goToSleep(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
+ PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ break;
+ case LID_BEHAVIOR_NONE:
+ // fall through
+ default:
+ break;
+ }
}
synchronized (mLock) {
@@ -5237,9 +5251,14 @@
Settings.Global.THEATER_MODE_ON, 0) == 1;
}
+ private boolean performHapticFeedback(int effectId, boolean always, String reason) {
+ return performHapticFeedback(Process.myUid(), mContext.getOpPackageName(),
+ effectId, always, reason);
+ }
+
@Override
- public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always,
- String reason) {
+ public boolean performHapticFeedback(int uid, String packageName, int effectId,
+ boolean always, String reason) {
if (!mVibrator.hasVibrator()) {
return false;
}
@@ -5254,16 +5273,7 @@
return false;
}
- int owningUid;
- String owningPackage;
- if (win != null) {
- owningUid = win.getOwningUid();
- owningPackage = win.getOwningPackage();
- } else {
- owningUid = android.os.Process.myUid();
- owningPackage = mContext.getOpPackageName();
- }
- mVibrator.vibrate(owningUid, owningPackage, effect, reason, VIBRATION_ATTRIBUTES);
+ mVibrator.vibrate(uid, packageName, effect, reason, VIBRATION_ATTRIBUTES);
return true;
}
@@ -5405,8 +5415,7 @@
pw.print(prefix); pw.print("mLidKeyboardAccessibility=");
pw.print(mLidKeyboardAccessibility);
pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility);
- pw.print(" mLidControlsScreenLock="); pw.println(mLidControlsScreenLock);
- pw.print(prefix); pw.print("mLidControlsSleep="); pw.println(mLidControlsSleep);
+ pw.print(" getLidBehavior="); pw.println(lidBehaviorToString(getLidBehavior()));
pw.print(prefix);
pw.print("mLongPressOnBackBehavior=");
pw.println(longPressOnBackBehaviorToString(mLongPressOnBackBehavior));
@@ -5640,6 +5649,19 @@
}
}
+ private static String lidBehaviorToString(int behavior) {
+ switch (behavior) {
+ case LID_BEHAVIOR_LOCK:
+ return "LID_BEHAVIOR_LOCK";
+ case LID_BEHAVIOR_SLEEP:
+ return "LID_BEHAVIOR_SLEEP";
+ case LID_BEHAVIOR_NONE:
+ return "LID_BEHAVIOR_NONE";
+ default:
+ return Integer.toString(behavior);
+ }
+ }
+
@Override
public boolean setAodShowing(boolean aodShowing) {
if (mAodShowing != aodShowing) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d7e4b6c..5cd0014 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -518,6 +518,10 @@
public static final int LID_CLOSED = 0;
public static final int LID_OPEN = 1;
+ public static final int LID_BEHAVIOR_NONE = 0;
+ public static final int LID_BEHAVIOR_SLEEP = 1;
+ public static final int LID_BEHAVIOR_LOCK = 2;
+
public static final int CAMERA_LENS_COVER_ABSENT = -1;
public static final int CAMERA_LENS_UNCOVERED = 0;
public static final int CAMERA_LENS_COVERED = 1;
@@ -1300,8 +1304,8 @@
/**
* Call from application to perform haptic feedback on its window.
*/
- public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always,
- String reason);
+ public boolean performHapticFeedback(int uid, String packageName, int effectId,
+ boolean always, String reason);
/**
* Called when we have started keeping the screen on because a window
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index c14f126..11839a5 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -966,36 +966,45 @@
}
getHandler().post(() -> {
- final RollbackData rollbackData = getRollbackForPackage(packageName);
- for (int userId : userIds) {
- if (rollbackData == null || !rollbackData.inProgress) {
- Log.e(TAG, "Request to restore userData for: " + packageName
- + ", but no rollback in progress.");
- continue;
- }
- final PackageRollbackInfo info = getPackageRollbackInfo(rollbackData, packageName);
- final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
- rollbackData.rollbackId, info, userId, appId, seInfo);
-
- // We've updated metadata about this rollback, so save it to flash.
- if (changedRollbackData) {
- try {
- mRollbackStore.saveAvailableRollback(rollbackData);
- } catch (IOException ioe) {
- // TODO(narayan): What is the right thing to do here ? This isn't a fatal
- // error, since it will only result in us trying to restore data again,
- // which will be a no-op if there's no data available.
- Log.e(TAG, "Unable to save available rollback: " + packageName, ioe);
- }
- }
- }
-
+ restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
final PackageManagerInternal pmi = LocalServices.getService(
PackageManagerInternal.class);
pmi.finishPackageInstall(token, false);
});
}
+ private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
+ long ceDataInode, String seInfo, int token) {
+ final RollbackData rollbackData = getRollbackForPackage(packageName);
+ if (rollbackData == null) {
+ return;
+ }
+
+ if (!rollbackData.inProgress) {
+ Log.e(TAG, "Request to restore userData for: " + packageName
+ + ", but no rollback in progress.");
+ return;
+ }
+
+ for (int userId : userIds) {
+ final PackageRollbackInfo info = getPackageRollbackInfo(rollbackData, packageName);
+ final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
+ rollbackData.rollbackId, info, userId, appId, seInfo);
+
+ // We've updated metadata about this rollback, so save it to flash.
+ if (changedRollbackData) {
+ try {
+ mRollbackStore.saveAvailableRollback(rollbackData);
+ } catch (IOException ioe) {
+ // TODO(narayan): What is the right thing to do here ? This isn't a fatal
+ // error, since it will only result in us trying to restore data again,
+ // which will be a no-op if there's no data available.
+ Log.e(TAG, "Unable to save available rollback: " + packageName, ioe);
+ }
+ }
+ }
+ }
+
@Override
public boolean notifyStagedSession(int sessionId) {
final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 543f196..34a4802 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -21,6 +21,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.IntDef;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.ContentResolver;
@@ -49,6 +50,8 @@
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Defines the mapping between orientation and rotation of a display.
@@ -96,11 +99,36 @@
private int mUserRotation = Surface.ROTATION_0;
/**
+ * Flag that indicates this is a display that may run better when fixed to user rotation.
+ */
+ private boolean mDefaultFixedToUserRotation;
+
+ /**
+ * No overridden behavior is provided in terms of fixing rotation to user rotation. Use other
+ * flags to derive the default behavior, such as {@link WindowManagerService#mIsPc} and
+ * {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
+ */
+ static final int FIXED_TO_USER_ROTATION_DEFAULT = 0;
+ /**
+ * Don't fix display rotation to {@link #mUserRotation} only. Always allow other factors to play
+ * a role in deciding display rotation.
+ */
+ static final int FIXED_TO_USER_ROTATION_DISABLED = 1;
+ /**
+ * Only use {@link #mUserRotation} as the display rotation.
+ */
+ static final int FIXED_TO_USER_ROTATION_ENABLED = 2;
+ @IntDef({ FIXED_TO_USER_ROTATION_DEFAULT, FIXED_TO_USER_ROTATION_DISABLED,
+ FIXED_TO_USER_ROTATION_ENABLED })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface FixedToUserRotation {}
+
+ /**
* A flag to indicate if the display rotation should be fixed to user specified rotation
* regardless of all other states (including app requrested orientation). {@code true} the
* display rotation should be fixed to user specified rotation, {@code false} otherwise.
*/
- private boolean mFixedToUserRotation;
+ private int mFixedToUserRotation = FIXED_TO_USER_ROTATION_DEFAULT;
private int mDemoHdmiRotation;
private int mDemoRotation;
@@ -208,31 +236,23 @@
}
mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false);
- // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
- // http://developer.android.com/guide/practices/screens_support.html#range
- // For car, ignore the dp limitation. It's physically impossible to rotate the car's screen
- // so if the orientation is forced, we need to respect that no matter what.
+ // It's physically impossible to rotate the car's screen.
final boolean isCar = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_AUTOMOTIVE);
- // For TV, it's usually 960dp x 540dp, ignore the size limitation.
- // so if the orientation is forced, we need to respect that no matter what.
+ // It's also not likely to rotate a TV screen.
final boolean isTv = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
+ // Not much of use to rotate the display since it's close to square.
final boolean isCloseToSquare =
isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
- final boolean forceDefaultOrientationInRes =
- res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation);
- final boolean forceDefaultOrienation =
- ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv || isCloseToSquare)
- && forceDefaultOrientationInRes
- // For debug purposes the next line turns this feature off with:
- // $ adb shell setprop config.override_forced_orient true
- // $ adb shell wm size reset
- && !"true".equals(SystemProperties.get("config.override_forced_orient"));
- // Configuration says we force to use the default orientation. We can fall back to fix
- // rotation to only user rotation. As long as OEM doesn't change user rotation then the
- // rotation of this display is effectively stuck at 0 deg.
- setFixedToUserRotation(forceDefaultOrienation);
+ final boolean forceDesktopMode =
+ mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
+ mDefaultFixedToUserRotation =
+ (isCar || isTv || mService.mIsPc || forceDesktopMode || isCloseToSquare)
+ // For debug purposes the next line turns this feature off with:
+ // $ adb shell setprop config.override_forced_orient true
+ // $ adb shell wm size reset
+ && !"true".equals(SystemProperties.get("config.override_forced_orient"));
}
private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
@@ -263,7 +283,7 @@
}
void restoreSettings(int userRotationMode, int userRotation,
- boolean fixedToUserRotation) {
+ @FixedToUserRotation int fixedToUserRotation) {
mFixedToUserRotation = fixedToUserRotation;
// We will retrieve user rotation and user rotation mode from settings for default display.
@@ -285,14 +305,13 @@
mUserRotation = userRotation;
}
- void setFixedToUserRotation(boolean fixedToUserRotation) {
+ void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
if (mFixedToUserRotation == fixedToUserRotation) {
return;
}
mFixedToUserRotation = fixedToUserRotation;
- mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent,
- fixedToUserRotation);
+ mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
mService.updateRotation(true /* alwaysSendConfiguration */,
false /* forceRelayout */);
}
@@ -346,7 +365,14 @@
}
boolean isFixedToUserRotation() {
- return mFixedToUserRotation;
+ switch (mFixedToUserRotation) {
+ case FIXED_TO_USER_ROTATION_DISABLED:
+ return false;
+ case FIXED_TO_USER_ROTATION_ENABLED:
+ return true;
+ default:
+ return mDefaultFixedToUserRotation;
+ }
}
/**
@@ -355,7 +381,7 @@
* false} is when {@link #isFixedToUserRotation()} is {@code true}.
*/
boolean respectAppRequestedOrientation() {
- return !mFixedToUserRotation;
+ return !isFixedToUserRotation();
}
public int getLandscapeRotation() {
@@ -461,7 +487,7 @@
* screen is switched off.
*/
private boolean needSensorRunning() {
- if (mFixedToUserRotation) {
+ if (isFixedToUserRotation()) {
// We are sure we only respect user rotation settings, so we are sure we will not
// support sensor rotation.
return false;
@@ -527,7 +553,7 @@
);
}
- if (mFixedToUserRotation) {
+ if (isFixedToUserRotation()) {
return mUserRotation;
}
@@ -739,7 +765,7 @@
// demo, hdmi, vr, etc mode.
// Determine if the rotation is currently forced.
- if (mFixedToUserRotation) {
+ if (isFixedToUserRotation()) {
return false; // Rotation is forced to user settings.
}
@@ -899,7 +925,7 @@
pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
- pw.println(prefix + " mFixedToUserRotation=" + mFixedToUserRotation);
+ pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
}
private class OrientationListener extends WindowOrientationListener {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 5cfa7de..4617890 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -22,6 +22,7 @@
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -80,7 +81,8 @@
private boolean mShouldShowWithInsecureKeyguard = false;
private boolean mShouldShowSystemDecors = false;
private boolean mShouldShowIme = false;
- private boolean mFixedToUserRotation;
+ private @DisplayRotation.FixedToUserRotation int mFixedToUserRotation =
+ FIXED_TO_USER_ROTATION_DEFAULT;
private Entry(String name) {
mName = name;
@@ -99,7 +101,7 @@
&& !mShouldShowWithInsecureKeyguard
&& !mShouldShowSystemDecors
&& !mShouldShowIme
- && !mFixedToUserRotation;
+ && mFixedToUserRotation == FIXED_TO_USER_ROTATION_DEFAULT;
}
}
@@ -188,7 +190,8 @@
writeSettingsIfNeeded(entry, displayInfo);
}
- void setFixedToUserRotation(DisplayContent displayContent, boolean fixedToUserRotation) {
+ void setFixedToUserRotation(DisplayContent displayContent,
+ @DisplayRotation.FixedToUserRotation int fixedToUserRotation) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final Entry entry = getOrCreateEntry(displayInfo);
entry.mFixedToUserRotation = fixedToUserRotation;
@@ -464,8 +467,7 @@
"shouldShowWithInsecureKeyguard");
entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
- entry.mFixedToUserRotation = getBooleanAttribute(parser,
- "fixedToUserRotation");
+ entry.mFixedToUserRotation = getIntAttribute(parser, "fixedToUserRotation");
mEntries.put(name, entry);
}
XmlUtils.skipCurrentTag(parser);
@@ -549,9 +551,9 @@
if (entry.mShouldShowIme) {
out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
}
- if (entry.mFixedToUserRotation) {
+ if (entry.mFixedToUserRotation != FIXED_TO_USER_ROTATION_DEFAULT) {
out.attribute(null, "fixedToUserRotation",
- Boolean.toString(entry.mFixedToUserRotation));
+ Integer.toString(entry.mFixedToUserRotation));
}
out.endTag(null, "display");
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 58cf73a..dc8c7b7 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -245,17 +245,13 @@
}
@Override
- public boolean performHapticFeedback(IWindow window, int effectId,
- boolean always) {
- synchronized (mService.mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
- try {
- return mService.mPolicy.performHapticFeedbackLw(
- mService.windowForClientLocked(this, window, true),
+ public boolean performHapticFeedback(int effectId, boolean always) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mService.mPolicy.performHapticFeedback(mUid, mPackageName,
effectId, always, null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index d4430da4..e19c7c6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -209,6 +209,7 @@
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.InputDevice;
+import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InsetsState;
import android.view.KeyEvent;
@@ -3519,14 +3520,15 @@
}
}
- void setRotateForApp(int displayId, boolean enabled) {
+ void setRotateForApp(int displayId,
+ @DisplayRotation.FixedToUserRotation int fixedToUserRotation) {
synchronized (mGlobalLock) {
final DisplayContent display = mRoot.getDisplayContent(displayId);
if (display == null) {
Slog.w(TAG, "Trying to set rotate for app for a missing display.");
return;
}
- display.getDisplayRotation().setFixedToUserRotation(enabled);
+ display.getDisplayRotation().setFixedToUserRotation(fixedToUserRotation);
}
}
@@ -7419,4 +7421,16 @@
}
}
}
+
+ @Override
+ public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
+ synchronized (mGlobalLock) {
+ mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+ new SurfaceControl.Transaction()
+ .syncInputWindows()
+ .apply(true);
+ }
+
+ return mInputManager.injectInputEvent(ev, mode);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index d13ee45..7384bb7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -342,21 +342,24 @@
arg = getNextArgRequired();
}
- final boolean enabled;
+ final @DisplayRotation.FixedToUserRotation int fixedToUserRotation;
switch (arg) {
case "enabled":
- enabled = true;
+ fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
break;
case "disabled":
- enabled = false;
+ fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
+ break;
+ case "default":
+ fixedToUserRotation = DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
break;
default:
- getErrPrintWriter().println("Error: expecting enabled or disabled, but we get "
- + arg);
+ getErrPrintWriter().println("Error: expecting enabled, disabled or default, but we "
+ + "get " + arg);
return -1;
}
- mInternal.setRotateForApp(displayId, enabled);
+ mInternal.setRotateForApp(displayId, fixedToUserRotation);
return 0;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 2ee58fe..cc791787 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -85,6 +85,12 @@
return mDeferDepth > 0;
}
+ void performSurfacePlacementIfScheduled() {
+ if (mTraversalScheduled) {
+ performSurfacePlacement();
+ }
+ }
+
final void performSurfacePlacement() {
performSurfacePlacement(false /* force */);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index cc62138..31788ae 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -99,7 +99,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
-import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationStats;
@@ -2519,7 +2518,7 @@
verify(mListeners, times(1)).migrateToXml();
verify(mConditionProviders, times(1)).migrateToXml();
verify(mAssistants, times(1)).migrateToXml();
- verify(mAssistants, times(2)).ensureAssistant();
+ verify(mAssistants, never()).ensureAssistant();
}
@Test
@@ -2539,7 +2538,7 @@
verify(mListeners, times(2)).migrateToXml();
verify(mConditionProviders, times(2)).migrateToXml();
verify(mAssistants, times(2)).migrateToXml();
- verify(mAssistants, times(2)).ensureAssistant();
+ verify(mAssistants, never()).ensureAssistant();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index b1b8e8c..69f7ced 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -621,7 +621,8 @@
@Test
public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
final DisplayContent dc = createNewDisplay();
- dc.getDisplayRotation().setFixedToUserRotation(true);
+ dc.getDisplayRotation().setFixedToUserRotation(
+ DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
? SCREEN_ORIENTATION_PORTRAIT
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 8733674..1c10ffb0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -31,6 +32,9 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -160,9 +164,7 @@
@Test
public void testPersistsUserRotation_LockRotation_NonDefaultDisplay() throws Exception {
- mBuilder.mIsDefaultDisplay = false;
-
- mBuilder.build();
+ mBuilder.setIsDefaultDisplay(false).build();
freezeRotation(Surface.ROTATION_180);
@@ -187,9 +189,7 @@
@Test
public void testPersistsUserRotation_UnlockRotation_NonDefaultDisplay() throws Exception {
- mBuilder.mIsDefaultDisplay = false;
-
- mBuilder.build();
+ mBuilder.setIsDefaultDisplay(false).build();
thawRotation();
@@ -203,14 +203,22 @@
public void testPersistsFixedToUserRotation() throws Exception {
mBuilder.build();
- mTarget.setFixedToUserRotation(true);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
- verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, true);
+ verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
+ FIXED_TO_USER_ROTATION_ENABLED);
reset(mMockDisplayWindowSettings);
- mTarget.setFixedToUserRotation(false);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DISABLED);
- verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, false);
+ verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
+ FIXED_TO_USER_ROTATION_DISABLED);
+
+ reset(mMockDisplayWindowSettings);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DEFAULT);
+
+ verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
+ FIXED_TO_USER_ROTATION_DEFAULT);
}
// ========================================
@@ -355,22 +363,7 @@
when(mMockDisplayPolicy.isAwake()).thenReturn(true);
when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
- mTarget.setFixedToUserRotation(true);
- mTarget.updateOrientationListener();
- verifyOrientationListenerRegistration(0);
- }
-
- @Test
- public void testNotEnablesSensor_ForceDefaultRotation() throws Exception {
- mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
- configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
-
- when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
- when(mMockDisplayPolicy.isAwake()).thenReturn(true);
- when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
- when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
mTarget.updateOrientationListener();
verifyOrientationListenerRegistration(0);
}
@@ -378,8 +371,6 @@
@Test
public void testNotEnablesSensor_ForceDefaultRotation_Car() throws Exception {
mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false);
when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
@@ -393,8 +384,6 @@
@Test
public void testNotEnablesSensor_ForceDefaultRotation_Tv() throws Exception {
mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true);
when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
@@ -405,6 +394,19 @@
verifyOrientationListenerRegistration(0);
}
+ @Test
+ public void testNotEnablesSensor_ForceDefaultRotation_Squared() throws Exception {
+ mBuilder.build();
+ configureDisplayRotation(SCREEN_ORIENTATION_LOCKED, false, false);
+
+ when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
+ when(mMockDisplayPolicy.isAwake()).thenReturn(true);
+ when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
+ when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
+ mTarget.updateOrientationListener();
+ verifyOrientationListenerRegistration(0);
+ }
+
private void enableOrientationSensor() {
when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
when(mMockDisplayPolicy.isAwake()).thenReturn(true);
@@ -513,21 +515,8 @@
// Tests for Policy based Rotation
// =================================
@Test
- public void testReturnsUserRotation_ForceDefaultRotation() throws Exception {
- mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
- configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
-
- assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
- Surface.ROTATION_180));
- }
-
- @Test
public void testReturnsUserRotation_ForceDefaultRotation_Car() throws Exception {
mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false);
assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
@@ -537,8 +526,6 @@
@Test
public void testReturnsUserRotation_ForceDefaultRotation_Tv() throws Exception {
mBuilder.build();
- when(mMockRes.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation))
- .thenReturn(true);
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true);
assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
@@ -546,6 +533,15 @@
}
@Test
+ public void testReturnsUserRotation_ForceDefaultRotation_Squared() throws Exception {
+ mBuilder.build();
+ configureDisplayRotation(SCREEN_ORIENTATION_LOCKED, false, false);
+
+ assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
+ Surface.ROTATION_180));
+ }
+
+ @Test
public void testReturnsLidOpenRotation_LidOpen() throws Exception {
mBuilder.setLidOpenRotation(Surface.ROTATION_90).build();
configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
@@ -591,7 +587,7 @@
mBuilder.build();
configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
- mTarget.setFixedToUserRotation(true);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
freezeRotation(Surface.ROTATION_180);
@@ -625,7 +621,7 @@
@Test
public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
mBuilder.build();
- mTarget.setFixedToUserRotation(true);
+ mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
assertFalse("Display rotation shouldn't respect app requested orientation if"
+ " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
@@ -647,9 +643,14 @@
width = 1080;
height = 1920;
break;
+ case SCREEN_ORIENTATION_LOCKED:
+ // We use locked for squared display.
+ width = 1080;
+ height = 1080;
+ break;
default:
- throw new IllegalArgumentException("displayOrientation needs to be either landscape"
- + " or portrait, but we got "
+ throw new IllegalArgumentException("displayOrientation needs to be landscape, "
+ + "portrait or locked, but we got "
+ ActivityInfo.screenOrientationToString(displayOrientation));
}
@@ -659,6 +660,10 @@
.thenReturn(isCar);
when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
.thenReturn(isTv);
+ when(mMockDisplayPolicy.getNonDecorDisplayWidth(anyInt(), anyInt(), anyInt(), anyInt(),
+ any())).thenReturn(width);
+ when(mMockDisplayPolicy.getNonDecorDisplayHeight(anyInt(), anyInt(), anyInt(), anyInt(),
+ any())).thenReturn(height);
final int shortSizeDp = (isCar || isTv) ? 540 : 720;
final int longSizeDp = 960;
@@ -826,6 +831,9 @@
.thenReturn(convertRotationToDegrees(mDeskDockRotation));
when(mMockRes.getInteger(com.android.internal.R.integer.config_undockedHdmiRotation))
.thenReturn(convertRotationToDegrees(mUndockedHdmiRotation));
+ when(mMockRes.getFloat(
+ com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio))
+ .thenReturn(1.33f);
mMockSensorManager = mock(SensorManager.class);
when(mMockContext.getSystemService(Context.SENSOR_SERVICE))
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 992d017..2dad187 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -26,6 +26,9 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED;
+import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -407,7 +410,7 @@
}
@Test
- public void testNotFixedToUserRotationByDefault() {
+ public void testFixedToUserRotationDefault() {
mTarget.setUserRotation(mPrimaryDisplay, WindowManagerPolicy.USER_ROTATION_LOCKED,
Surface.ROTATION_0);
@@ -419,13 +422,14 @@
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
- verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(false));
+ verify(displayRotation).restoreSettings(anyInt(), anyInt(),
+ eq(FIXED_TO_USER_ROTATION_DEFAULT));
mockitoSession.finishMocking();
}
@Test
- public void testSetFixedToUserRotation() {
- mTarget.setFixedToUserRotation(mPrimaryDisplay, true);
+ public void testSetFixedToUserRotationDisabled() {
+ mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_DISABLED);
final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
.startMocking();
@@ -435,7 +439,25 @@
applySettingsToDisplayByNewInstance(mPrimaryDisplay);
- verify(displayRotation).restoreSettings(anyInt(), anyInt(), eq(true));
+ verify(displayRotation).restoreSettings(anyInt(), anyInt(),
+ eq(FIXED_TO_USER_ROTATION_DISABLED));
+ mockitoSession.finishMocking();
+ }
+
+ @Test
+ public void testSetFixedToUserRotationEnabled() {
+ mTarget.setFixedToUserRotation(mPrimaryDisplay, FIXED_TO_USER_ROTATION_ENABLED);
+
+ final MockitoSession mockitoSession = ExtendedMockito.mockitoSession()
+ .startMocking();
+ final DisplayRotation displayRotation = mock(DisplayRotation.class);
+ spyOn(mPrimaryDisplay);
+ doReturn(displayRotation).when(mPrimaryDisplay).getDisplayRotation();
+
+ applySettingsToDisplayByNewInstance(mPrimaryDisplay);
+
+ verify(displayRotation).restoreSettings(anyInt(), anyInt(),
+ eq(FIXED_TO_USER_ROTATION_ENABLED));
mockitoSession.finishMocking();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 849772a..c3561f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -313,8 +313,8 @@
}
@Override
- public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always,
- String reason) {
+ public boolean performHapticFeedback(int uid, String packageName, int effectId,
+ boolean always, String reason) {
return false;
}
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index 87834fd..cde7f60 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -45,13 +45,13 @@
* {@link CallIdentification} for a screened call.
*/
public static class Builder {
- private String mName;
- private String mDescription;
- private String mDetails;
+ private CharSequence mName;
+ private CharSequence mDescription;
+ private CharSequence mDetails;
private Icon mPhoto;
private int mNuisanceConfidence = CallIdentification.CONFIDENCE_UNKNOWN;
private String mPackageName;
- private String mAppName;
+ private CharSequence mAppName;
/**
* Default builder constructor.
@@ -67,7 +67,7 @@
* @param callIdAppName The app name.
* @hide
*/
- public Builder(String callIdPackageName, String callIdAppName) {
+ public Builder(String callIdPackageName, CharSequence callIdAppName) {
mPackageName = callIdPackageName;
mAppName = callIdAppName;
}
@@ -80,7 +80,7 @@
* @param name The name associated with the call, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setName(@Nullable String name) {
+ public Builder setName(@Nullable CharSequence name) {
mName = name;
return this;
}
@@ -97,7 +97,7 @@
* @param description The call description, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setDescription(@Nullable String description) {
+ public Builder setDescription(@Nullable CharSequence description) {
mDescription = description;
return this;
}
@@ -114,7 +114,7 @@
* @param details The call details, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setDetails(@Nullable String details) {
+ public Builder setDetails(@Nullable CharSequence details) {
mDetails = details;
return this;
}
@@ -241,10 +241,10 @@
* call identification.
* @hide
*/
- private CallIdentification(@Nullable String name, @Nullable String description,
- @Nullable String details, @Nullable Icon photo,
+ private CallIdentification(@Nullable CharSequence name, @Nullable CharSequence description,
+ @Nullable CharSequence details, @Nullable Icon photo,
@NuisanceConfidence int nuisanceConfidence, @NonNull String callScreeningPackageName,
- @NonNull String callScreeningAppName) {
+ @NonNull CharSequence callScreeningAppName) {
mName = name;
mDescription = description;
mDetails = details;
@@ -254,13 +254,13 @@
mCallScreeningPackageName = callScreeningPackageName;
}
- private String mName;
- private String mDescription;
- private String mDetails;
+ private CharSequence mName;
+ private CharSequence mDescription;
+ private CharSequence mDetails;
private Icon mPhoto;
private int mNuisanceConfidence;
private String mCallScreeningPackageName;
- private String mCallScreeningAppName;
+ private CharSequence mCallScreeningAppName;
@Override
public int describeContents() {
@@ -269,13 +269,13 @@
@Override
public void writeToParcel(Parcel parcel, int i) {
- parcel.writeString(mName);
- parcel.writeString(mDescription);
- parcel.writeString(mDetails);
+ parcel.writeCharSequence(mName);
+ parcel.writeCharSequence(mDescription);
+ parcel.writeCharSequence(mDetails);
parcel.writeParcelable(mPhoto, 0);
parcel.writeInt(mNuisanceConfidence);
parcel.writeString(mCallScreeningPackageName);
- parcel.writeString(mCallScreeningAppName);
+ parcel.writeCharSequence(mCallScreeningAppName);
}
/**
@@ -286,13 +286,13 @@
@Override
public CallIdentification createFromParcel(Parcel source) {
- String name = source.readString();
- String description = source.readString();
- String details = source.readString();
+ CharSequence name = source.readCharSequence();
+ CharSequence description = source.readCharSequence();
+ CharSequence details = source.readCharSequence();
Icon photo = source.readParcelable(ClassLoader.getSystemClassLoader());
int nuisanceConfidence = source.readInt();
String callScreeningPackageName = source.readString();
- String callScreeningAppName = source.readString();
+ CharSequence callScreeningAppName = source.readCharSequence();
return new CallIdentification(name, description, details, photo,
nuisanceConfidence, callScreeningPackageName, callScreeningAppName);
}
@@ -311,7 +311,7 @@
*
* @return The name associated with the number, or {@code null} if none was provided.
*/
- public final @Nullable String getName() {
+ public final @Nullable CharSequence getName() {
return mName;
}
@@ -325,7 +325,7 @@
*
* @return The call description, or {@code null} if none was provided.
*/
- public final @Nullable String getDescription() {
+ public final @Nullable CharSequence getDescription() {
return mDescription;
}
@@ -340,7 +340,7 @@
*
* @return The call details, or {@code null} if none was provided.
*/
- public final @Nullable String getDetails() {
+ public final @Nullable CharSequence getDetails() {
return mDetails;
}
@@ -363,8 +363,7 @@
*
* @return The nuisance confidence.
*/
- public final @NuisanceConfidence
- int getNuisanceConfidence() {
+ public final @NuisanceConfidence int getNuisanceConfidence() {
return mNuisanceConfidence;
}
@@ -387,7 +386,7 @@
*
* @return The name of the app.
*/
- public final @NonNull String getCallScreeningAppName() {
+ public final @NonNull CharSequence getCallScreeningAppName() {
return mCallScreeningAppName;
}
@@ -407,7 +406,7 @@
* @param callScreeningAppName The app name.
* @hide
*/
- public void setCallScreeningAppName(@NonNull String callScreeningAppName) {
+ public void setCallScreeningAppName(@NonNull CharSequence callScreeningAppName) {
mCallScreeningAppName = callScreeningAppName;
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a10fb4e..ed524f6 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -154,6 +154,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.net.VpnConfig;
import com.android.internal.util.ArrayUtils;
@@ -748,6 +749,10 @@
// mExpectations is non-empty.
private boolean mExpectingAdditions;
+ // Used to collect the networks requests managed by this factory. This is a duplicate of
+ // the internal information stored in the NetworkFactory (which is private).
+ private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
+
public MockNetworkFactory(Looper looper, Context context, String logTag,
NetworkCapabilities filter) {
super(looper, context, logTag, filter);
@@ -800,6 +805,7 @@
}
// Add the request.
+ mNetworkRequests.put(request.requestId, request);
super.handleAddRequest(request, score, factorySerialNumber);
mExpectations.notify();
}
@@ -817,11 +823,17 @@
}
// Remove the request.
+ mNetworkRequests.remove(request.requestId);
super.handleRemoveRequest(request);
mExpectations.notify();
}
}
+ // Trigger releasing the request as unfulfillable
+ public void triggerUnfulfillable(NetworkRequest r) {
+ super.releaseRequestAsUnfulfillableByAnyFactory(r);
+ }
+
private void assertNoExpectations() {
if (mExpectations.size() != 0) {
fail("Can't add expectation, " + mExpectations.size() + " already pending");
@@ -861,9 +873,11 @@
assertEquals(msg, 0, count);
}
- public void waitForNetworkRequests(final int count) throws InterruptedException {
+ public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
+ throws InterruptedException {
waitForRequests();
assertEquals(count, getMyRequestCount());
+ return mNetworkRequests;
}
}
@@ -3533,6 +3547,55 @@
networkCallback.assertNoCallback();
}
+ /**
+ * Validate the callback flow for a factory releasing a request as unfulfillable.
+ */
+ @Test
+ public void testUnfulfillableNetworkRequest() throws Exception {
+ NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+
+ final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
+ handlerThread.start();
+ NetworkCapabilities filter = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET);
+ final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter);
+ testFactory.setScoreFilter(40);
+
+ // Register the factory and expect it to receive the default request.
+ testFactory.expectAddRequestsWithScores(0);
+ testFactory.register();
+ SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
+
+ assertEquals(1, requests.size()); // have 1 request at this point
+ int origRequestId = requests.valueAt(0).requestId;
+
+ // Now file the test request and expect it.
+ testFactory.expectAddRequestsWithScores(0);
+ mCm.requestNetwork(nr, networkCallback);
+ requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
+
+ int newRequestId = 0;
+ for (int i = 0; i < requests.size(); ++i) {
+ if (requests.valueAt(i).requestId != origRequestId) {
+ newRequestId = requests.valueAt(i).requestId;
+ break;
+ }
+ }
+
+ // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
+ testFactory.expectRemoveRequests(1);
+ testFactory.triggerUnfulfillable(requests.get(newRequestId));
+ networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ testFactory.waitForRequests();
+
+ testFactory.unregister();
+ handlerThread.quit();
+ }
+
private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index af9fdfb..089b59a 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -137,6 +137,16 @@
private boolean mOsuAp;
/**
+ * Fully qualified domain name of a Passpoint configuration
+ */
+ private String mFqdn;
+
+ /**
+ * Name of Passpoint credential provider
+ */
+ private String mProviderFriendlyName;
+
+ /**
* If connected to a network suggestion or specifier, store the package name of the app,
* else null.
*/
@@ -223,6 +233,8 @@
setEphemeral(false);
setOsuAp(false);
setNetworkSuggestionOrSpecifierPackageName(null);
+ setFQDN(null);
+ setProviderFriendlyName(null);
txBad = 0;
txSuccess = 0;
rxSuccess = 0;
@@ -257,6 +269,8 @@
mNetworkSuggestionOrSpecifierPackageName =
source.mNetworkSuggestionOrSpecifierPackageName;
mOsuAp = source.mOsuAp;
+ mFqdn = source.mFqdn;
+ mProviderFriendlyName = source.mProviderFriendlyName;
txBad = source.txBad;
txRetries = source.txRetries;
txSuccess = source.txSuccess;
@@ -504,6 +518,34 @@
}
/** {@hide} */
+ @SystemApi
+ public boolean isPasspointAp() {
+ return mFqdn != null && mProviderFriendlyName != null;
+ }
+
+ /** {@hide} */
+ public void setFQDN(@Nullable String fqdn) {
+ mFqdn = fqdn;
+ }
+
+ /** {@hide} */
+ @SystemApi
+ public @Nullable String getFqdn() {
+ return mFqdn;
+ }
+
+ /** {@hide} */
+ public void setProviderFriendlyName(@Nullable String providerFriendlyName) {
+ mProviderFriendlyName = providerFriendlyName;
+ }
+
+ /** {@hide} */
+ @SystemApi
+ public @Nullable String getProviderFriendlyName() {
+ return mProviderFriendlyName;
+ }
+
+ /** {@hide} */
public void setNetworkSuggestionOrSpecifierPackageName(@Nullable String packageName) {
mNetworkSuggestionOrSpecifierPackageName = packageName;
}
@@ -677,6 +719,8 @@
mSupplicantState.writeToParcel(dest, flags);
dest.writeInt(mOsuAp ? 1 : 0);
dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
+ dest.writeString(mFqdn);
+ dest.writeString(mProviderFriendlyName);
}
/** Implement the Parcelable interface {@hide} */
@@ -716,6 +760,8 @@
info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
info.mOsuAp = in.readInt() != 0;
info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
+ info.mFqdn = in.readString();
+ info.mProviderFriendlyName = in.readString();
return info;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7caace6..6c645fc 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1738,10 +1738,7 @@
* @deprecated This is no longer supported.
*/
@Deprecated
- @RequiresPermission(anyOf = {
- android.Manifest.permission.NETWORK_SETTINGS,
- android.Manifest.permission.NETWORK_SETUP_WIZARD
- })
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void removePasspointConfiguration(String fqdn) {
try {
if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 22dc2ed..ab7bb68 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -17,14 +17,13 @@
package android.net.wifi.p2p;
import android.annotation.UnsupportedAppUsage;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Log;
import java.util.Objects;
-
-import java.util.regex.Pattern;
import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* A class representing a Wi-Fi p2p device
@@ -360,7 +359,9 @@
deviceCapability = source.deviceCapability;
groupCapability = source.groupCapability;
status = source.status;
- wfdInfo = new WifiP2pWfdInfo(source.wfdInfo);
+ if (source.wfdInfo != null) {
+ wfdInfo = new WifiP2pWfdInfo(source.wfdInfo);
+ }
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 948dcfa..b303496 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -36,6 +36,8 @@
private static final long TEST_TX_BAD = 3;
private static final long TEST_RX_SUCCESS = 4;
private static final String TEST_PACKAGE_NAME = "com.test.example";
+ private static final String TEST_FQDN = "test.com";
+ private static final String TEST_PROVIDER_NAME = "test";
/**
* Verify parcel write/read with WifiInfo.
@@ -49,6 +51,8 @@
writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
writeWifiInfo.setTrusted(true);
writeWifiInfo.setOsuAp(true);
+ writeWifiInfo.setFQDN(TEST_FQDN);
+ writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
writeWifiInfo.setNetworkSuggestionOrSpecifierPackageName(TEST_PACKAGE_NAME);
Parcel parcel = Parcel.obtain();
@@ -64,6 +68,9 @@
assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
assertTrue(readWifiInfo.isTrusted());
assertTrue(readWifiInfo.isOsuAp());
+ assertTrue(readWifiInfo.isPasspointAp());
assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
+ assertEquals(TEST_FQDN, readWifiInfo.getFqdn());
+ assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getProviderFriendlyName());
}
}
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
index f61e6b7..17ee755 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
@@ -30,6 +30,31 @@
public class WifiP2pDeviceTest {
/**
+ * Compare two p2p devices.
+ *
+ * @param devA is the first device to be compared
+ * @param devB is the second device to be compared
+ */
+ private void compareWifiP2pDevices(WifiP2pDevice devA, WifiP2pDevice devB) {
+ assertEquals(devA.deviceName, devB.deviceName);
+ assertEquals(devA.deviceAddress, devB.deviceAddress);
+ assertEquals(devA.primaryDeviceType, devB.primaryDeviceType);
+ assertEquals(devA.secondaryDeviceType, devB.secondaryDeviceType);
+ assertEquals(devA.wpsConfigMethodsSupported, devB.wpsConfigMethodsSupported);
+ assertEquals(devA.deviceCapability, devB.deviceCapability);
+ assertEquals(devA.groupCapability, devB.groupCapability);
+ assertEquals(devA.status, devB.status);
+ if (devA.wfdInfo != null) {
+ assertEquals(devA.wfdInfo.isWfdEnabled(), devB.wfdInfo.isWfdEnabled());
+ assertEquals(devA.wfdInfo.getDeviceInfoHex(), devB.wfdInfo.getDeviceInfoHex());
+ assertEquals(devA.wfdInfo.getControlPort(), devB.wfdInfo.getControlPort());
+ assertEquals(devA.wfdInfo.getMaxThroughput(), devB.wfdInfo.getMaxThroughput());
+ } else {
+ assertEquals(devA.wfdInfo, devB.wfdInfo);
+ }
+ }
+
+ /**
* Check equals and hashCode consistency
*/
@Test
@@ -42,4 +67,52 @@
assertTrue(dev_a.equals(dev_b));
assertEquals(dev_a.hashCode(), dev_b.hashCode());
}
+
+ /**
+ * Check the copy constructor with default values.
+ */
+ @Test
+ public void testCopyConstructorWithDefaultValues() throws Exception {
+ WifiP2pDevice device = new WifiP2pDevice();
+ WifiP2pDevice copy = new WifiP2pDevice(device);
+ compareWifiP2pDevices(device, copy);
+ }
+
+ /**
+ * Check the copy constructor with updated values.
+ */
+ @Test
+ public void testCopyConstructorWithUpdatedValues() throws Exception {
+ WifiP2pDevice device = new WifiP2pDevice();
+ device.deviceName = "deviceName";
+ device.deviceAddress = "11:22:33:44:55:66";
+ device.primaryDeviceType = "primaryDeviceType";
+ device.secondaryDeviceType = "secondaryDeviceType";
+ device.wpsConfigMethodsSupported = 0x0008;
+ device.deviceCapability = 1;
+ device.groupCapability = 1;
+ device.status = WifiP2pDevice.CONNECTED;
+ device.wfdInfo = new WifiP2pWfdInfo();
+ WifiP2pDevice copy = new WifiP2pDevice(device);
+ compareWifiP2pDevices(device, copy);
+ }
+
+ /**
+ * Check the copy constructor when the wfdInfo of the source object is null.
+ */
+ @Test
+ public void testCopyConstructorWithNullWfdInfo() throws Exception {
+ WifiP2pDevice device = new WifiP2pDevice();
+ device.deviceName = "deviceName";
+ device.deviceAddress = "11:22:33:44:55:66";
+ device.primaryDeviceType = "primaryDeviceType";
+ device.secondaryDeviceType = "secondaryDeviceType";
+ device.wpsConfigMethodsSupported = 0x0008;
+ device.deviceCapability = 1;
+ device.groupCapability = 1;
+ device.status = WifiP2pDevice.CONNECTED;
+ device.wfdInfo = null;
+ WifiP2pDevice copy = new WifiP2pDevice(device);
+ compareWifiP2pDevices(device, copy);
+ }
}