Merge "metrics: num saved networks with mac randomization"
diff --git a/Android.bp b/Android.bp
index 7bdedc7..0848d2b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -804,6 +804,7 @@
srcs: [
"core/java/android/os/IStatsCompanionService.aidl",
"core/java/android/os/IStatsManager.aidl",
+ "core/java/android/os/IStatsPullerCallback.aidl",
],
}
diff --git a/Android.mk b/Android.mk
index 9c65948..9a91dd1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -72,6 +72,9 @@
$(hide) mkdir -p $(OUT_DOCS)/offline-sdk
( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1
+.PHONY: docs offline-sdk-docs
+docs offline-sdk-docs: $(OUT_DOCS)/offline-sdk-timestamp
+
# Run this for checkbuild
checkbuild: doc-comment-check-docs
# Check comment when you are updating the API
diff --git a/api/current.txt b/api/current.txt
index a3b8328..c5cd573 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30111,10 +30111,14 @@
method public void onIdentityChanged(byte[]);
}
- public final class PeerHandle implements android.os.Parcelable {
+ public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable {
+ ctor public ParcelablePeerHandle(android.net.wifi.aware.PeerHandle);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.wifi.aware.PeerHandle> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR;
+ }
+
+ public class PeerHandle {
}
public final class PublishConfig implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 7babf56..f673827 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5779,6 +5779,11 @@
field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
}
+ public static interface DeviceConfig.Runtime {
+ field public static final String NAMESPACE = "runtime";
+ field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
+ }
+
public static interface DeviceConfig.RuntimeNative {
field public static final String NAMESPACE = "runtime_native";
}
@@ -7024,6 +7029,7 @@
method @NonNull public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers();
method public int getMultiSimPolicy();
method public boolean isAllCarriersAllowed();
+ method public java.util.List<java.lang.Boolean> isCarrierIdentifiersAllowed(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1
field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0
@@ -7839,6 +7845,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMultisimCarrierRestricted();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 6954011..1a7e4cb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1785,12 +1785,19 @@
}
public final class DeviceConfig {
+ method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
+ method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
+ field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
}
+ public static interface DeviceConfig.OnPropertyChangedListener {
+ method public void onPropertyChanged(String, String, String);
+ }
+
public static interface DeviceConfig.Privacy {
field public static final String NAMESPACE = "privacy";
field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
@@ -2694,6 +2701,7 @@
public final class AutofillManager {
method public void setAugmentedAutofillWhitelist(@Nullable java.util.List<java.lang.String>, @Nullable java.util.List<android.content.ComponentName>);
field public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES = "smart_suggestion_supported_modes";
+ field public static final int FLAG_SMART_SUGGESTION_OFF = 0; // 0x0
field public static final int FLAG_SMART_SUGGESTION_SYSTEM = 1; // 0x1
field public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 120000; // 0x1d4c0
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index d6f045e..faf2053 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -71,6 +71,7 @@
"src/external/Perfetto.cpp",
"src/external/Perfprofd.cpp",
"src/external/StatsPuller.cpp",
+ "src/external/StatsCallbackPuller.cpp",
"src/external/StatsCompanionServicePuller.cpp",
"src/external/SubsystemSleepStatePuller.cpp",
"src/external/PowerStatsPuller.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 86bf3ec..bd21a95 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1057,6 +1057,24 @@
return Status::ok();
}
+Status StatsService::registerPullerCallback(int32_t atomTag,
+ const sp<android::os::IStatsPullerCallback>& pullerCallback,
+ const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ VLOG("StatsService::registerPullerCallback called.");
+ mPullerManager->RegisterPullerCallback(atomTag, pullerCallback);
+ return Status::ok();
+}
+
+Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ VLOG("StatsService::unregisterPullerCallback called.");
+ mPullerManager->UnregisterPullerCallback(atomTag);
+ return Status::ok();
+}
+
hardware::Return<void> StatsService::reportSpeakerImpedance(
const SpeakerImpedance& speakerImpedance) {
LogEvent event(getWallClockSec() * NS_PER_SEC, getElapsedRealtimeNs(), speakerImpedance);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index cdff50f..941ed46 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -173,6 +173,19 @@
virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override;
/**
+ * Binder call to register a callback function for a vendor pulled atom.
+ * Note: this atom must NOT have uid as a field.
+ */
+ virtual Status registerPullerCallback(int32_t atomTag,
+ const sp<android::os::IStatsPullerCallback>& pullerCallback,
+ const String16& packageName) override;
+
+ /**
+ * Binder call to unregister any existing callback function for a vendor pulled atom.
+ */
+ virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
+
+ /**
* Binder call to get SpeakerImpedance atom.
*/
virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 458e0f5..da7e4da 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -2177,6 +2177,7 @@
SPEAKER_SHORT = 3;
FINGERPRINT_SENSOR_BROKEN = 4;
FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
+ DEGRADE = 6;
}
optional int32 failure_code = 3;
}
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
new file mode 100644
index 0000000..d718273
--- /dev/null
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include <android/os/IStatsPullerCallback.h>
+
+#include "StatsCallbackPuller.h"
+#include "logd/LogEvent.h"
+#include "stats_log_util.h"
+
+using namespace android::binder;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback) :
+ StatsPuller(tagId), mCallback(callback) {
+ VLOG("StatsCallbackPuller created for tag %d", tagId);
+}
+
+bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
+ VLOG("StatsCallbackPuller called for tag %d", mTagId)
+ if(mCallback == nullptr) {
+ ALOGW("No callback registered");
+ return false;
+ }
+ int64_t wallClockTimeNs = getWallClockNs();
+ int64_t elapsedTimeNs = getElapsedRealtimeNs();
+ vector<StatsLogEventWrapper> returned_value;
+ Status status = mCallback->pullData(mTagId, elapsedTimeNs, wallClockTimeNs, &returned_value);
+ if (!status.isOk()) {
+ ALOGW("StatsCallbackPuller::pull failed for %d", mTagId);
+ return false;
+ }
+ data->clear();
+ for (const StatsLogEventWrapper& it: returned_value) {
+ LogEvent::createLogEvents(it, *data);
+ }
+ VLOG("StatsCallbackPuller::pull succeeded for %d", mTagId);
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h
new file mode 100644
index 0000000..c4bfa89
--- /dev/null
+++ b/cmds/statsd/src/external/StatsCallbackPuller.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/os/IStatsPullerCallback.h>
+#include <utils/String16.h>
+#include "StatsPuller.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class StatsCallbackPuller : public StatsPuller {
+public:
+ explicit StatsCallbackPuller(int tagId, const sp<IStatsPullerCallback>& callback);
+
+private:
+ bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
+ const sp<IStatsPullerCallback> mCallback;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index c7c22ee..9552c0a 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -33,7 +33,7 @@
void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
StatsPuller::StatsPuller(const int tagId)
- : mTagId(tagId) {
+ : mTagId(tagId), mLastPullTimeNs(0) {
}
bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index ecdcd21..ed72b29 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsPullerCallback.h>
#include <cutils/log.h>
#include <math.h>
#include <stdint.h>
@@ -29,6 +30,7 @@
#include "PowerStatsPuller.h"
#include "ResourceHealthManagerPuller.h"
#include "StatsCompanionServicePuller.h"
+#include "StatsCallbackPuller.h"
#include "StatsPullerManager.h"
#include "SubsystemSleepStatePuller.h"
#include "statslog.h"
@@ -49,7 +51,7 @@
// Values smaller than this may require to update the alarm.
const int64_t NO_ALARM_UPDATE = INT64_MAX;
-const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
+std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
// wifi_bytes_transfer
{android::util::WIFI_BYTES_TRANSFER,
{.additiveFields = {2, 3, 4, 5},
@@ -420,6 +422,30 @@
return totalCleared;
}
+void StatsPullerManager::RegisterPullerCallback(int32_t atomTag,
+ const sp<IStatsPullerCallback>& callback) {
+ AutoMutex _l(mLock);
+ // Platform pullers cannot be changed.
+ if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+ VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d",
+ atomTag, StatsdStats::kMaxPlatformAtomTag);
+ return;
+ }
+ VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
+ StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
+ kAllPullAtomInfo[atomTag] = {.puller = new StatsCallbackPuller(atomTag, callback)};
+}
+
+void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) {
+ AutoMutex _l(mLock);
+ // Platform pullers cannot be changed.
+ if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+ return;
+ }
+ StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false);
+ kAllPullAtomInfo.erase(atomTag);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 807e4af..45f6b35 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/os/IStatsCompanionService.h>
+#include <android/os/IStatsPullerCallback.h>
#include <binder/IServiceManager.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -91,7 +92,12 @@
void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
- const static std::map<int, PullAtomInfo> kAllPullAtomInfo;
+ void RegisterPullerCallback(int32_t atomTag,
+ const sp<IStatsPullerCallback>& callback);
+
+ void UnregisterPullerCallback(int32_t atomTag);
+
+ static std::map<int, PullAtomInfo> kAllPullAtomInfo;
private:
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index c4034ff..40329b7 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -423,6 +423,15 @@
mPulledAtomStats[atomId].emptyData++;
}
+void StatsdStats::notePullerCallbackRegistrationChanged(int atomId, bool registered) {
+ lock_guard<std::mutex> lock(mLock);
+ if (registered) {
+ mPulledAtomStats[atomId].registeredCount++;
+ } else {
+ mPulledAtomStats[atomId].unregisteredCount++;
+ }
+}
+
void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) {
lock_guard<std::mutex> lock(mLock);
getAtomMetricStats(metricId).hardDimensionLimitReached++;
@@ -514,6 +523,8 @@
pullStats.second.dataError = 0;
pullStats.second.pullTimeout = 0;
pullStats.second.pullExceedMaxDelay = 0;
+ pullStats.second.registeredCount = 0;
+ pullStats.second.unregisteredCount = 0;
}
mAtomMetricStats.clear();
}
@@ -625,12 +636,14 @@
" (average pull time nanos)%lld, (max pull time nanos)%lld, (average pull delay "
"nanos)%lld, "
" (max pull delay nanos)%lld, (data error)%ld\n"
- " (pull timeout)%ld, (pull exceed max delay)%ld\n",
+ " (pull timeout)%ld, (pull exceed max delay)%ld\n"
+ " (registered count) %ld, (unregistered count) %ld\n",
(int)pair.first, (long)pair.second.totalPull, (long)pair.second.totalPullFromCache,
(long)pair.second.minPullIntervalSec, (long long)pair.second.avgPullTimeNs,
(long long)pair.second.maxPullTimeNs, (long long)pair.second.avgPullDelayNs,
(long long)pair.second.maxPullDelayNs, pair.second.dataError,
- pair.second.pullTimeout, pair.second.pullExceedMaxDelay);
+ pair.second.pullTimeout, pair.second.pullExceedMaxDelay,
+ pair.second.registeredCount, pair.second.unregisteredCount);
}
if (mAnomalyAlarmRegisteredStats > 0) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index ea3f3b3..65e8a32 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -146,6 +146,10 @@
// Max time to do a pull.
static const int64_t kPullMaxDelayNs = 10 * NS_PER_SEC;
+
+ // Max platform atom tag number.
+ static const int32_t kMaxPlatformAtomTag = 100000;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -340,6 +344,13 @@
void noteEmptyData(int atomId);
/**
+ * Records that a puller callback for the given atomId was registered or unregistered.
+ *
+ * @param registered True if the callback was registered, false if was unregistered.
+ */
+ void notePullerCallbackRegistrationChanged(int atomId, bool registered);
+
+ /**
* Hard limit was reached in the cardinality of an atom
*/
void noteHardDimensionLimitReached(int64_t metricId);
@@ -416,6 +427,8 @@
long statsCompanionPullFailed = 0;
long statsCompanionPullBinderTransactionFailed = 0;
long emptyData = 0;
+ long registeredCount = 0;
+ long unregisteredCount = 0;
} PulledAtomStats;
typedef struct {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index ac6c27a..851ae99 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -450,6 +450,17 @@
}
mMatchedMetricDimensionKeys.clear();
mHasGlobalBase = true;
+
+ // If we reach the guardrail, we might have dropped some data which means the bucket is
+ // incomplete.
+ //
+ // The base also needs to be reset. If we do not have the full data, we might
+ // incorrectly compute the diff when mUseZeroDefaultBase is true since an existing key
+ // might be missing from mCurrentSlicedBucket.
+ if (hasReachedGuardRailLimit()) {
+ invalidateCurrentBucket();
+ mCurrentSlicedBucket.clear();
+ }
}
void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
@@ -471,6 +482,10 @@
}
}
+bool ValueMetricProducer::hasReachedGuardRailLimit() const {
+ return mCurrentSlicedBucket.size() >= mDimensionHardLimit;
+}
+
bool ValueMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) {
// ===========GuardRail==============
// 1. Report the tuple count if the tuple count > soft limit
@@ -481,7 +496,7 @@
size_t newTupleCount = mCurrentSlicedBucket.size() + 1;
StatsdStats::getInstance().noteMetricDimensionSize(mConfigKey, mMetricId, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
- if (newTupleCount > mDimensionHardLimit) {
+ if (hasReachedGuardRailLimit()) {
ALOGE("ValueMetric %lld dropping data for dimension key %s", (long long)mMetricId,
newKey.toString().c_str());
StatsdStats::getInstance().noteHardDimensionLimitReached(mMetricId);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index d1c2315..f26ad85 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -158,6 +158,7 @@
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const MetricDimensionKey& newKey);
+ bool hasReachedGuardRailLimit() const;
bool hitFullBucketGuardRailLocked(const MetricDimensionKey& newKey);
@@ -244,6 +245,7 @@
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
+ FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 6a07a3f..863261a 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -407,6 +407,8 @@
optional int64 stats_companion_pull_failed = 13;
optional int64 stats_companion_pull_binder_transaction_failed = 14;
optional int64 empty_data = 15;
+ optional int64 registered_count = 16;
+ optional int64 unregistered_count = 17;
}
repeated PulledAtomStats pulled_atom_stats = 10;
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index aa8cfc5..0ebf2ca 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -70,6 +70,8 @@
const int FIELD_ID_STATS_COMPANION_FAILED = 13;
const int FIELD_ID_STATS_COMPANION_BINDER_TRANSACTION_FAILED = 14;
const int FIELD_ID_EMPTY_DATA = 15;
+const int FIELD_ID_PULL_REGISTERED_COUNT = 16;
+const int FIELD_ID_PULL_UNREGISTERED_COUNT = 17;
// for AtomMetricStats proto
const int FIELD_ID_ATOM_METRIC_STATS = 17;
const int FIELD_ID_METRIC_ID = 1;
@@ -480,6 +482,10 @@
(long long)pair.second.statsCompanionPullBinderTransactionFailed);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_EMPTY_DATA,
(long long)pair.second.emptyData);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_REGISTERED_COUNT,
+ (long long) pair.second.registeredCount);
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_PULL_UNREGISTERED_COUNT,
+ (long long) pair.second.unregisteredCount);
protoOutput->end(token);
}
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index 92aa998..44a88f0 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -259,6 +259,10 @@
stats.notePullDelay(android::util::DISK_SPACE, 3335L);
stats.notePull(android::util::DISK_SPACE);
stats.notePullFromCache(android::util::DISK_SPACE);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, false);
+ stats.notePullerCallbackRegistrationChanged(android::util::DISK_SPACE, true);
+
vector<uint8_t> output;
stats.dumpStats(&output, false);
@@ -276,6 +280,8 @@
EXPECT_EQ(3333L, report.pulled_atom_stats(0).max_pull_time_nanos());
EXPECT_EQ(2223L, report.pulled_atom_stats(0).average_pull_delay_nanos());
EXPECT_EQ(3335L, report.pulled_atom_stats(0).max_pull_delay_nanos());
+ EXPECT_EQ(2L, report.pulled_atom_stats(0).registered_count());
+ EXPECT_EQ(1L, report.pulled_atom_stats(0).unregistered_count());
}
TEST(StatsdStatsTest, TestAtomMetricsStats) {
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index ae3cdbc..572b199 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2390,6 +2390,51 @@
EXPECT_EQ(true, valueProducer.mHasGlobalBase);
}
+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);
+ 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);
+
+ 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, _)).WillRepeatedly(Return());
+
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // First onConditionChanged
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ for (int i = 0; i < 2000; i++) {
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+ event->write(i);
+ event->write(i);
+ event->init();
+ data->push_back(event);
+ }
+ return true;
+ }));
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
+
+ valueProducer.mCondition = false;
+ valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2);
+ EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid);
+ EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+}
+
TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
ValueMetric metric;
metric.set_id(metricId);
diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS
new file mode 100644
index 0000000..265674a
--- /dev/null
+++ b/core/java/android/accessibilityservice/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index db6ad3d..2b765b2 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -247,8 +247,20 @@
boolean preserveWindows, boolean animate, int animationDuration);
boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
boolean animate, in Rect initialBounds, boolean showRecents);
-
-
+ /**
+ * Use the offset to adjust the stack boundary with animation.
+ *
+ * @param stackId Id of the stack to adjust.
+ * @param compareBounds Offset is only applied if the current pinned stack bounds is equal to
+ * the compareBounds.
+ * @param xOffset The horizontal offset.
+ * @param yOffset The vertical offset.
+ * @param animationDuration The duration of the resize animation in milliseconds or -1 if the
+ * default animation duration should be used.
+ * @throws RemoteException
+ */
+ void offsetPinnedStackBounds(int stackId, in Rect compareBounds, int xOffset, int yOffset,
+ int animationDuration);
/**
* Removes stacks in the input windowing modes from the system if they are of activity type
* ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 3119b37..7746148 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.os.IBinder;
import android.os.IStatsManager;
+import android.os.IStatsPullerCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.AndroidException;
@@ -408,6 +409,39 @@
}
}
+ /**
+ * Registers a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke pullData in the callback when the stats service determines that this atom needs to be
+ * pulled. Currently, this only works for atoms with tags above 100,000 that do not have a uid.
+ *
+ * @param atomTag The tag of the atom for this puller callback. Must be at least 100000.
+ * @param callback The callback to be invoked when the stats service pulls the atom.
+ * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
+ *
+ * @hide
+ */
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
+ public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
+ throws StatsUnavailableException {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (callback == null) {
+ service.unregisterPullerCallback(atomTag, mContext.getOpPackageName());
+ } else {
+ service.registerPullerCallback(atomTag, callback,
+ mContext.getOpPackageName());
+ }
+
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to connect to statsd when registering data listener.");
+ throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
+ }
+ }
+ }
+
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 077b177..dd00e5a 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -97,6 +97,12 @@
public long lastActiveTime;
/**
+ * The id of the display this task is associated with.
+ * @hide
+ */
+ public int displayId;
+
+ /**
* The recent activity values for the highest activity in the stack to have set the values.
* {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
*/
@@ -152,6 +158,7 @@
userId = source.readInt();
stackId = source.readInt();
taskId = source.readInt();
+ displayId = source.readInt();
isRunning = source.readBoolean();
baseIntent = source.readInt() != 0
? Intent.CREATOR.createFromParcel(source)
@@ -179,6 +186,7 @@
dest.writeInt(userId);
dest.writeInt(stackId);
dest.writeInt(taskId);
+ dest.writeInt(displayId);
dest.writeBoolean(isRunning);
if (baseIntent != null) {
@@ -209,6 +217,7 @@
@Override
public String toString() {
return "TaskInfo{userId=" + userId + " stackId=" + stackId + " taskId=" + taskId
+ + " displayId=" + displayId
+ " isRunning=" + isRunning
+ " baseIntent=" + baseIntent + " baseActivity=" + baseActivity
+ " topActivity=" + topActivity + " origActivity=" + origActivity
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 47034a6..7cc4391 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1029,10 +1029,18 @@
}
/**
+ * Returns true if the activity has maximum or minimum aspect ratio.
+ * @hide
+ */
+ public boolean hasFixedAspectRatio() {
+ return maxAspectRatio != 0 || minAspectRatio != 0;
+ }
+
+ /**
* Returns true if the activity's orientation is fixed.
* @hide
*/
- boolean isFixedOrientation() {
+ public boolean isFixedOrientation() {
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
}
diff --git a/core/java/android/net/INetworkMonitorCallbacks.aidl b/core/java/android/net/INetworkMonitorCallbacks.aidl
index a8682f9..5146585 100644
--- a/core/java/android/net/INetworkMonitorCallbacks.aidl
+++ b/core/java/android/net/INetworkMonitorCallbacks.aidl
@@ -24,7 +24,7 @@
void onNetworkMonitorCreated(in INetworkMonitor networkMonitor);
void notifyNetworkTested(int testResult, @nullable String redirectUrl);
void notifyPrivateDnsConfigResolved(in PrivateDnsConfigParcel config);
- void showProvisioningNotification(String action);
+ void showProvisioningNotification(String action, String packageName);
void hideProvisioningNotification();
void logCaptivePortalLoginEvent(int eventId, String packageName);
}
\ No newline at end of file
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index b6cd635..7a4c9bc 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -63,9 +63,6 @@
public static final String PERMISSION_MAINLINE_NETWORK_STACK =
"android.permission.MAINLINE_NETWORK_STACK";
- /** @hide */
- public static final String NETWORKSTACK_PACKAGE_NAME = "com.android.mainline.networkstack";
-
private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
@NonNull
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 93d6f4c..f1bba1a 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -16,6 +16,8 @@
package android.os;
+import android.os.IStatsPullerCallback;
+
/**
* Binder interface to communicate with the statistics management service.
* {@hide}
@@ -178,4 +180,20 @@
* this label. This allows building custom metrics and predicates.
*/
void sendAppBreadcrumbAtom(int label, int state);
+
+ /**
+ * Registers a puller callback function that, when invoked, pulls the data
+ * for the specified vendor atom tag.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+ */
+ oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
+ String packageName);
+
+ /**
+ * Unregisters a puller callback function for the given vendor atom.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+ */
+ oneway void unregisterPullerCallback(int atomTag, String packageName);
}
diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl
new file mode 100644
index 0000000..1684aeb
--- /dev/null
+++ b/core/java/android/os/IStatsPullerCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.StatsLogEventWrapper;
+
+/**
+ * Binder interface to pull atoms for the stats service.
+ * {@hide}
+ */
+interface IStatsPullerCallback {
+ /**
+ * Pull data for the specified atom tag. Returns an array of StatsLogEventWrapper containing
+ * the data.
+ *
+ * Note: These pulled atoms should not have uid/attribution chain. Additionally, the event
+ * timestamps will be truncated to the nearest 5 minutes.
+ */
+ StatsLogEventWrapper[] pullData(int atomTag, long elapsedNanos, long wallClocknanos);
+
+}
diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java
index acb9eac..2334242 100644
--- a/core/java/android/os/StatsLogEventWrapper.java
+++ b/core/java/android/os/StatsLogEventWrapper.java
@@ -57,20 +57,18 @@
public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
Parcelable.Creator<StatsLogEventWrapper>() {
public StatsLogEventWrapper createFromParcel(Parcel in) {
- android.util.EventLog.writeEvent(0x534e4554, "112550251",
- android.os.Binder.getCallingUid(), "");
- // Purposefully leaving this method not implemented.
- throw new RuntimeException("Not implemented");
+ return new StatsLogEventWrapper(in);
}
public StatsLogEventWrapper[] newArray(int size) {
- android.util.EventLog.writeEvent(0x534e4554, "112550251",
- android.os.Binder.getCallingUid(), "");
- // Purposefully leaving this method not implemented.
- throw new RuntimeException("Not implemented");
+ return new StatsLogEventWrapper[size];
}
};
+ private StatsLogEventWrapper(Parcel in) {
+ readFromParcel(in);
+ }
+
/**
* Set work source if any.
*/
@@ -197,6 +195,70 @@
}
/**
+ * Reads from parcel and appropriately fills member fields.
+ */
+ public void readFromParcel(Parcel in) {
+ mTypes = new ArrayList<>();
+ mValues = new ArrayList<>();
+ mWorkSource = null;
+
+ mTag = in.readInt();
+ mElapsedTimeNs = in.readLong();
+ mWallClockTimeNs = in.readLong();
+
+ // Clear any data.
+ if (DEBUG) {
+ Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs);
+ }
+ // Set up worksource if present.
+ int numWorkChains = in.readInt();
+ if (numWorkChains > 0) {
+ mWorkSource = new WorkSource();
+ for (int i = 0; i < numWorkChains; i++) {
+ android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain();
+ int workChainSize = in.readInt();
+ for (int j = 0; j < workChainSize; j++) {
+ int uid = in.readInt();
+ String tag = in.readString();
+ workChain.addNode(uid, tag);
+ }
+ }
+ }
+
+ // Do the rest of the types.
+ int numTypes = in.readInt();
+ if (DEBUG) {
+ Slog.d(TAG, "Reading " + numTypes + " elements");
+ }
+ for (int i = 0; i < numTypes; i++) {
+ int type = in.readInt();
+ mTypes.add(type);
+ switch (type) {
+ case EVENT_TYPE_INT:
+ mValues.add(in.readInt());
+ break;
+ case EVENT_TYPE_LONG:
+ mValues.add(in.readLong());
+ break;
+ case EVENT_TYPE_FLOAT:
+ mValues.add(in.readFloat());
+ break;
+ case EVENT_TYPE_DOUBLE:
+ mValues.add(in.readDouble());
+ break;
+ case EVENT_TYPE_STRING:
+ mValues.add(in.readString());
+ break;
+ case EVENT_TYPE_STORAGE:
+ mValues.add(in.createByteArray());
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
* Boilerplate for Parcel.
*/
public int describeContents() {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 8254e33..18e1f59 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -69,6 +69,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final String NAMESPACE_AUTOFILL = "autofill";
/**
@@ -122,6 +123,21 @@
}
/**
+ * Namespace for all runtime related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface Runtime {
+ String NAMESPACE = "runtime";
+
+ /**
+ * Whether or not we use the precompiled layout.
+ */
+ String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
+ }
+
+ /**
* Namespace for all runtime native related features.
*
* @hide
@@ -418,6 +434,7 @@
* @see #removeOnPropertyChangedListener(OnPropertyChangedListener)
*/
@SystemApi
+ @TestApi
@RequiresPermission(READ_DEVICE_CONFIG)
public static void addOnPropertyChangedListener(
@NonNull String namespace,
@@ -451,6 +468,7 @@
* @see #addOnPropertyChangedListener(String, Executor, OnPropertyChangedListener)
*/
@SystemApi
+ @TestApi
public static void removeOnPropertyChangedListener(
OnPropertyChangedListener onPropertyChangedListener) {
synchronized (sLock) {
@@ -547,6 +565,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public interface OnPropertyChangedListener {
/**
* Called when a property has changed.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3747ec6..22329ba 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13343,6 +13343,14 @@
public static final String ISOLATED_STORAGE_REMOTE = "isolated_storage_remote";
/**
+ * Indicates whether aware is available in the current location.
+ * @hide
+ */
+ public static final String AWARE_ALLOWED = "aware_allowed";
+
+ private static final Validator AWARE_ALLOWED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
@@ -13388,6 +13396,7 @@
SOFT_AP_TIMEOUT_ENABLED,
ZEN_DURATION,
CHARGING_VIBRATION_ENABLED,
+ AWARE_ALLOWED,
};
/**
@@ -13448,6 +13457,7 @@
VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED,
WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR);
VALIDATORS.put(WIFI_LINK_PROBING_ENABLED, WIFI_LINK_PROBING_ENABLED_VALIDATOR);
+ VALIDATORS.put(AWARE_ALLOWED, AWARE_ALLOWED_VALIDATOR);
}
/**
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 39b6876..b28ac47 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -33,6 +33,8 @@
import android.os.Message;
import android.os.SystemProperties;
import android.os.Trace;
+import android.provider.DeviceConfig;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -80,8 +82,6 @@
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
- = "view.precompiled_layout_enabled";
private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
/** Empty stack trace used to avoid log spam in re-throw exceptions. */
@@ -412,8 +412,24 @@
}
private void initPrecompiledViews() {
- initPrecompiledViews(
- SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false));
+ // Use the device config if enabled, otherwise default to the system property.
+ String usePrecompiledLayout = null;
+ try {
+ usePrecompiledLayout = DeviceConfig.getProperty(
+ DeviceConfig.Runtime.NAMESPACE,
+ DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT);
+ } catch (Exception e) {
+ // May be caused by permission errors reading the property (i.e. instant apps).
+ }
+ boolean enabled = false;
+ if (TextUtils.isEmpty(usePrecompiledLayout)) {
+ enabled = SystemProperties.getBoolean(
+ DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT,
+ false);
+ } else {
+ enabled = Boolean.parseBoolean(usePrecompiledLayout);
+ }
+ initPrecompiledViews(enabled);
}
private void initPrecompiledViews(boolean enablePrecompiledViews) {
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
new file mode 100644
index 0000000..265674a
--- /dev/null
+++ b/core/java/android/view/accessibility/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 397fc66..5e5c826 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -337,6 +337,14 @@
public static final int MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes
/**
+ * Disables Augmented Autofill.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final int FLAG_SMART_SUGGESTION_OFF = 0x0;
+
+ /**
* Displays the Augment Autofill window using the same mechanism (such as a popup-window
* attached to the focused view) as the standard autofill.
*
@@ -346,14 +354,13 @@
public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1;
/** @hide */
- @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
- FLAG_SMART_SUGGESTION_SYSTEM
- })
+ @IntDef(flag = false, value = { FLAG_SMART_SUGGESTION_OFF, FLAG_SMART_SUGGESTION_SYSTEM })
@Retention(RetentionPolicy.SOURCE)
public @interface SmartSuggestionMode {}
/**
- * Used to emulate Smart Suggestion for Augmented Autofill during development
+ * {@code DeviceConfig} property used to set which Smart Suggestion modes for Augmented Autofill
+ * are available.
*
* @hide
*/
@@ -2355,7 +2362,14 @@
/** @hide */
public static String getSmartSuggestionModeToString(@SmartSuggestionMode int flags) {
- return (flags == FLAG_SMART_SUGGESTION_SYSTEM) ? "1-SYSTEM" : flags + "-UNSUPPORTED";
+ switch (flags) {
+ case FLAG_SMART_SUGGESTION_OFF:
+ return "OFF";
+ case FLAG_SMART_SUGGESTION_SYSTEM:
+ return "SYSTEM";
+ default:
+ return "INVALID:" + flags;
+ }
}
@GuardedBy("mLock")
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 8a09788..e63a406 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1373,7 +1373,7 @@
* @hide
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
try {
Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be removed "
diff --git a/core/java/com/android/internal/os/ChildZygoteInit.java b/core/java/com/android/internal/os/ChildZygoteInit.java
index cc74863..1f816c1 100644
--- a/core/java/com/android/internal/os/ChildZygoteInit.java
+++ b/core/java/com/android/internal/os/ChildZygoteInit.java
@@ -102,7 +102,7 @@
// are just isolated UIDs in the range, because for the webview zygote, there is no
// single range that captures all possible isolated UIDs.
// TODO(b/123615476) narrow this down
- if (uidGidMin < Process.FIRST_ISOLATED_UID) {
+ if (uidGidMin < Process.FIRST_APP_ZYGOTE_ISOLATED_UID) {
throw new RuntimeException("Passed in UID range does not map to isolated processes.");
}
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index a9d75fd..15d1944 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -107,6 +107,7 @@
if (obj == NULL){
jniThrowException(_env, "java/lang/IllegalArgumentException",
"Object is set to null.");
+ return nullptr;
}
jlong handle = _env->CallLongMethod(obj, mid);
@@ -238,6 +239,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -335,6 +337,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -454,6 +457,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -509,6 +513,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -582,6 +587,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -664,6 +670,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -721,6 +728,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -731,7 +739,7 @@
(JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) {
jniThrowException(_env, "java/lang/UnsupportedOperationException",
"eglCreatePixmapSurface");
- return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
+ return nullptr;
}
/* EGLBoolean eglDestroySurface ( EGLDisplay dpy, EGLSurface surface ) */
@@ -800,6 +808,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
@@ -898,6 +907,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
@@ -1034,6 +1044,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return nullptr;
}
return toEGLHandle(_env, eglcontextClass, eglcontextConstructor, _returnValue);
}
@@ -1152,6 +1163,7 @@
}
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
+ return false;
}
return (jboolean)_returnValue;
}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 130f629..18eb7e9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3425,8 +3425,14 @@
-->
<string-array translatable="false" name="config_convert_to_emergency_number_map" />
- <!-- An array of packages for which notifications cannot be blocked. -->
- <string-array translatable="false" name="config_nonBlockableNotificationPackages" />
+ <!-- An array of packages for which notifications cannot be blocked.
+ Should only be used for core device functionality that must not be
+ rendered inoperative for safety reasons, like the phone dialer and
+ SMS handler. -->
+ <string-array translatable="false" name="config_nonBlockableNotificationPackages">
+ <item>com.android.dialer</item>
+ <item>com.android.messaging</item>
+ </string-array>
<!-- An array of packages which can listen for notifications on low ram devices. -->
<string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" />
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 0dc54e0..93068ea9 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -41,9 +41,7 @@
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="textColor">@color/btn_colored_text_material</item>
</style>
- <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView">
- <item name="fontFamily">@string/config_bodyFontFamily</item>
- </style>
+ <style name="Widget.DeviceDefault.TextView" parent="Widget.Material.TextView" />
<style name="Widget.DeviceDefault.CheckedTextView" parent="Widget.Material.CheckedTextView"/>
<style name="Widget.DeviceDefault.AutoCompleteTextView" parent="Widget.Material.AutoCompleteTextView"/>
<style name="Widget.DeviceDefault.CompoundButton.CheckBox" parent="Widget.Material.CompoundButton.CheckBox"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 6770ae1..7382213 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -209,21 +209,14 @@
<privapp-permissions package="com.android.mainline.networkstack">
<permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
- <permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/>
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.CONTROL_VPN"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
- <permission name="android.permission.MANAGE_IPSEC_TUNNELS"/>
- <permission name="android.permission.MANAGE_NETWORK_POLICY"/>
<permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS"/>
<permission name="android.permission.MANAGE_USB"/>
- <permission name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"/>
- <permission name="android.permission.NETWORK_SETTINGS"/>
- <permission name="android.permission.NETWORK_STACK" />
- <permission name="android.permission.NET_TUNNELING"/>
<permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
- <permission name="android.permission.PEERS_MAC_ADDRESS"/>
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
<permission name="android.permission.READ_PRECISE_PHONE_STATE"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
@@ -261,6 +254,7 @@
<permission name="android.permission.CHANGE_LOWPAN_STATE"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<permission name="android.permission.CLEAR_APP_CACHE"/>
+ <permission name="android.permission.ACCESS_INSTANT_APPS" />
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.DELETE_CACHE_FILES"/>
<permission name="android.permission.DELETE_PACKAGES"/>
diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java
deleted file mode 100644
index 9a346ff..0000000
--- a/media/java/android/media/session/MediaSessionProviderService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.session;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-/**
- * Abstract class for mainline module services.
- *
- * @hide // TODO: Make it as a @SystemApi
- */
-public abstract class MediaSessionProviderService extends Service {
-
- @Override
- public IBinder onBind(Intent intent) {
- // TODO: Return IMediaSessionProviderService.Stub()
- return null;
- }
-}
diff --git a/media/packages/MediaCore/Android.bp.bak b/media/packages/MediaCore/Android.bp.bak
deleted file mode 100644
index c7fd58b..0000000
--- a/media/packages/MediaCore/Android.bp.bak
+++ /dev/null
@@ -1,21 +0,0 @@
-android_app {
- name: "MediaCore",
-
- srcs: [
- "src/**/*.java",
- ],
-
- static_libs: [
- // TODO: Temporarily statically linked. Should go into "libs"
- "media1",
- ],
-
- // System app
- platform_apis: true,
-
- // Privileged app
- privileged: true,
-
- // Make sure that the implementation only relies on SDK or system APIs.
- sdk_version: "system_current",
-}
diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml
deleted file mode 100644
index 4e2b274..0000000
--- a/media/packages/MediaCore/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/AndroidManifest.xml
-**
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system"
- android:sharedUserLabel="@string/android_system_label">
- <application android:process="system"
- android:persistent="true"
- android:directBootAware="true">
- <service android:name="AmlMediaSessionProviderService" android:singleUser="true">
- <intent-filter>
- <action android:name="android.media.session.MediaSessionProviderService"/>
- </intent-filter>
- </service>
- </application>
-</manifest>
diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml
deleted file mode 100644
index 59fd635..0000000
--- a/media/packages/MediaCore/res/values/strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources>
- <!-- Label for the Android system components when they are shown to the user. -->
- <string name="android_system_label" translatable="false">Android System</string>
-</resources>
-
diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
deleted file mode 100644
index 43b95ab..0000000
--- a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.media;
-
-import android.content.Context;
-import android.media.session.MediaSessionProviderService;
-import android.os.PowerManager;
-import android.util.Log;
-
-/**
- * System implementation of MediaSessionProviderService
- */
-public class AmlMediaSessionProviderService extends MediaSessionProviderService {
- private static final String TAG = "AmlMediaSessionProviderS";
- static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
- private Context mContext;
-
- public AmlMediaSessionProviderService(Context context) {
- mContext = context;
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- }
-}
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index ac55bfa..e4d3591 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -27,8 +27,8 @@
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
- <!-- Launch captive portal app as specific user -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <!-- Send latency broadcast as current user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 0d6d080..2e72d82 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -500,7 +500,7 @@
private void showProvisioningNotification(String action) {
try {
- mCallback.showProvisioningNotification(action);
+ mCallback.showProvisioningNotification(action, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error showing provisioning notification", e);
}
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d11bb64..b98b0f7 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -482,7 +482,7 @@
nm.notifyNetworkConnected();
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .showProvisioningNotification(any());
+ .showProvisioningNotification(any(), any());
// Check that startCaptivePortalApp sends the expected intent.
nm.launchCaptivePortalApp();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e28c894..ab95910 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -167,7 +167,7 @@
// This is to ensure all the profiles are disconnected as some CK/Hs do not
// disconnect PBAP connection when HF connection is brought down
PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
- if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
+ if (PbapProfile != null && isConnectedProfile(PbapProfile))
{
PbapProfile.disconnect(mDevice);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 88adcdb..5c9a06f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -20,6 +20,7 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
public class ThreadUtils {
@@ -59,12 +60,14 @@
/**
* Posts runnable in background using shared background thread pool.
+ *
+ * @Return A future of the task that can be monitored for updates or cancelled.
*/
- public static void postOnBackgroundThread(Runnable runnable) {
+ public static Future postOnBackgroundThread(Runnable runnable) {
if (sSingleThreadExecutor == null) {
sSingleThreadExecutor = Executors.newSingleThreadExecutor();
}
- sSingleThreadExecutor.execute(runnable);
+ return sSingleThreadExecutor.submit(runnable);
}
/**
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e8c728d..0da3b10 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -82,6 +82,7 @@
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+ <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
index 6f7f398..c8dc8e4 100644
--- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml
@@ -19,9 +19,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <include
+ <TextClock
android:id="@+id/digital_clock"
- layout="@layout/text_clock"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="72dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|left"
+ android:textSize="44dp"
+ android:letterSpacing="0.05"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:elegantTextHeight="false"
/>
<com.android.keyguard.clock.ImageClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
index 64b676f5..116a044 100644
--- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
@@ -19,9 +19,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
>
- <include
+ <TextClock
android:id="@+id/digital_clock"
- layout="@layout/text_clock"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="72dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|left"
+ android:textSize="44dp"
+ android:letterSpacing="0.05"
+ android:textColor="?attr/wallpaperTextColor"
+ android:singleLine="true"
+ style="@style/widget_big"
+ android:format12Hour="@string/keyguard_widget_12_hours_format"
+ android:format24Hour="@string/keyguard_widget_24_hours_format"
+ android:elegantTextHeight="false"
/>
<com.android.keyguard.clock.StretchAnalogClock
android:id="@+id/analog_clock"
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 3591dc8..4d8cf96 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
import com.android.keyguard.R;
@@ -80,8 +81,9 @@
// Put digital clock in two left corner of the screen.
if (mDigitalClock != null) {
- mDigitalClock.setX(0.1f * getWidth() + offsetX);
- mDigitalClock.setY(0.1f * getHeight() + offsetY);
+ LayoutParams params = (LayoutParams) mDigitalClock.getLayoutParams();
+ mDigitalClock.setX(offsetX + params.leftMargin);
+ mDigitalClock.setY(offsetY + params.topMargin);
}
// Put the analog clock in the middle of the screen.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 82aa473..9c65994 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -79,6 +79,7 @@
private static final int MSG_RESIZE_IMMEDIATE = 1;
private static final int MSG_RESIZE_ANIMATE = 2;
+ private static final int MSG_OFFSET_ANIMATE = 3;
private Context mContext;
private IActivityManager mActivityManager;
@@ -360,9 +361,20 @@
/**
* Animates the PiP to offset it from the IME or shelf.
*/
- void animateToOffset(Rect toBounds) {
+ void animateToOffset(Rect originalBounds, int offset) {
cancelAnimations();
- resizeAndAnimatePipUnchecked(toBounds, SHIFT_DURATION);
+ adjustAndAnimatePipOffset(originalBounds, offset, SHIFT_DURATION);
+ }
+
+ private void adjustAndAnimatePipOffset(Rect originalBounds, int offset, int duration) {
+ if (offset == 0) {
+ return;
+ }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = originalBounds;
+ args.argi1 = offset;
+ args.argi2 = duration;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_OFFSET_ANIMATE, args));
}
/**
@@ -549,6 +561,31 @@
return true;
}
+ case MSG_OFFSET_ANIMATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Rect originalBounds = (Rect) args.arg1;
+ final int offset = args.argi1;
+ final int duration = args.argi2;
+ try {
+ StackInfo stackInfo = mActivityTaskManager.getStackInfo(
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (stackInfo == null) {
+ // In the case where we've already re-expanded or dismissed the PiP, then
+ // just skip the resize
+ return true;
+ }
+
+ mActivityTaskManager.offsetPinnedStackBounds(stackInfo.stackId, originalBounds,
+ 0/* xOffset */, offset, duration);
+ Rect toBounds = new Rect(originalBounds);
+ toBounds.offset(0, offset);
+ mBounds.set(toBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not animate offset pinned stack with offset: " + offset, e);
+ }
+ return true;
+ }
+
default:
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 6a9f24c..cef1b6b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -346,12 +346,11 @@
}
private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) {
- final Rect bounds = new Rect(animatingBounds);
- bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
+ int offset = toAdjustedBounds.bottom - animatingBounds.top;
// In landscape mode, PIP window can go offset while launching IME. We want to align the
// the top of the PIP window with the top of the movement bounds in that case.
- bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top));
- mMotionHelper.animateToOffset(bounds);
+ offset += Math.max(0, mMovementBounds.top - animatingBounds.top);
+ mMotionHelper.animateToOffset(animatingBounds, offset);
}
private void onRegistrationChanged(boolean isRegistered) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f054345..c43f572 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -54,6 +54,7 @@
import java.io.PrintWriter;
import java.time.Duration;
import java.util.Arrays;
+import java.util.concurrent.Future;
public class PowerUI extends SystemUI {
static final String TAG = "PowerUI";
@@ -80,6 +81,7 @@
private Estimate mLastEstimate;
private boolean mLowWarningShownThisChargeCycle;
private boolean mSevereWarningShownThisChargeCycle;
+ private Future mLastShowWarningTask;
private int mLowBatteryAlertCloseLevel;
private final int[] mLowBatteryReminderLevels = new int[2];
@@ -247,7 +249,10 @@
}
// Show the correct version of low battery warning if needed
- ThreadUtils.postOnBackgroundThread(() -> {
+ if (mLastShowWarningTask != null) {
+ mLastShowWarningTask.cancel(true);
+ }
+ mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
maybeShowBatteryWarning(
oldBatteryLevel, plugged, oldPlugged, oldBucket, bucket);
});
@@ -276,7 +281,7 @@
estimate = mEnhancedEstimates.getEstimate();
mLastEstimate = estimate;
}
- // Turbo is not always booted once SysUI is running so we have ot make sure we actually
+ // Turbo is not always booted once SysUI is running so we have to make sure we actually
// get data back
if (estimate != null) {
mTimeRemaining = estimate.estimateMillis;
@@ -355,13 +360,26 @@
// Only show the low warning once per charge cycle & no battery saver
final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
&& (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
- || mBatteryLevel <= warnLevel);
+ || mBatteryLevel <= warnLevel);
// Only show the severe warning once per charge cycle
final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
&& (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
- || mBatteryLevel <= critLevel);
+ || mBatteryLevel <= critLevel);
+ final boolean canShow = canShowWarning || canShowSevereWarning;
+ if (DEBUG) {
+ Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: "
+ + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
+ + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
+ + " mEnhancedEstimates.timeremaining: " + timeRemaining
+ + " mBatteryLevel: " + mBatteryLevel
+ + " canShowWarning: " + canShowWarning
+ + " canShowSevereWarning: " + canShowSevereWarning
+ + " plugged: " + plugged
+ + " batteryStatus: " + batteryStatus
+ + " isPowerSaver: " + isPowerSaver);
+ }
return canShowWarning || canShowSevereWarning;
}
diff --git a/sax/tests/saxtests/Android.bp b/sax/tests/saxtests/Android.bp
new file mode 100644
index 0000000..5889f76
--- /dev/null
+++ b/sax/tests/saxtests/Android.bp
@@ -0,0 +1,11 @@
+android_test {
+ name: "FrameworksSaxTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ platform_apis: true,
+}
diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
deleted file mode 100644
index c4517a9..0000000
--- a/sax/tests/saxtests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_PACKAGE_NAME := FrameworksSaxTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
new file mode 100644
index 0000000..265674a
--- /dev/null
+++ b/services/accessibility/OWNERS
@@ -0,0 +1,3 @@
+svetoslavganov@google.com
+pweaver@google.com
+rhedjao@google.com
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java
similarity index 89%
rename from services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java
rename to services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java
index 2d2e88a..a448901 100644
--- a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListing.java
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkListingMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,13 +11,14 @@
* 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
+ * limitations under the License.
*/
package com.android.server.backup.encryption.chunk;
import android.annotation.Nullable;
import android.util.proto.ProtoInputStream;
+
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
@@ -30,16 +31,16 @@
* It can then tell the server to use that chunk, through telling it the position and length of the
* chunk in the previous backup's blob.
*/
-public class ChunkListing {
+public class ChunkListingMap {
/**
- * Reads a ChunkListing from a {@link ProtoInputStream}. Expects the message to be of format
+ * Reads a ChunkListingMap from a {@link ProtoInputStream}. Expects the message to be of format
* {@link ChunksMetadataProto.ChunkListing}.
*
* @param inputStream Currently at a {@link ChunksMetadataProto.ChunkListing} message.
* @throws IOException when the message is not structured as expected or a field can not be
* read.
*/
- public static ChunkListing readFromProto(ProtoInputStream inputStream) throws IOException {
+ public static ChunkListingMap readFromProto(ProtoInputStream inputStream) throws IOException {
Map<ChunkHash, Entry> entries = new HashMap();
long start = 0;
@@ -54,12 +55,12 @@
}
}
- return new ChunkListing(entries);
+ return new ChunkListingMap(entries);
}
private final Map<ChunkHash, Entry> mChunksByHash;
- private ChunkListing(Map<ChunkHash, Entry> chunksByHash) {
+ private ChunkListingMap(Map<ChunkHash, Entry> chunksByHash) {
mChunksByHash = Collections.unmodifiableMap(new HashMap<>(chunksByHash));
}
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index 2756610..5b0de5e 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -26,6 +26,8 @@
void broadcastAlarmComplete(int recipientUid);
}
+ /** Returns true if AlarmManager is delaying alarms due to device idle. */
+ boolean isIdling();
public void removeAlarmsForUid(int uid);
public void registerInFlightListener(InFlightListener callback);
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 10b5327..a400cc3 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1991,6 +1991,11 @@
*/
private final class LocalService implements AlarmManagerInternal {
@Override
+ public boolean isIdling() {
+ return isIdlingImpl();
+ }
+
+ @Override
public void removeAlarmsForUid(int uid) {
synchronized (mLock) {
removeLocked(uid);
@@ -2823,6 +2828,12 @@
}
}
+ private boolean isIdlingImpl() {
+ synchronized (mLock) {
+ return mPendingIdleUntil != null;
+ }
+ }
+
AlarmManager.AlarmClockInfo getNextAlarmClockImpl(int userId) {
synchronized (mLock) {
return mNextAlarmClockForUser.get(userId);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fe4411c..d1cd072 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -38,7 +38,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
-import static android.net.NetworkStack.NETWORKSTACK_PACKAGE_NAME;
import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
import static android.net.shared.NetworkParcelableUtil.toStableParcelable;
import static android.os.Process.INVALID_UID;
@@ -2667,9 +2666,9 @@
}
@Override
- public void showProvisioningNotification(String action) {
+ public void showProvisioningNotification(String action, String packageName) {
final Intent intent = new Intent(action);
- intent.setPackage(NETWORKSTACK_PACKAGE_NAME);
+ intent.setPackage(packageName);
final PendingIntent pendingIntent;
// Only the system server can register notifications with package "android"
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 39030aa..6b66394 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -271,6 +271,7 @@
private static final int EVENT_BUFFER_SIZE = 100;
private AlarmManager mAlarmManager;
+ private AlarmManagerInternal mLocalAlarmManager;
private IBatteryStats mBatteryStats;
private ActivityManagerInternal mLocalActivityManager;
private ActivityTaskManagerInternal mLocalActivityTaskManager;
@@ -616,7 +617,8 @@
}
};
- private final AlarmManager.OnAlarmListener mDeepAlarmListener
+ @VisibleForTesting
+ final AlarmManager.OnAlarmListener mDeepAlarmListener
= new AlarmManager.OnAlarmListener() {
@Override
public void onAlarm() {
@@ -1874,6 +1876,7 @@
if (phase == PHASE_SYSTEM_SERVICES_READY) {
synchronized (this) {
mAlarmManager = mInjector.getAlarmManager();
+ mLocalAlarmManager = getLocalService(AlarmManagerInternal.class);
mBatteryStats = BatteryStatsService.getService();
mLocalActivityManager = getLocalService(ActivityManagerInternal.class);
mLocalActivityTaskManager = getLocalService(ActivityTaskManagerInternal.class);
@@ -2605,6 +2608,16 @@
// next natural time to come out of it.
}
+
+ /** Returns true if the screen is locked. */
+ @VisibleForTesting
+ boolean isKeyguardShowing() {
+ synchronized (this) {
+ return mScreenLocked;
+ }
+ }
+
+ @VisibleForTesting
void keyguardShowingLocked(boolean showing) {
if (DEBUG) Slog.i(TAG, "keyguardShowing=" + showing);
if (mScreenLocked != showing) {
@@ -2616,25 +2629,38 @@
}
}
+ @VisibleForTesting
void scheduleReportActiveLocked(String activeReason, int activeUid) {
Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, activeUid, 0, activeReason);
mHandler.sendMessage(msg);
}
void becomeActiveLocked(String activeReason, int activeUid) {
- if (DEBUG) Slog.i(TAG, "becomeActiveLocked, reason = " + activeReason);
+ becomeActiveLocked(activeReason, activeUid, mConstants.INACTIVE_TIMEOUT, true);
+ }
+
+ private void becomeActiveLocked(String activeReason, int activeUid,
+ long newInactiveTimeout, boolean changeLightIdle) {
+ if (DEBUG) {
+ Slog.i(TAG, "becomeActiveLocked, reason=" + activeReason
+ + ", changeLightIdle=" + changeLightIdle);
+ }
if (mState != STATE_ACTIVE || mLightState != STATE_ACTIVE) {
EventLogTags.writeDeviceIdle(STATE_ACTIVE, activeReason);
- EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
- scheduleReportActiveLocked(activeReason, activeUid);
mState = STATE_ACTIVE;
- mLightState = LIGHT_STATE_ACTIVE;
- mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
+ mInactiveTimeout = newInactiveTimeout;
mCurIdleBudget = 0;
mMaintenanceStartTime = 0;
resetIdleManagementLocked();
- resetLightIdleManagementLocked();
- addEvent(EVENT_NORMAL, activeReason);
+
+ if (changeLightIdle) {
+ EventLogTags.writeDeviceIdleLight(LIGHT_STATE_ACTIVE, activeReason);
+ mLightState = LIGHT_STATE_ACTIVE;
+ resetLightIdleManagementLocked();
+ // Only report active if light is also ACTIVE.
+ scheduleReportActiveLocked(activeReason, activeUid);
+ addEvent(EVENT_NORMAL, activeReason);
+ }
}
}
@@ -2654,49 +2680,81 @@
}
}
+ /** Sanity check to make sure DeviceIdleController and AlarmManager are on the same page. */
+ private void verifyAlarmStateLocked() {
+ if (mState == STATE_ACTIVE && mNextAlarmTime != 0) {
+ Slog.wtf(TAG, "mState=ACTIVE but mNextAlarmTime=" + mNextAlarmTime);
+ }
+ if (mState != STATE_IDLE && mLocalAlarmManager.isIdling()) {
+ Slog.wtf(TAG, "mState=" + stateToString(mState) + " but AlarmManager is idling");
+ }
+ if (mState == STATE_IDLE && !mLocalAlarmManager.isIdling()) {
+ Slog.wtf(TAG, "mState=IDLE but AlarmManager is not idling");
+ }
+ if (mLightState == LIGHT_STATE_ACTIVE && mNextLightAlarmTime != 0) {
+ Slog.wtf(TAG, "mLightState=ACTIVE but mNextLightAlarmTime is "
+ + TimeUtils.formatDuration(mNextLightAlarmTime - SystemClock.elapsedRealtime())
+ + " from now");
+ }
+ }
+
void becomeInactiveIfAppropriateLocked() {
- if (DEBUG) Slog.d(TAG, "becomeInactiveIfAppropriateLocked()");
- if ((!mScreenOn && !mCharging) || mForceIdle) {
- // Become inactive and determine if we will ultimately go idle.
- if (mDeepEnabled) {
- if (mQuickDozeActivated) {
- if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
- || mState == STATE_IDLE_MAINTENANCE) {
- // Already "idling". Don't want to restart the process.
- // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
- // values, so returning here is safe.
- return;
- }
- if (DEBUG) {
- Slog.d(TAG, "Moved from "
- + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
- }
- mState = STATE_QUICK_DOZE_DELAY;
- // Make sure any motion sensing or locating is stopped.
- resetIdleManagementLocked();
- // Wait a small amount of time in case something (eg: background service from
- // recently closed app) needs to finish running.
- scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
- EventLogTags.writeDeviceIdle(mState, "no activity");
- } else if (mState == STATE_ACTIVE) {
- mState = STATE_INACTIVE;
- if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
- resetIdleManagementLocked();
- long delay = mInactiveTimeout;
- if (shouldUseIdleTimeoutFactorLocked()) {
- delay = (long) (mPreIdleFactor * delay);
- }
- scheduleAlarmLocked(delay, false);
- EventLogTags.writeDeviceIdle(mState, "no activity");
+ verifyAlarmStateLocked();
+
+ final boolean isScreenBlockingInactive =
+ mScreenOn && (!mConstants.WAIT_FOR_UNLOCK || !mScreenLocked);
+ if (DEBUG) {
+ Slog.d(TAG, "becomeInactiveIfAppropriateLocked():"
+ + " isScreenBlockingInactive=" + isScreenBlockingInactive
+ + " (mScreenOn=" + mScreenOn
+ + ", WAIT_FOR_UNLOCK=" + mConstants.WAIT_FOR_UNLOCK
+ + ", mScreenLocked=" + mScreenLocked + ")"
+ + " mCharging=" + mCharging
+ + " mForceIdle=" + mForceIdle
+ );
+ }
+ if (!mForceIdle && (mCharging || isScreenBlockingInactive)) {
+ return;
+ }
+ // Become inactive and determine if we will ultimately go idle.
+ if (mDeepEnabled) {
+ if (mQuickDozeActivated) {
+ if (mState == STATE_QUICK_DOZE_DELAY || mState == STATE_IDLE
+ || mState == STATE_IDLE_MAINTENANCE) {
+ // Already "idling". Don't want to restart the process.
+ // mLightState can't be LIGHT_STATE_ACTIVE if mState is any of these 3
+ // values, so returning here is safe.
+ return;
}
+ if (DEBUG) {
+ Slog.d(TAG, "Moved from "
+ + stateToString(mState) + " to STATE_QUICK_DOZE_DELAY");
+ }
+ mState = STATE_QUICK_DOZE_DELAY;
+ // Make sure any motion sensing or locating is stopped.
+ resetIdleManagementLocked();
+ // Wait a small amount of time in case something (eg: background service from
+ // recently closed app) needs to finish running.
+ scheduleAlarmLocked(mConstants.QUICK_DOZE_DELAY_TIMEOUT, false);
+ EventLogTags.writeDeviceIdle(mState, "no activity");
+ } else if (mState == STATE_ACTIVE) {
+ mState = STATE_INACTIVE;
+ if (DEBUG) Slog.d(TAG, "Moved from STATE_ACTIVE to STATE_INACTIVE");
+ resetIdleManagementLocked();
+ long delay = mInactiveTimeout;
+ if (shouldUseIdleTimeoutFactorLocked()) {
+ delay = (long) (mPreIdleFactor * delay);
+ }
+ scheduleAlarmLocked(delay, false);
+ EventLogTags.writeDeviceIdle(mState, "no activity");
}
- if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
- mLightState = LIGHT_STATE_INACTIVE;
- if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
- resetLightIdleManagementLocked();
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
- EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
- }
+ }
+ if (mLightState == LIGHT_STATE_ACTIVE && mLightEnabled) {
+ mLightState = LIGHT_STATE_INACTIVE;
+ if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
+ resetLightIdleManagementLocked();
+ scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+ EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -3216,33 +3274,10 @@
// The device is not yet active, so we want to go back to the pending idle
// state to wait again for no motion. Note that we only monitor for motion
// after moving out of the inactive state, so no need to worry about that.
- boolean becomeInactive = false;
- if (mState != STATE_ACTIVE) {
- // Motion shouldn't affect light state, if it's already in doze-light or maintenance
- boolean lightIdle = mLightState == LIGHT_STATE_IDLE
- || mLightState == LIGHT_STATE_WAITING_FOR_NETWORK
- || mLightState == LIGHT_STATE_IDLE_MAINTENANCE;
- if (!lightIdle) {
- // Only switch to active state if we're not in either idle state
- scheduleReportActiveLocked(type, Process.myUid());
- addEvent(EVENT_NORMAL, type);
- }
- mActiveReason = ACTIVE_REASON_MOTION;
- mState = STATE_ACTIVE;
- mInactiveTimeout = timeout;
- mCurIdleBudget = 0;
- mMaintenanceStartTime = 0;
- EventLogTags.writeDeviceIdle(mState, type);
- becomeInactive = true;
- updateActiveConstraintsLocked();
- }
- if (mLightState == LIGHT_STATE_OVERRIDE) {
- // We went out of light idle mode because we had started deep idle mode... let's
- // now go back and reset things so we resume light idling if appropriate.
- mLightState = LIGHT_STATE_ACTIVE;
- EventLogTags.writeDeviceIdleLight(mLightState, type);
- becomeInactive = true;
- }
+ final boolean becomeInactive = mState != STATE_ACTIVE
+ || mLightState == LIGHT_STATE_OVERRIDE;
+ // We only want to change the IDLE state if it's OVERRIDE.
+ becomeActiveLocked(type, Process.myUid(), timeout, mLightState == LIGHT_STATE_OVERRIDE);
if (becomeInactive) {
becomeInactiveIfAppropriateLocked();
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index a14fd17..19bdc09 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -96,6 +96,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -180,6 +181,7 @@
// into a single coherent structure.
private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
+ private final VersionedBroadcastListener mDefaultSubscriptionChange;
private final TetheringDependencies mDeps;
private final EntitlementManager mEntitlementMgr;
@@ -232,6 +234,15 @@
mEntitlementMgr.reevaluateSimCardProvisioning();
});
+ filter = new IntentFilter();
+ filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
+ mDefaultSubscriptionChange = new VersionedBroadcastListener(
+ "DefaultSubscriptionChangeListener", mContext, smHandler, filter,
+ (Intent ignored) -> {
+ mLog.log("OBSERVED default data subscription change");
+ updateConfiguration();
+ mEntitlementMgr.reevaluateSimCardProvisioning();
+ });
mStateReceiver = new StateReceiver();
// Load tethering configuration.
@@ -242,6 +253,7 @@
private void startStateMachineUpdaters() {
mCarrierConfigChange.startListening();
+ mDefaultSubscriptionChange.startListening();
final Handler handler = mTetherMasterSM.getHandler();
IntentFilter filter = new IntentFilter();
@@ -270,7 +282,8 @@
// NOTE: This is always invoked on the mLooper thread.
private void updateConfiguration() {
- mConfig = new TetheringConfiguration(mContext, mLog);
+ final int subId = mDeps.getDefaultDataSubscriptionId();
+ mConfig = new TetheringConfiguration(mContext, mLog, subId);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
mEntitlementMgr.updateConfiguration(mConfig);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 1e6bb04..8a46ff1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -26,8 +26,8 @@
import static com.android.internal.R.array.config_mobile_hotspot_provision_app;
import static com.android.internal.R.array.config_tether_bluetooth_regexs;
import static com.android.internal.R.array.config_tether_dhcp_range;
-import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_upstream_types;
+import static com.android.internal.R.array.config_tether_usb_regexs;
import static com.android.internal.R.array.config_tether_wifi_regexs;
import static com.android.internal.R.bool.config_tether_upstream_automatic;
import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
@@ -38,6 +38,7 @@
import android.net.ConnectivityManager;
import android.net.util.SharedLog;
import android.provider.Settings;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -100,29 +101,34 @@
public final String[] provisioningApp;
public final String provisioningAppNoUi;
- public TetheringConfiguration(Context ctx, SharedLog log) {
+ public final int subId;
+
+ public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
- tetherableUsbRegexs = getResourceStringArray(ctx, config_tether_usb_regexs);
+ subId = id;
+ Resources res = getResources(ctx, subId);
+
+ tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs);
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
- tetherableWifiRegexs = getResourceStringArray(ctx, config_tether_wifi_regexs);
- tetherableBluetoothRegexs = getResourceStringArray(ctx, config_tether_bluetooth_regexs);
+ tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
+ tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
dunCheck = checkDunRequired(ctx);
configLog.log("DUN check returned: " + dunCheckString(dunCheck));
- chooseUpstreamAutomatically = getResourceBoolean(ctx, config_tether_upstream_automatic);
- preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
+ chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic);
+ preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, dunCheck);
isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
- legacyDhcpRanges = getLegacyDhcpRanges(ctx);
+ legacyDhcpRanges = getLegacyDhcpRanges(res);
defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
enableLegacyDhcpServer = getEnableLegacyDhcpServer(ctx);
- provisioningApp = getResourceStringArray(ctx, config_mobile_hotspot_provision_app);
- provisioningAppNoUi = getProvisioningAppNoUi(ctx);
+ provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app);
+ provisioningAppNoUi = getProvisioningAppNoUi(res);
configLog.log(toString());
}
@@ -144,6 +150,9 @@
}
public void dump(PrintWriter pw) {
+ pw.print("subId: ");
+ pw.println(subId);
+
dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
@@ -169,6 +178,7 @@
public String toString() {
final StringJoiner sj = new StringJoiner(" ");
+ sj.add(String.format("subId:%d", subId));
sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
sj.add(String.format("tetherableBluetoothRegexs:%s",
@@ -235,8 +245,8 @@
}
}
- private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
- final int ifaceTypes[] = ctx.getResources().getIntArray(config_tether_upstream_types);
+ private static Collection<Integer> getUpstreamIfaceTypes(Resources res, int dunCheck) {
+ final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types);
final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
for (int i : ifaceTypes) {
switch (i) {
@@ -286,33 +296,33 @@
return false;
}
- private static String[] getLegacyDhcpRanges(Context ctx) {
- final String[] fromResource = getResourceStringArray(ctx, config_tether_dhcp_range);
+ private static String[] getLegacyDhcpRanges(Resources res) {
+ final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range);
if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
return fromResource;
}
return copy(LEGACY_DHCP_DEFAULT_RANGE);
}
- private static String getProvisioningAppNoUi(Context ctx) {
+ private static String getProvisioningAppNoUi(Resources res) {
try {
- return ctx.getResources().getString(config_mobile_hotspot_provision_app_no_ui);
+ return res.getString(config_mobile_hotspot_provision_app_no_ui);
} catch (Resources.NotFoundException e) {
return "";
}
}
- private static boolean getResourceBoolean(Context ctx, int resId) {
+ private static boolean getResourceBoolean(Resources res, int resId) {
try {
- return ctx.getResources().getBoolean(resId);
+ return res.getBoolean(resId);
} catch (Resources.NotFoundException e404) {
return false;
}
}
- private static String[] getResourceStringArray(Context ctx, int resId) {
+ private static String[] getResourceStringArray(Resources res, int resId) {
try {
- final String[] strArray = ctx.getResources().getStringArray(resId);
+ final String[] strArray = res.getStringArray(resId);
return (strArray != null) ? strArray : EMPTY_STRING_ARRAY;
} catch (Resources.NotFoundException e404) {
return EMPTY_STRING_ARRAY;
@@ -325,6 +335,19 @@
return intVal != 0;
}
+ private Resources getResources(Context ctx, int subId) {
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return getResourcesForSubIdWrapper(ctx, subId);
+ } else {
+ return ctx.getResources();
+ }
+ }
+
+ @VisibleForTesting
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return SubscriptionManager.getResourcesForSubId(ctx, subId);
+ }
+
private static String[] copy(String[] strarray) {
return Arrays.copyOf(strarray, strarray.length);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 6d6f81e..3fddac1 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,6 +21,7 @@
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
+import android.telephony.SubscriptionManager;
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
@@ -85,4 +86,11 @@
SharedLog log, MockableSystemProperties systemProperties) {
return new EntitlementManager(ctx, target, log, systemProperties);
}
+
+ /**
+ * Get default data subscription id to build TetheringConfiguration.
+ */
+ public int getDefaultDataSubscriptionId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 8171ad6..45f169c 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -558,14 +558,16 @@
if (setting != null) {
switch (setting) {
case Secure.NIGHT_DISPLAY_ACTIVATED:
- final boolean activated = isNightDisplayActivatedSetting();
+ final boolean activated = mNightDisplayTintController
+ .isActivatedSetting();
if (mNightDisplayTintController.isActivatedStateNotSet()
|| mNightDisplayTintController.isActivated() != activated) {
- mNightDisplayTintController.onActivated(activated);
+ mNightDisplayTintController.setActivated(activated);
}
break;
case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
- final int temperature = getNightDisplayColorTemperatureSetting();
+ final int temperature = mNightDisplayTintController
+ .getColorTemperatureSetting();
if (mNightDisplayTintController.getColorTemperature()
!= temperature) {
mNightDisplayTintController
@@ -641,14 +643,16 @@
// Prepare the night display color transformation matrix.
mNightDisplayTintController
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
- mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
+ mNightDisplayTintController
+ .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
// Initialize the current auto mode.
onNightDisplayAutoModeChanged(getNightDisplayAutoModeInternal());
// Force the initialization of the current saved activation state.
if (mNightDisplayTintController.isActivatedStateNotSet()) {
- mNightDisplayTintController.onActivated(isNightDisplayActivatedSetting());
+ mNightDisplayTintController
+ .setActivated(mNightDisplayTintController.isActivatedSetting());
}
}
@@ -728,7 +732,8 @@
if (mNightDisplayTintController.isAvailable(getContext())) {
mNightDisplayTintController
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
- mNightDisplayTintController.setMatrix(getNightDisplayColorTemperatureSetting());
+ mNightDisplayTintController
+ .setMatrix(mNightDisplayTintController.getColorTemperatureSetting());
}
updateDisplayWhiteBalanceStatus();
@@ -1046,8 +1051,7 @@
*
* See {@link com.android.server.display.DisplayTransformManager}
*/
- private @ColorMode
- int getCurrentColorModeFromSystemProperties() {
+ private @ColorMode int getCurrentColorModeFromSystemProperties() {
final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
if (displayColorSetting == 0) {
return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
@@ -1104,33 +1108,6 @@
pw.println("Color mode: " + getColorModeInternal());
}
- private boolean isNightDisplayActivatedSetting() {
- return Secure.getIntForUser(getContext().getContentResolver(),
- Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
- }
-
- private int getNightDisplayColorTemperatureSetting() {
- return clampNightDisplayColorTemperature(Secure.getIntForUser(
- getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, NOT_SET,
- mCurrentUser));
- }
-
- private int clampNightDisplayColorTemperature(int colorTemperature) {
- if (colorTemperature == NOT_SET) {
- colorTemperature = getContext().getResources().getInteger(
- R.integer.config_nightDisplayColorTemperatureDefault);
- }
- final int minimumTemperature = ColorDisplayManager.getMinimumColorTemperature(getContext());
- final int maximumTemperature = ColorDisplayManager.getMaximumColorTemperature(getContext());
- if (colorTemperature < minimumTemperature) {
- colorTemperature = minimumTemperature;
- } else if (colorTemperature > maximumTemperature) {
- colorTemperature = maximumTemperature;
- }
-
- return colorTemperature;
- }
-
private abstract class NightDisplayAutoMode {
public abstract void onActivated(boolean activated);
@@ -1177,7 +1154,7 @@
// Maintain the existing activated state if within the current period.
if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
&& (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
- activate = isNightDisplayActivatedSetting();
+ activate = mNightDisplayTintController.isActivatedSetting();
}
}
@@ -1273,7 +1250,7 @@
// Maintain the existing activated state if within the current period.
if (mLastActivatedTime.isBefore(now) && (mLastActivatedTime.isBefore(sunrise)
^ mLastActivatedTime.isBefore(sunset))) {
- activate = isNightDisplayActivatedSetting();
+ activate = mNightDisplayTintController.isActivatedSetting();
}
}
@@ -1472,9 +1449,11 @@
if (isActivatedStateNotSet() || activationStateChanged) {
super.setActivated(activated);
- Secure.putIntForUser(getContext().getContentResolver(),
- Secure.NIGHT_DISPLAY_ACTIVATED,
- activated ? 1 : 0, mCurrentUser);
+ if (isActivatedSetting() != activated) {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED,
+ activated ? 1 : 0, mCurrentUser);
+ }
onActivated(activated);
}
}
@@ -1492,7 +1471,7 @@
return mIsAvailable;
}
- void onActivated(boolean activated) {
+ private void onActivated(boolean activated) {
Slog.i(TAG, activated ? "Turning on night display" : "Turning off night display");
if (mNightDisplayAutoMode != null) {
mNightDisplayAutoMode.onActivated(activated);
@@ -1507,7 +1486,7 @@
int getColorTemperature() {
return mColorTemp != null ? clampNightDisplayColorTemperature(mColorTemp)
- : getNightDisplayColorTemperatureSetting();
+ : getColorTemperatureSetting();
}
boolean setColorTemperature(int temperature) {
@@ -1522,6 +1501,36 @@
setMatrix(temperature);
mHandler.sendEmptyMessage(MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE);
}
+
+ boolean isActivatedSetting() {
+ return Secure.getIntForUser(getContext().getContentResolver(),
+ Secure.NIGHT_DISPLAY_ACTIVATED, 0, mCurrentUser) == 1;
+ }
+
+ int getColorTemperatureSetting() {
+ return clampNightDisplayColorTemperature(Secure.getIntForUser(
+ getContext().getContentResolver(), Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
+ NOT_SET,
+ mCurrentUser));
+ }
+
+ private int clampNightDisplayColorTemperature(int colorTemperature) {
+ if (colorTemperature == NOT_SET) {
+ colorTemperature = getContext().getResources().getInteger(
+ R.integer.config_nightDisplayColorTemperatureDefault);
+ }
+ final int minimumTemperature = ColorDisplayManager
+ .getMinimumColorTemperature(getContext());
+ final int maximumTemperature = ColorDisplayManager
+ .getMaximumColorTemperature(getContext());
+ if (colorTemperature < minimumTemperature) {
+ colorTemperature = minimumTemperature;
+ } else if (colorTemperature > maximumTemperature) {
+ colorTemperature = maximumTemperature;
+ }
+
+ return colorTemperature;
+ }
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 144f2b6..96ba084 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -667,13 +667,19 @@
final int mSequenceNumber;
final long mTimestamp;
final long mWallTime;
+ @UserIdInt
+ final int mImeUserId;
@NonNull
final IBinder mImeToken;
+ final int mImeDisplayId;
@NonNull
final String mImeId;
@StartInputReason
final int mStartInputReason;
final boolean mRestarting;
+ @UserIdInt
+ final int mTargetUserId;
+ final int mTargetDisplayId;
@Nullable
final IBinder mTargetWindow;
@NonNull
@@ -682,17 +688,22 @@
final int mTargetWindowSoftInputMode;
final int mClientBindSequenceNumber;
- StartInputInfo(@NonNull IBinder imeToken, @NonNull String imeId,
- @StartInputReason int startInputReason, boolean restarting,
- @Nullable IBinder targetWindow, @NonNull EditorInfo editorInfo,
- @SoftInputModeFlags int targetWindowSoftInputMode, int clientBindSequenceNumber) {
+ StartInputInfo(@UserIdInt int imeUserId, @NonNull IBinder imeToken, int imeDisplayId,
+ @NonNull String imeId, @StartInputReason int startInputReason, boolean restarting,
+ @UserIdInt int targetUserId, int targetDisplayId, @Nullable IBinder targetWindow,
+ @NonNull EditorInfo editorInfo, @SoftInputModeFlags int targetWindowSoftInputMode,
+ int clientBindSequenceNumber) {
mSequenceNumber = sSequenceNumber.getAndIncrement();
mTimestamp = SystemClock.uptimeMillis();
mWallTime = System.currentTimeMillis();
+ mImeUserId = imeUserId;
mImeToken = imeToken;
+ mImeDisplayId = imeDisplayId;
mImeId = imeId;
mStartInputReason = startInputReason;
mRestarting = restarting;
+ mTargetUserId = targetUserId;
+ mTargetDisplayId = targetDisplayId;
mTargetWindow = targetWindow;
mEditorInfo = editorInfo;
mTargetWindowSoftInputMode = targetWindowSoftInputMode;
@@ -749,13 +760,19 @@
int mSequenceNumber;
long mTimestamp;
long mWallTime;
+ @UserIdInt
+ int mImeUserId;
@NonNull
String mImeTokenString;
+ int mImeDisplayId;
@NonNull
String mImeId;
@StartInputReason
int mStartInputReason;
boolean mRestarting;
+ @UserIdInt
+ int mTargetUserId;
+ int mTargetDisplayId;
@NonNull
String mTargetWindowString;
@NonNull
@@ -772,12 +789,16 @@
mSequenceNumber = original.mSequenceNumber;
mTimestamp = original.mTimestamp;
mWallTime = original.mWallTime;
+ mImeUserId = original.mImeUserId;
// Intentionally convert to String so as not to keep a strong reference to a Binder
// object.
mImeTokenString = String.valueOf(original.mImeToken);
+ mImeDisplayId = original.mImeDisplayId;
mImeId = original.mImeId;
mStartInputReason = original.mStartInputReason;
mRestarting = original.mRestarting;
+ mTargetUserId = original.mTargetUserId;
+ mTargetDisplayId = original.mTargetDisplayId;
// Intentionally convert to String so as not to keep a strong reference to a Binder
// object.
mTargetWindowString = String.valueOf(original.mTargetWindow);
@@ -821,11 +842,15 @@
+ " restarting=" + entry.mRestarting);
pw.print(prefix);
- pw.println(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
+ pw.print(" imeToken=" + entry.mImeTokenString + " [" + entry.mImeId + "]");
+ pw.print(" imeUserId=" + entry.mImeUserId);
+ pw.println(" imeDisplayId=" + entry.mImeDisplayId);
pw.print(prefix);
pw.println(" targetWin=" + entry.mTargetWindowString
+ " [" + entry.mEditorInfo.packageName + "]"
+ + " targetUserId=" + entry.mTargetUserId
+ + " targetDisplayId=" + entry.mTargetDisplayId
+ " clientBindSeq=" + entry.mClientBindSequenceNumber);
pw.print(prefix);
@@ -1904,9 +1929,10 @@
}
final Binder startInputToken = new Binder();
- final StartInputInfo info = new StartInputInfo(mCurToken, mCurId, startInputReason,
- !initial, mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode,
- mCurSeq);
+ final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(), mCurToken,
+ mCurTokenDisplayId, mCurId, startInputReason, !initial,
+ UserHandle.getUserId(mCurClient.uid), mCurClient.selfReportedDisplayId,
+ mCurFocusedWindow, mCurAttribute, mCurFocusedWindowSoftInputMode, mCurSeq);
mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
mStartInputHistory.addEntry(info);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index bfa539c..2036ed7 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -645,7 +645,7 @@
grantPermissionsToSystemPackage(packageName, userId,
CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
- SENSORS_PERMISSIONS, STORAGE_PERMISSIONS);
+ SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
grantSystemFixedPermissionsToSystemPackage(packageName, userId,
LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4faf910..0251efb 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -75,12 +75,12 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.EMPTY;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@@ -2610,10 +2610,6 @@
}
}
- int getRequestedOrientation() {
- return getOrientation();
- }
-
void setRequestedOrientation(int requestedOrientation) {
setOrientation(requestedOrientation, mayFreezeScreenLocked(app));
mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
@@ -2641,7 +2637,7 @@
int getOrientation() {
if (mAppWindowToken == null) {
- return SCREEN_ORIENTATION_UNSPECIFIED;
+ return info.screenOrientation;
}
return mAppWindowToken.getOrientationIgnoreVisibility();
@@ -2677,25 +2673,92 @@
mLastReportedConfiguration.setConfiguration(global, override);
}
+ /**
+ * Get the configuration orientation by the requested screen orientation
+ * ({@link ActivityInfo.ScreenOrientation}) of this activity.
+ *
+ * @return orientation in ({@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT},
+ * {@link #ORIENTATION_UNDEFINED}).
+ */
+ int getRequestedConfigurationOrientation() {
+ final int screenOrientation = getOrientation();
+ if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ // NOSENSOR means the display's "natural" orientation, so return that.
+ final ActivityDisplay display = getDisplay();
+ if (display != null && display.mDisplayContent != null) {
+ return display.mDisplayContent.getNaturalOrientation();
+ }
+ } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
+ // LOCKED means the activity's orientation remains unchanged, so return existing value.
+ return getConfiguration().orientation;
+ } else if (isFixedOrientationLandscape(screenOrientation)) {
+ return ORIENTATION_LANDSCAPE;
+ } else if (isFixedOrientationPortrait(screenOrientation)) {
+ return ORIENTATION_PORTRAIT;
+ }
+ return ORIENTATION_UNDEFINED;
+ }
+
+ /**
+ * Indicates the activity will keep the bounds and screen configuration when it was first
+ * launched, no matter how its parent changes.
+ *
+ * @return {@code true} if this activity is declared as non-resizable and fixed orientation or
+ * aspect ratio.
+ */
+ private boolean inSizeCompatMode() {
+ return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio())
+ // The configuration of non-standard type should be enforced by system.
+ && isActivityTypeStandard()
+ && !mAtmService.mForceResizableActivities;
+ }
+
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private void updateOverrideConfiguration() {
+ final boolean inSizeCompatMode = inSizeCompatMode();
+ if (inSizeCompatMode) {
+ if (!matchParentBounds()) {
+ // The override configuration is set only once in size compatible mode.
+ return;
+ }
+ if (!hasProcess() && !isConfigurationCompatible(task.getConfiguration())) {
+ // Don't compute when launching in fullscreen and the fixed orientation is not the
+ // current orientation. It is more accurately to compute the override bounds from
+ // the updated configuration after the fixed orientation is applied.
+ return;
+ }
+ }
+
computeBounds(mTmpBounds);
+ if (inSizeCompatMode && mTmpBounds.isEmpty()) {
+ mTmpBounds.set(task.getWindowConfiguration().getBounds());
+ }
if (mTmpBounds.equals(getRequestedOverrideBounds())) {
+ // The bounds is not changed or the activity is resizable (both the 2 bounds are empty).
return;
}
- setBounds(mTmpBounds);
-
- // Bounds changed...update configuration to match.
- if (!matchParentBounds()) {
- mTmpConfig.setTo(getRequestedOverrideConfiguration());
- task.computeConfigResourceOverrides(mTmpConfig, task.getParent().getConfiguration());
- } else {
- mTmpConfig.unset();
+ final Configuration overrideConfig = mTmpConfig;
+ overrideConfig.unset();
+ if (!mTmpBounds.isEmpty()) {
+ overrideConfig.windowConfiguration.setBounds(mTmpBounds);
+ if (inSizeCompatMode) {
+ // Ensure the screen related fields are set. It is used to prevent activity relaunch
+ // when moving between displays. For screenWidthDp and screenWidthDp, because they
+ // are relative to bounds and density, they will be calculated in
+ // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
+ // relatively fixed.
+ final Configuration srcConfig = task.getConfiguration();
+ overrideConfig.colorMode = srcConfig.colorMode;
+ overrideConfig.densityDpi = srcConfig.densityDpi;
+ overrideConfig.screenLayout = srcConfig.screenLayout;
+ // The smallest screen width is the short side of screen bounds. Because the bounds
+ // and density won't be changed, smallestScreenWidthDp is also fixed.
+ overrideConfig.smallestScreenWidthDp = srcConfig.smallestScreenWidthDp;
+ }
}
-
- onRequestedOverrideConfigurationChanged(mTmpConfig);
+ onRequestedOverrideConfigurationChanged(overrideConfig);
}
@Override
@@ -2707,6 +2770,86 @@
// layout traversals.
mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
getResolvedOverrideConfiguration().seq = mConfigurationSeq;
+
+ if (matchParentBounds()) {
+ return;
+ }
+
+ final Configuration resolvedConfig = getResolvedOverrideConfiguration();
+ if (!inSizeCompatMode()) {
+ computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
+ ORIENTATION_UNDEFINED, true /* insideParentBounds */);
+ return;
+ }
+
+ final Configuration displayConfig = getDisplay().getConfiguration();
+ int orientation = getConfiguration().orientation;
+ if (orientation != displayConfig.orientation && isConfigurationCompatible(displayConfig)) {
+ // The activity is compatible to apply the orientation change or it requests different
+ // fixed orientation.
+ orientation = displayConfig.orientation;
+ } else {
+ if (resolvedConfig.windowConfiguration.getAppBounds() != null) {
+ // Keep the computed resolved override configuration.
+ return;
+ }
+ final int requestedOrientation = getRequestedConfigurationOrientation();
+ if (requestedOrientation != ORIENTATION_UNDEFINED) {
+ orientation = requestedOrientation;
+ }
+ }
+
+ // Adjust the bounds to match the current orientation.
+ if (orientation != ORIENTATION_UNDEFINED) {
+ final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();
+ final int longSide = Math.max(resolvedBounds.height(), resolvedBounds.width());
+ final int shortSide = Math.min(resolvedBounds.height(), resolvedBounds.width());
+ final boolean toBeLandscape = orientation == ORIENTATION_LANDSCAPE;
+ final int width = toBeLandscape ? longSide : shortSide;
+ final int height = toBeLandscape ? shortSide : longSide;
+ // Assume the bounds is always started from zero because the size may be bigger than its
+ // parent (task ~ display). The actual letterboxing will be done by surface offset.
+ resolvedBounds.set(0, 0, width, height);
+ }
+
+ // In size compatible mode, activity is allowed to have larger bounds than its parent.
+ computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, orientation,
+ false /* insideParentBounds */);
+ }
+
+ private void computeConfigResourceOverrides(Configuration inOutConfig,
+ Configuration parentConfig, int orientation, boolean insideParentBounds) {
+ // Set the real orientation or undefined value to ensure the output orientation won't be the
+ // old value. Also reset app bounds so it will be updated according to bounds.
+ inOutConfig.orientation = orientation;
+ final Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds != null) {
+ outAppBounds.setEmpty();
+ }
+
+ // TODO(b/112288258): Remove below calculation because the position information in bounds
+ // will be replaced by the offset of surface.
+ final Rect appBounds = parentConfig.windowConfiguration.getAppBounds();
+ if (appBounds != null) {
+ final Rect outBounds = inOutConfig.windowConfiguration.getBounds();
+ final int activityWidth = outBounds.width();
+ final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
+ if (navBarPosition == NAV_BAR_LEFT) {
+ // Position the activity frame on the opposite side of the nav bar.
+ outBounds.left = appBounds.right - activityWidth;
+ outBounds.right = appBounds.right;
+ } else if (navBarPosition == NAV_BAR_RIGHT) {
+ // Position the activity frame on the opposite side of the nav bar.
+ outBounds.left = 0;
+ outBounds.right = activityWidth + appBounds.left;
+ } else if (appBounds.width() > activityWidth) {
+ // Horizontally center the frame.
+ outBounds.left = appBounds.left + (appBounds.width() - activityWidth) / 2;
+ outBounds.right = outBounds.left + activityWidth;
+ }
+ }
+
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, insideParentBounds);
}
@Override
@@ -2739,8 +2882,7 @@
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
- final int orientation = mAppWindowToken != null
- ? getOrientation() : info.screenOrientation;
+ final int orientation = getOrientation();
if (isFixedOrientationPortrait(orientation)
&& config.orientation != ORIENTATION_PORTRAIT) {
return false;
@@ -2822,21 +2964,6 @@
// away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
// bounds would end up too small.
outBounds.set(0, 0, activityWidth + appBounds.left, activityHeight + appBounds.top);
-
- final int navBarPosition = mAtmService.mWindowManager.getNavBarPosition(getDisplayId());
- if (navBarPosition == NAV_BAR_LEFT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = appBounds.right - activityWidth;
- outBounds.right = appBounds.right;
- } else if (navBarPosition == NAV_BAR_RIGHT) {
- // Position the activity frame on the opposite side of the nav bar.
- outBounds.left = 0;
- outBounds.right = activityWidth + appBounds.left;
- } else {
- // Horizontally center the frame.
- outBounds.left = appBounds.left + (containingAppWidth - activityWidth) / 2;
- outBounds.right = outBounds.left + activityWidth;
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index cc78588..932cfd3 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -5631,6 +5631,19 @@
}
}
+ /**
+ * Get current bounds of this stack, return empty when it is unavailable.
+ * @see TaskStack#getAnimationOrCurrentBounds(Rect)
+ */
+ void getAnimationOrCurrentBounds(Rect outBounds) {
+ final TaskStack stack = getTaskStack();
+ if (stack == null) {
+ outBounds.setEmpty();
+ return;
+ }
+ stack.getAnimationOrCurrentBounds(outBounds);
+ }
+
private boolean skipResizeAnimation(boolean toFullscreen) {
if (!toFullscreen) {
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 678a896..c33a2c1 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -989,8 +989,8 @@
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return false;
}
- // don't abort if the callingPackage is a device owner
- if (mService.getDevicePolicyManager().isDeviceOwnerApp(callingPackage)) {
+ // don't abort if the callingPackage is the device owner
+ if (mService.isDeviceOwner(callingPackage)) {
return false;
}
// anything that has fallen through would currently be aborted
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 1a5e6a1..5a20959 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -492,4 +492,9 @@
/** Returns true if uid has a visible window or its process is in a top state. */
public abstract boolean isUidForeground(int uid);
+
+ /**
+ * Called by DevicePolicyManagerService to set the package name of the device owner.
+ */
+ public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 875fc4e..258819f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -151,7 +151,6 @@
import android.app.WaitResult;
import android.app.WindowConfiguration;
import android.app.admin.DevicePolicyCache;
-import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.usage.UsageStatsManagerInternal;
@@ -363,7 +362,6 @@
WindowManagerService mWindowManager;
private UserManagerService mUserManager;
private AppOpsService mAppOpsService;
- private DevicePolicyManager mDpm;
/** All active uids in the system. */
private final SparseArray<Integer> mActiveUids = new SparseArray<>();
private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
@@ -623,6 +621,8 @@
private FontScaleSettingObserver mFontScaleSettingObserver;
+ private String mDeviceOwnerPackageName;
+
private final class FontScaleSettingObserver extends ContentObserver {
private final Uri mFontScaleUri = Settings.System.getUriFor(FONT_SCALE);
private final Uri mHideErrorDialogsUri = Settings.Global.getUriFor(HIDE_ERROR_DIALOGS);
@@ -838,13 +838,6 @@
return mAppOpsService;
}
- DevicePolicyManager getDevicePolicyManager() {
- if (mDpm == null) {
- mDpm = mContext.getSystemService(DevicePolicyManager.class);
- }
- return mDpm;
- }
-
boolean hasUserRestriction(String restriction, int userId) {
return getUserManager().hasUserRestriction(restriction, userId);
}
@@ -1720,7 +1713,7 @@
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return r.getRequestedOrientation();
+ return r.getOrientation();
}
}
@@ -2452,6 +2445,40 @@
}
}
+ @Override
+ public void offsetPinnedStackBounds(int stackId, Rect compareBounds, int xOffset, int yOffset,
+ int animationDuration) {
+ enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "offsetPinnedStackBounds()");
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ if (xOffset == 0 && yOffset == 0) {
+ return;
+ }
+ final ActivityStack stack = mRootActivityContainer.getStack(stackId);
+ if (stack == null) {
+ Slog.w(TAG, "offsetPinnedStackBounds: stackId " + stackId + " not found.");
+ return;
+ }
+ if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) {
+ throw new IllegalArgumentException("Stack: " + stackId
+ + " doesn't support animated resize.");
+ }
+ final Rect destBounds = new Rect();
+ stack.getAnimationOrCurrentBounds(destBounds);
+ if (!destBounds.isEmpty() || !destBounds.equals(compareBounds)) {
+ Slog.w(TAG, "The current stack bounds does not matched! It may be obsolete.");
+ return;
+ }
+ destBounds.offset(xOffset, yOffset);
+ stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+ animationDuration, false /* fromFullscreen */);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
/**
* Moves the specified task to the primary-split-screen stack.
*
@@ -5691,6 +5718,17 @@
|| mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
}
+ boolean isDeviceOwner(String packageName) {
+ if (packageName == null) {
+ return false;
+ }
+ return packageName.equals(mDeviceOwnerPackageName);
+ }
+
+ void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+ mDeviceOwnerPackageName = deviceOwnerPkg;
+ }
+
/**
* @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
* the whitelist
@@ -7108,5 +7146,12 @@
return ActivityTaskManagerService.this.isUidForeground(uid);
}
}
+
+ @Override
+ public void setDeviceOwnerPackageName(String deviceOwnerPkg) {
+ synchronized (mGlobalLock) {
+ ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index bcf6aba..88c8b95 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -239,6 +239,17 @@
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
+ /**
+ * The scale to fit at least one side of the activity to its parent. If the activity uses
+ * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5.
+ */
+ private float mSizeCompatScale = 1f;
+ /**
+ * The bounds in global coordinates for activity in size compatibility mode.
+ * @see ActivityRecord#inSizeCompatMode
+ */
+ private Rect mSizeCompatBounds;
+
private boolean mDisablePreviewScreenshots;
private Task mLastParent;
@@ -884,6 +895,10 @@
dc.setFocusedApp(null);
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
}
+ if (mLetterbox != null) {
+ mLetterbox.destroy();
+ mLetterbox = null;
+ }
if (!delayed) {
updateReportedVisibilityLocked();
@@ -1297,6 +1312,10 @@
}
}
}
+
+ if (prevDc != mDisplayContent && mLetterbox != null) {
+ mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
+ }
}
/**
@@ -1555,11 +1574,52 @@
return mOrientation;
}
+ /** @return {@code true} if the compatibility bounds is taking effect. */
+ boolean inSizeCompatMode() {
+ return mSizeCompatBounds != null;
+ }
+
+ @Override
+ float getSizeCompatScale() {
+ return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale();
+ }
+
+ /**
+ * @return Non-empty bounds if the activity has override bounds.
+ * @see ActivityRecord#resolveOverrideConfiguration(Configuration)
+ */
+ Rect getResolvedOverrideBounds() {
+ // Get bounds from resolved override configuration because it is computed with orientation.
+ return getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+ }
+
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
final int prevWinMode = getWindowingMode();
mTmpPrevBounds.set(getBounds());
super.onConfigurationChanged(newParentConfig);
+
+ final Task task = getTask();
+ final Rect overrideBounds = getResolvedOverrideBounds();
+ if (task != null && !overrideBounds.isEmpty()
+ // If the changes come from change-listener, the incoming parent configuration is
+ // still the old one. Make sure their orientations are the same to reduce computing
+ // the compatibility bounds for the intermediate state.
+ && getResolvedOverrideConfiguration().orientation == newParentConfig.orientation) {
+ final Rect taskBounds = task.getBounds();
+ // Since we only center the activity horizontally, if only the fixed height is smaller
+ // than its container, the override bounds don't need to take effect.
+ if ((overrideBounds.width() != taskBounds.width()
+ || overrideBounds.height() > taskBounds.height())) {
+ calculateCompatBoundsTransformation(newParentConfig);
+ updateSurfacePosition();
+ } else if (mSizeCompatBounds != null) {
+ mSizeCompatBounds = null;
+ mSizeCompatScale = 1f;
+ updateSurfacePosition();
+ }
+ }
+
final int winMode = getWindowingMode();
if (prevWinMode == winMode) {
@@ -1657,8 +1717,10 @@
final ActivityManager.TaskSnapshot snapshot = snapshotCtrl.getSnapshot(
getTask().mTaskId, getTask().mUserId, false /* restoreFromDisk */,
false /* reducedResolution */);
- mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
- true /* relative */);
+ if (snapshot != null) {
+ mThumbnail = new AppWindowThumbnail(t, this, snapshot.getSnapshot(),
+ true /* relative */);
+ }
}
}
@@ -1671,6 +1733,54 @@
return mThumbnail;
}
+ /**
+ * Calculates the scale and offset to horizontal center the size compatibility bounds into the
+ * region which is available to application.
+ */
+ private void calculateCompatBoundsTransformation(Configuration newParentConfig) {
+ final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect viewportBounds = parentAppBounds != null
+ ? parentAppBounds : newParentConfig.windowConfiguration.getBounds();
+ final Rect contentBounds = getResolvedOverrideBounds();
+ final float contentW = contentBounds.width();
+ final float contentH = contentBounds.height();
+ final float viewportW = viewportBounds.width();
+ final float viewportH = viewportBounds.height();
+ // Only allow to scale down.
+ mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
+ ? 1 : Math.min(viewportW / contentW, viewportH / contentH);
+ final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f)
+ + viewportBounds.left;
+
+ if (mSizeCompatBounds == null) {
+ mSizeCompatBounds = new Rect();
+ }
+ mSizeCompatBounds.set(contentBounds);
+ mSizeCompatBounds.offsetTo(0, 0);
+ mSizeCompatBounds.scale(mSizeCompatScale);
+ mSizeCompatBounds.left += offsetX;
+ mSizeCompatBounds.right += offsetX;
+ }
+
+ @Override
+ public Rect getBounds() {
+ if (mSizeCompatBounds != null) {
+ return mSizeCompatBounds;
+ }
+ return super.getBounds();
+ }
+
+ @Override
+ public boolean matchParentBounds() {
+ if (super.matchParentBounds()) {
+ return true;
+ }
+ // An activity in size compatibility mode may have override bounds which equals to its
+ // parent bounds, so the exact bounds should also be checked.
+ final WindowContainer parent = getParent();
+ return parent == null || parent.getBounds().equals(getResolvedOverrideBounds());
+ }
+
@Override
void checkAppWindowsReadyToShow() {
if (allDrawn == mLastAllDrawn) {
@@ -1844,6 +1954,7 @@
if (needsLetterbox) {
if (mLetterbox == null) {
mLetterbox = new Letterbox(() -> makeChildSurface(null));
+ mLetterbox.attachInput(w);
}
getPosition(mTmpPoint);
mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
@@ -2864,6 +2975,10 @@
if (mPendingRelaunchCount != 0) {
pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
}
+ if (mSizeCompatScale != 1f || mSizeCompatBounds != null) {
+ pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds="
+ + mSizeCompatBounds);
+ }
if (mRemovingFromDisplay) {
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
}
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 9874920..d67193e 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -20,7 +20,15 @@
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Process;
+import android.view.InputChannel;
+import android.view.InputEventReceiver;
+import android.view.InputWindowHandle;
import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import com.android.server.UiThread;
import java.util.function.Supplier;
@@ -40,6 +48,7 @@
private final LetterboxSurface mLeft = new LetterboxSurface("left");
private final LetterboxSurface mBottom = new LetterboxSurface("bottom");
private final LetterboxSurface mRight = new LetterboxSurface("right");
+ private final LetterboxSurface[] mSurfaces = { mLeft, mTop, mRight, mBottom };
/**
* Constructs a Letterbox.
@@ -87,8 +96,12 @@
* Returns true if any part of the letterbox overlaps with the given {@code rect}.
*/
public boolean isOverlappingWith(Rect rect) {
- return mTop.isOverlappingWith(rect) || mLeft.isOverlappingWith(rect)
- || mBottom.isOverlappingWith(rect) || mRight.isOverlappingWith(rect);
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.isOverlappingWith(rect)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -107,25 +120,94 @@
mOuter.setEmpty();
mInner.setEmpty();
- mTop.remove();
- mLeft.remove();
- mBottom.remove();
- mRight.remove();
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.remove();
+ }
}
/** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */
public boolean needsApplySurfaceChanges() {
- return mTop.needsApplySurfaceChanges()
- || mLeft.needsApplySurfaceChanges()
- || mBottom.needsApplySurfaceChanges()
- || mRight.needsApplySurfaceChanges();
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.needsApplySurfaceChanges()) {
+ return true;
+ }
+ }
+ return false;
}
public void applySurfaceChanges(SurfaceControl.Transaction t) {
- mTop.applySurfaceChanges(t);
- mLeft.applySurfaceChanges(t);
- mBottom.applySurfaceChanges(t);
- mRight.applySurfaceChanges(t);
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.applySurfaceChanges(t);
+ }
+ }
+
+ /** Enables touches to slide into other neighboring surfaces. */
+ void attachInput(WindowState win) {
+ for (LetterboxSurface surface : mSurfaces) {
+ surface.attachInput(win);
+ }
+ }
+
+ void onMovedToDisplay(int displayId) {
+ for (LetterboxSurface surface : mSurfaces) {
+ if (surface.mInputInterceptor != null) {
+ surface.mInputInterceptor.mWindowHandle.displayId = displayId;
+ }
+ }
+ }
+
+ private static class InputInterceptor {
+ final InputChannel mServerChannel;
+ final InputChannel mClientChannel;
+ final InputWindowHandle mWindowHandle;
+ final InputEventReceiver mInputEventReceiver;
+ final WindowManagerService mWmService;
+
+ InputInterceptor(String namePrefix, WindowState win) {
+ mWmService = win.mWmService;
+ final String name = namePrefix + (win.mAppToken != null ? win.mAppToken : win);
+ final InputChannel[] channels = InputChannel.openInputChannelPair(name);
+ mServerChannel = channels[0];
+ mClientChannel = channels[1];
+ mInputEventReceiver = new SimpleInputReceiver(mClientChannel);
+
+ final Binder token = new Binder();
+ mWmService.mInputManager.registerInputChannel(mServerChannel, token);
+
+ mWindowHandle = new InputWindowHandle(null /* inputApplicationHandle */,
+ null /* clientWindow */, win.getDisplayId());
+ mWindowHandle.name = name;
+ mWindowHandle.token = token;
+ mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_SLIPPERY;
+ mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+ mWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.visible = true;
+ mWindowHandle.ownerPid = Process.myPid();
+ mWindowHandle.ownerUid = Process.myUid();
+ mWindowHandle.scaleFactor = 1.0f;
+ }
+
+ void updateTouchableRegion(Rect frame) {
+ mWindowHandle.touchableRegion.set(frame);
+ mWindowHandle.touchableRegion.translate(-frame.left, -frame.top);
+ }
+
+ void dispose() {
+ mWmService.mInputManager.unregisterInputChannel(mServerChannel);
+ mInputEventReceiver.dispose();
+ mServerChannel.dispose();
+ mClientChannel.dispose();
+ }
+
+ private static class SimpleInputReceiver extends InputEventReceiver {
+ SimpleInputReceiver(InputChannel inputChannel) {
+ super(inputChannel, UiThread.getHandler().getLooper());
+ }
+ }
}
private class LetterboxSurface {
@@ -137,6 +219,8 @@
private final Rect mLayoutFrameGlobal = new Rect();
private final Rect mLayoutFrameRelative = new Rect();
+ private InputInterceptor mInputInterceptor;
+
public LetterboxSurface(String type) {
mType = type;
}
@@ -154,11 +238,22 @@
mSurface.setColor(new float[]{0, 0, 0});
}
+ void attachInput(WindowState win) {
+ if (mInputInterceptor != null) {
+ mInputInterceptor.dispose();
+ }
+ mInputInterceptor = new InputInterceptor("Letterbox_" + mType + "_", win);
+ }
+
public void remove() {
if (mSurface != null) {
mSurface.remove();
mSurface = null;
}
+ if (mInputInterceptor != null) {
+ mInputInterceptor.dispose();
+ mInputInterceptor = null;
+ }
}
public int getWidth() {
@@ -193,6 +288,10 @@
t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
mSurfaceFrameRelative.height());
+ if (mInputInterceptor != null) {
+ mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
+ t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
+ }
t.show(mSurface);
} else if (mSurface != null) {
t.hide(mSurface);
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 5ea2451..35b8641 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -251,7 +251,7 @@
if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
final SurfaceControl leash = mLeash;
final AnimationAdapter animation = mAnimation;
- reset(t, forwardCancel);
+ reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
animation.onAnimationCancelled(leash);
@@ -260,6 +260,12 @@
mAnimationFinishedCallback.run();
}
}
+
+ if (forwardCancel && leash != null) {
+ t.remove(leash);
+ mService.scheduleAnimationLocked();
+ }
+
if (!restarting) {
mAnimationStartDelayed = false;
}
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 69f0012..59d7560 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -119,6 +119,7 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -1288,22 +1289,7 @@
|| top == null) {
return getRequestedOverrideConfiguration().orientation;
}
- int screenOrientation = top.getOrientation();
- if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
- // NOSENSOR means the display's "natural" orientation, so return that.
- ActivityDisplay display = mStack != null ? mStack.getDisplay() : null;
- if (display != null && display.mDisplayContent != null) {
- return mStack.getDisplay().mDisplayContent.getNaturalOrientation();
- }
- } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
- // LOCKED means the activity's orientation remains unchanged, so return existing value.
- return top.getConfiguration().orientation;
- } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
- return ORIENTATION_LANDSCAPE;
- } else if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
- return ORIENTATION_PORTRAIT;
- }
- return ORIENTATION_UNDEFINED;
+ return top.getRequestedConfigurationOrientation();
}
/**
@@ -2084,6 +2070,11 @@
return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
}
+ void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+ @NonNull Configuration parentConfig) {
+ computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */);
+ }
+
/**
* Calculates configuration values used by the client to get resources. This should be run
* using app-facing bounds (bounds unmodified by animations or transient interactions).
@@ -2093,7 +2084,7 @@
* just be inherited from the parent configuration.
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig) {
+ @NonNull Configuration parentConfig, boolean insideParentBounds) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2111,7 +2102,7 @@
inOutConfig.windowConfiguration.setAppBounds(bounds);
outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
}
- if (windowingMode != WINDOWING_MODE_FREEFORM) {
+ if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
outAppBounds.intersect(parentAppBounds);
@@ -2120,7 +2111,7 @@
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
|| inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- if (mStack != null) {
+ if (insideParentBounds && mStack != null) {
final DisplayInfo di = new DisplayInfo();
mStack.getDisplay().mDisplay.getDisplayInfo(di);
@@ -2135,12 +2126,16 @@
}
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutConfig.screenWidthDp = Math.min((int) (mTmpStableBounds.width() / density),
- parentConfig.screenWidthDp);
+ final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+ inOutConfig.screenWidthDp = insideParentBounds
+ ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
+ : overrideScreenWidthDp;
}
if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutConfig.screenHeightDp = Math.min((int) (mTmpStableBounds.height() / density),
- parentConfig.screenHeightDp);
+ final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+ inOutConfig.screenHeightDp = insideParentBounds
+ ? Math.min(overrideScreenHeightDp, parentConfig.screenWidthDp)
+ : overrideScreenHeightDp;
}
if (inOutConfig.smallestScreenWidthDp
@@ -2162,7 +2157,7 @@
if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
+ ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
}
if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
// For calculating screen layout, we need to use the non-decor inset screen area for the
@@ -2332,6 +2327,7 @@
info.userId = userId;
info.stackId = getStackId();
info.taskId = taskId;
+ info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
info.isRunning = getTopActivity() != null;
info.baseIntent = new Intent(getBaseIntent());
info.baseActivity = reuseActivitiesReport.base != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 00105be..c747c6d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -47,7 +47,6 @@
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -1839,6 +1838,9 @@
return;
}
outDisplayFrame.set(win.getDisplayFrameLw());
+ if (win.inSizeCompatMode()) {
+ outDisplayFrame.scale(win.mInvGlobalScale);
+ }
}
}
@@ -1963,8 +1965,6 @@
if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
+ " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
winAnimator.mSurfaceDestroyDeferred = (flags & RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
- win.mEnforceSizeCompat =
- (win.mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
winAnimator.mAlpha = attrs.alpha;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 85b251a..48cd6b6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -246,7 +246,6 @@
final boolean mIsWallpaper;
private final boolean mIsFloatingLayer;
int mSeq;
- boolean mEnforceSizeCompat;
int mViewVisibility;
int mSystemUiVisibility;
/**
@@ -505,7 +504,8 @@
*/
private PowerManager.WakeLock mDrawLock;
- final private Rect mTmpRect = new Rect();
+ private final Rect mTmpRect = new Rect();
+ private final Point mTmpPoint = new Point();
/**
* Whether the window was resized by us while it was gone for layout.
@@ -655,7 +655,6 @@
mContext = mWmService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
mSeq = seq;
- mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
mPowerManagerWrapper = powerManagerWrapper;
mForceSeamlesslyRotate = token.mRoundedCornerOverlay;
if (localLOGV) Slog.v(
@@ -733,6 +732,18 @@
}
/**
+ * @return {@code true} if the application runs in size compatibility mode.
+ * @see android.content.res.CompatibilityInfo#supportsScreen
+ * @see ActivityRecord#inSizeCompatMode
+ */
+ boolean inSizeCompatMode() {
+ return (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0
+ || (mAppToken != null && mAppToken.inSizeCompatMode()
+ // Exclude starting window because it is not displayed by the application.
+ && mAttrs.type != TYPE_APPLICATION_STARTING);
+ }
+
+ /**
* Returns whether this {@link WindowState} has been considered for drawing by its parent.
*/
boolean getDrawnStateEvaluated() {
@@ -995,7 +1006,7 @@
mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
// If there is a size compatibility scale being applied to the
// window, we need to apply this to its insets so that they are
// reported to the app in its coordinate space.
@@ -1354,8 +1365,8 @@
}
void prelayout() {
- if (mEnforceSizeCompat) {
- mGlobalScale = getDisplayContent().mCompatibleScreenScale;
+ if (inSizeCompatMode()) {
+ mGlobalScale = mToken.getSizeCompatScale();
mInvGlobalScale = 1 / mGlobalScale;
} else {
mGlobalScale = mInvGlobalScale = 1;
@@ -2145,6 +2156,30 @@
int getSurfaceTouchableRegion(Region region, int flags) {
final boolean modal = (flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
+ if (mAppToken != null && !mAppToken.getResolvedOverrideBounds().isEmpty()) {
+ // There may have touchable letterboxes around the activity, so in order to let the
+ // letterboxes are able to receive touch event and slip to activity, the activity with
+ // compatibility bounds cannot occupy full screen touchable region.
+ if (modal) {
+ // A modal window uses the whole compatibility bounds.
+ flags |= FLAG_NOT_TOUCH_MODAL;
+ mTmpRect.set(mAppToken.getResolvedOverrideBounds());
+ // TODO(b/112288258): Remove the forced offset when the override bounds always
+ // starts from zero (See {@link ActivityRecord#resolveOverrideConfiguration}).
+ mTmpRect.offsetTo(0, 0);
+ } else {
+ // Non-modal uses the application based frame.
+ mTmpRect.set(mWindowFrames.mCompatFrame);
+ }
+ // The offset of compatibility bounds is applied to surface of {@link #AppWindowToken}
+ // and frame, so it is unnecessary to translate twice in surface based coordinates.
+ final int surfaceOffsetX = mAppToken.inSizeCompatMode()
+ ? mAppToken.getBounds().left : 0;
+ mTmpRect.offset(surfaceOffsetX - mWindowFrames.mFrame.left, -mWindowFrames.mFrame.top);
+ region.set(mTmpRect);
+ return flags;
+ }
+
if (modal && mAppToken != null) {
// Limit the outer touch to the activity stack region.
flags |= FLAG_NOT_TOUCH_MODAL;
@@ -2943,7 +2978,7 @@
if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
- final Rect frame = mWindowFrames.mFrame;
+ final Rect frame = mWindowFrames.mCompatFrame;
final Rect overscanInsets = mWindowFrames.mLastOverscanInsets;
final Rect contentInsets = mWindowFrames.mLastContentInsets;
final Rect visibleInsets = mWindowFrames.mLastVisibleInsets;
@@ -3353,7 +3388,7 @@
pw.println(prefix + "mHasSurface=" + mHasSurface
+ " isReadyForDisplay()=" + isReadyForDisplay()
+ " mWindowRemovalAllowed=" + mWindowRemovalAllowed);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
pw.println(prefix + "mCompatFrame=" + mWindowFrames.mCompatFrame.toShortString(sTmpSB));
}
if (dumpAll) {
@@ -3477,17 +3512,18 @@
float x, y;
int w,h;
+ final boolean inSizeCompatMode = inSizeCompatMode();
if ((mAttrs.flags & FLAG_SCALED) != 0) {
if (mAttrs.width < 0) {
w = pw;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
w = (int)(mAttrs.width * mGlobalScale + .5f);
} else {
w = mAttrs.width;
}
if (mAttrs.height < 0) {
h = ph;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
h = (int)(mAttrs.height * mGlobalScale + .5f);
} else {
h = mAttrs.height;
@@ -3495,21 +3531,21 @@
} else {
if (mAttrs.width == MATCH_PARENT) {
w = pw;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
w = (int)(mRequestedWidth * mGlobalScale + .5f);
} else {
w = mRequestedWidth;
}
if (mAttrs.height == MATCH_PARENT) {
h = ph;
- } else if (mEnforceSizeCompat) {
+ } else if (inSizeCompatMode) {
h = (int)(mRequestedHeight * mGlobalScale + .5f);
} else {
h = mRequestedHeight;
}
}
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode) {
x = mAttrs.x * mGlobalScale;
y = mAttrs.y * mGlobalScale;
} else {
@@ -3537,7 +3573,7 @@
// We need to make sure we update the CompatFrame as it is used for
// cropping decisions, etc, on systems where we lack a decor layer.
mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode) {
// See comparable block in computeFrameLw.
mWindowFrames.mCompatFrame.scale(mInvGlobalScale);
}
@@ -3650,7 +3686,7 @@
float translateToWindowX(float x) {
float winX = x - mWindowFrames.mFrame.left;
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
winX *= mGlobalScale;
}
return winX;
@@ -3658,7 +3694,7 @@
float translateToWindowY(float y) {
float winY = y - mWindowFrames.mFrame.top;
- if (mEnforceSizeCompat) {
+ if (inSizeCompatMode()) {
winY *= mGlobalScale;
}
return winY;
@@ -4233,12 +4269,11 @@
*/
void calculatePolicyCrop(Rect policyCrop) {
final DisplayContent displayContent = getDisplayContent();
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (!isDefaultDisplay()) {
+ if (!displayContent.isDefaultDisplay && !displayContent.supportsSystemDecorations()) {
// On a different display there is no system decor. Crop the window
// by the screen boundaries.
- // TODO(multi-display)
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
policyCrop.set(0, 0, mWindowFrames.mCompatFrame.width(),
mWindowFrames.mCompatFrame.height());
policyCrop.intersect(-mWindowFrames.mCompatFrame.left, -mWindowFrames.mCompatFrame.top,
@@ -4304,7 +4339,7 @@
// scale function because we want to round things to make the crop
// always round to a larger rect to ensure we don't crop too
// much and hide part of the window that should be seen.
- if (mEnforceSizeCompat && mInvGlobalScale != 1.0f) {
+ if (inSizeCompatMode() && mInvGlobalScale != 1.0f) {
final float scale = mInvGlobalScale;
systemDecorRect.left = (int) (systemDecorRect.left * scale - 0.5f);
systemDecorRect.top = (int) (systemDecorRect.top * scale - 0.5f);
@@ -4664,8 +4699,9 @@
// Since the parent was outset by its surface insets, we need to undo the outsetting
// with insetting by the same amount.
final WindowState parent = getParentWindow();
- outPoint.offset(-parent.mWindowFrames.mFrame.left + parent.mAttrs.surfaceInsets.left,
- -parent.mWindowFrames.mFrame.top + parent.mAttrs.surfaceInsets.top);
+ transformSurfaceInsetsPosition(mTmpPoint, parent.mAttrs.surfaceInsets);
+ outPoint.offset(-parent.mWindowFrames.mFrame.left + mTmpPoint.x,
+ -parent.mWindowFrames.mFrame.top + mTmpPoint.y);
} else if (parentWindowContainer != null) {
final Rect parentBounds = parentWindowContainer.getDisplayedBounds();
outPoint.offset(-parentBounds.left, -parentBounds.top);
@@ -4683,7 +4719,22 @@
}
// Expand for surface insets. See WindowState.expandForSurfaceInsets.
- outPoint.offset(-mAttrs.surfaceInsets.left, -mAttrs.surfaceInsets.top);
+ transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
+ outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
+ }
+
+ /**
+ * The surface insets from layout parameter are in application coordinate. If the window is
+ * scaled, the insets also need to be scaled for surface position in global coordinate.
+ */
+ private void transformSurfaceInsetsPosition(Point outPos, Rect surfaceInsets) {
+ if (!inSizeCompatMode()) {
+ outPos.x = surfaceInsets.left;
+ outPos.y = surfaceInsets.top;
+ return;
+ }
+ outPos.x = (int) (surfaceInsets.left * mGlobalScale + 0.5f);
+ outPos.y = (int) (surfaceInsets.top * mGlobalScale + 0.5f);
}
boolean needsRelativeLayeringToIme() {
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 3b9b8ba..f0b9c62 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -182,6 +182,14 @@
}
/**
+ * @return The scale for applications running in compatibility mode. Multiply the size in the
+ * application by this scale will be the size in the screen.
+ */
+ float getSizeCompatScale() {
+ return mDisplayContent.mCompatibleScreenScale;
+ }
+
+ /**
* Returns true if the new window is considered greater than the existing window in terms of
* z-order.
*/
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e30acf7..093ac89 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -247,6 +247,7 @@
import com.android.server.pm.UserRestrictionsUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import com.google.android.collect.Sets;
@@ -1870,7 +1871,7 @@
Owners newOwners() {
return new Owners(getUserManager(), getUserManagerInternal(),
- getPackageManagerInternal());
+ getPackageManagerInternal(), getActivityTaskManagerInternal());
}
UserManager getUserManager() {
@@ -1885,6 +1886,10 @@
return LocalServices.getService(PackageManagerInternal.class);
}
+ ActivityTaskManagerInternal getActivityTaskManagerInternal() {
+ return LocalServices.getService(ActivityTaskManagerInternal.class);
+ }
+
UsageStatsManagerInternal getUsageStatsManagerInternal() {
return LocalServices.getService(UsageStatsManagerInternal.class);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index ee1c1df3..27cd70c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
import libcore.io.IoUtils;
@@ -104,6 +105,7 @@
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
private final PackageManagerInternal mPackageManagerInternal;
+ private final ActivityTaskManagerInternal mActivityTaskManagerInternal;
private boolean mSystemReady;
@@ -129,18 +131,22 @@
public Owners(UserManager userManager,
UserManagerInternal userManagerInternal,
- PackageManagerInternal packageManagerInternal) {
- this(userManager, userManagerInternal, packageManagerInternal, new Injector());
+ PackageManagerInternal packageManagerInternal,
+ ActivityTaskManagerInternal activityTaskManagerInternal) {
+ this(userManager, userManagerInternal, packageManagerInternal,
+ activityTaskManagerInternal, new Injector());
}
@VisibleForTesting
Owners(UserManager userManager,
UserManagerInternal userManagerInternal,
PackageManagerInternal packageManagerInternal,
+ ActivityTaskManagerInternal activityTaskManagerInternal,
Injector injector) {
mUserManager = userManager;
mUserManagerInternal = userManagerInternal;
mPackageManagerInternal = packageManagerInternal;
+ mActivityTaskManagerInternal = activityTaskManagerInternal;
mInjector = injector;
}
@@ -187,6 +193,7 @@
getDeviceOwnerUserId()));
}
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -201,6 +208,11 @@
po);
}
+ private void pushToActivityTaskManagerLocked() {
+ mActivityTaskManagerInternal.setDeviceOwnerPackageName(mDeviceOwner != null
+ ? mDeviceOwner.packageName : null);
+ }
+
String getDeviceOwnerPackageName() {
synchronized (mLock) {
return mDeviceOwner != null ? mDeviceOwner.packageName : null;
@@ -275,6 +287,7 @@
mUserManagerInternal.setDeviceManaged(true);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -286,6 +299,7 @@
mUserManagerInternal.setDeviceManaged(false);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
@@ -333,6 +347,7 @@
mDeviceOwner.remoteBugreportHash, /* canAccessDeviceIds =*/
mDeviceOwner.canAccessDeviceIds);
pushToPackageManagerLocked();
+ pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
}
}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
similarity index 76%
rename from services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java
rename to services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
index 4354db7..24e5573 100644
--- a/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunk/ChunkListingMapTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.backup.encryption.chunk;
@@ -36,7 +36,7 @@
@RunWith(RobolectricTestRunner.class)
@Presubmit
-public class ChunkListingTest {
+public class ChunkListingMapTest {
private static final String CHUNK_A = "CHUNK_A";
private static final String CHUNK_B = "CHUNK_B";
private static final String CHUNK_C = "CHUNK_C";
@@ -62,13 +62,13 @@
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- boolean chunkAInList = chunkListing.hasChunk(mChunkHashA);
- boolean chunkBInList = chunkListing.hasChunk(mChunkHashB);
- boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
+ boolean chunkAInList = chunkListingMap.hasChunk(mChunkHashA);
+ boolean chunkBInList = chunkListingMap.hasChunk(mChunkHashB);
+ boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
assertThat(chunkAInList).isTrue();
assertThat(chunkBInList).isTrue();
@@ -81,13 +81,13 @@
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
ChunkHash chunkHashEmpty = getHash("");
- boolean chunkCInList = chunkListing.hasChunk(mChunkHashC);
- boolean emptyChunkInList = chunkListing.hasChunk(chunkHashEmpty);
+ boolean chunkCInList = chunkListingMap.hasChunk(mChunkHashC);
+ boolean emptyChunkInList = chunkListingMap.hasChunk(chunkHashEmpty);
assertThat(chunkCInList).isFalse();
assertThat(emptyChunkInList).isFalse();
@@ -99,13 +99,13 @@
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
- ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
- ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
+ ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
+ ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(entryA.getLength()).isEqualTo(CHUNK_A_LENGTH);
assertThat(entryB.getLength()).isEqualTo(CHUNK_B_LENGTH);
@@ -118,13 +118,13 @@
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry entryA = chunkListing.getChunkEntry(mChunkHashA);
- ChunkListing.Entry entryB = chunkListing.getChunkEntry(mChunkHashB);
- ChunkListing.Entry entryC = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry entryA = chunkListingMap.getChunkEntry(mChunkHashA);
+ ChunkListingMap.Entry entryB = chunkListingMap.getChunkEntry(mChunkHashB);
+ ChunkListingMap.Entry entryC = chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(entryA.getStart()).isEqualTo(0);
assertThat(entryB.getStart()).isEqualTo(CHUNK_A_LENGTH);
@@ -137,22 +137,24 @@
createChunkListingProto(
new ChunkHash[] {mChunkHashA, mChunkHashB},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- ChunkListing.Entry chunkEntryNonexistentChunk = chunkListing.getChunkEntry(mChunkHashC);
+ ChunkListingMap.Entry chunkEntryNonexistentChunk =
+ chunkListingMap.getChunkEntry(mChunkHashC);
assertThat(chunkEntryNonexistentChunk).isNull();
}
@Test
- public void testReadFromProto_whenEmptyProto_returnsChunkListingWith0Chunks() throws Exception {
+ public void testReadFromProto_whenEmptyProto_returnsChunkListingMapWith0Chunks()
+ throws Exception {
ProtoInputStream emptyProto = new ProtoInputStream(new ByteArrayInputStream(new byte[] {}));
- ChunkListing chunkListing = ChunkListing.readFromProto(emptyProto);
+ ChunkListingMap chunkListingMap = ChunkListingMap.readFromProto(emptyProto);
- assertThat(chunkListing.getChunkCount()).isEqualTo(0);
+ assertThat(chunkListingMap.getChunkCount()).isEqualTo(0);
}
@Test
@@ -162,11 +164,11 @@
new ChunkHash[] {mChunkHashA, mChunkHashB, mChunkHashC},
new int[] {CHUNK_A_LENGTH, CHUNK_B_LENGTH, CHUNK_C_LENGTH});
- ChunkListing chunkListing =
- ChunkListing.readFromProto(
+ ChunkListingMap chunkListingMap =
+ ChunkListingMap.readFromProto(
new ProtoInputStream(new ByteArrayInputStream(chunkListingProto)));
- assertThat(chunkListing.getChunkCount()).isEqualTo(3);
+ assertThat(chunkListingMap.getChunkCount()).isEqualTo(3);
}
private byte[] createChunkListingProto(ChunkHash[] hashes, int[] lengths) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 53d72bb..e51ee94 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -19,6 +19,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -51,6 +52,9 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -82,6 +86,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
@@ -105,6 +110,8 @@
@Mock
private ContentResolver mContentResolver;
@Mock
+ private DeviceIdleController.MyHandler mHandler;
+ @Mock
private IActivityManager mIActivityManager;
@Mock
private LocationManager mLocationManager;
@@ -154,7 +161,7 @@
@Override
DeviceIdleController.MyHandler getHandler(DeviceIdleController controller) {
- return mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
+ return mHandler;
}
@Override
@@ -232,10 +239,12 @@
.when(() -> LocalServices.getService(ActivityManagerInternal.class));
doReturn(mock(ActivityTaskManagerInternal.class))
.when(() -> LocalServices.getService(ActivityTaskManagerInternal.class));
+ doReturn(mock(AlarmManagerInternal.class))
+ .when(() -> LocalServices.getService(AlarmManagerInternal.class));
doReturn(mPowerManagerInternal)
.when(() -> LocalServices.getService(PowerManagerInternal.class));
- when(mPowerManagerInternal.getLowPowerState(anyInt())).thenReturn(
- mock(PowerSaveState.class));
+ when(mPowerManagerInternal.getLowPowerState(anyInt()))
+ .thenReturn(mock(PowerSaveState.class));
doReturn(mock(NetworkPolicyManagerInternal.class))
.when(() -> LocalServices.getService(NetworkPolicyManagerInternal.class));
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
@@ -246,8 +255,11 @@
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper());
mAnyMotionDetector = new AnyMotionDetectorForTest();
+ mHandler = mock(DeviceIdleController.MyHandler.class, Answers.RETURNS_DEEP_STUBS);
+ doNothing().when(mHandler).handleMessage(any());
mInjector = new InjectorForTest(getContext());
doNothing().when(mContentResolver).registerContentObserver(any(), anyBoolean(), any());
+
mDeviceIdleController = new DeviceIdleController(getContext(), mInjector);
spyOn(mDeviceIdleController);
doNothing().when(mDeviceIdleController).publishBinderService(any(), any());
@@ -423,6 +435,29 @@
mDeviceIdleController.becomeInactiveIfAppropriateLocked();
verifyStateConditions(STATE_ACTIVE);
+
+ mConstants.WAIT_FOR_UNLOCK = false;
+ setScreenLocked(true);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
+
+ setScreenLocked(false);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
+
+ mConstants.WAIT_FOR_UNLOCK = true;
+ setScreenLocked(false);
+ setScreenOn(true);
+ setChargingOn(false);
+
+ mDeviceIdleController.becomeInactiveIfAppropriateLocked();
+ verifyStateConditions(STATE_ACTIVE);
}
@Test
@@ -1307,7 +1342,7 @@
}
@Test
- public void testbecomeActiveLocked_deep() {
+ public void testBecomeActiveLocked_deep() {
// becomeActiveLocked should put everything into ACTIVE.
enterDeepState(STATE_ACTIVE);
@@ -1344,7 +1379,7 @@
}
@Test
- public void testbecomeActiveLocked_light() {
+ public void testBecomeActiveLocked_light() {
// becomeActiveLocked should put everything into ACTIVE.
enterLightState(LIGHT_STATE_ACTIVE);
@@ -1376,6 +1411,163 @@
verifyLightStateConditions(LIGHT_STATE_ACTIVE);
}
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_ScreenThenMotion() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(true);
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
+ // shouldn't bring the device out of deep IDLE.
+ verifyStateConditions(STATE_IDLE);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // Motion should bring the device out of Doze. Since the screen is still locked (albeit
+ // on), the states should go back into INACTIVE.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_ScreenThenMotion() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(false);
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOn_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(true);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen locked, turning the screen on by itself
+ // shouldn't bring the device all the way to ACTIVE.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager, never()).cancel(
+ eq(mDeviceIdleController.mDeepAlarmListener));
+
+ // User finally unlocks the device. Device should be fully active.
+ mDeviceIdleController.keyguardShowingLocked(false);
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ /** Test based on b/119058625. */
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOn_KeyguardOff_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = true;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.keyguardShowingLocked(false);
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = true and the screen unlocked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOff_Screen() {
+ mConstants.WAIT_FOR_UNLOCK = false;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ verify(mAlarmManager).cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ verify(mDeviceIdleController).scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
+ @Test
+ public void testExitNotifiesDependencies_WaitForUnlockOff_MotionThenScreen() {
+ mConstants.WAIT_FOR_UNLOCK = false;
+ enterDeepState(STATE_IDLE);
+ reset(mAlarmManager);
+ spyOn(mDeviceIdleController);
+
+ InOrder alarmManagerInOrder = inOrder(mAlarmManager);
+ InOrder controllerInOrder = inOrder(mDeviceIdleController);
+
+ mDeviceIdleController.handleMotionDetectedLocked(1000, "test");
+ // The screen is still off, so motion should result in the INACTIVE state.
+ verifyStateConditions(STATE_INACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_INACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+
+ setScreenOn(true);
+ // With WAIT_FOR_UNLOCK = false and the screen locked, turning the screen on by itself
+ // should bring the device out of deep IDLE.
+ verifyStateConditions(STATE_ACTIVE);
+ verifyLightStateConditions(LIGHT_STATE_ACTIVE);
+ alarmManagerInOrder.verify(mAlarmManager)
+ .cancel(eq(mDeviceIdleController.mDeepAlarmListener));
+ controllerInOrder.verify(mDeviceIdleController)
+ .scheduleReportActiveLocked(anyString(), anyInt());
+ }
+
@Test
public void testStepToIdleMode() {
float delta = mDeviceIdleController.MIN_PRE_IDLE_FACTOR_CHANGE;
@@ -1508,6 +1700,10 @@
mDeviceIdleController.updateChargingLocked(on);
}
+ private void setScreenLocked(boolean locked) {
+ mDeviceIdleController.keyguardShowingLocked(locked);
+ }
+
private void setScreenOn(boolean on) {
doReturn(on).when(mPowerManager).isInteractive();
mDeviceIdleController.updateInteractivityLocked();
@@ -1549,7 +1745,8 @@
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE_PENDING:
assertEquals(
@@ -1557,7 +1754,8 @@
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_SENSING:
assertEquals(
@@ -1567,14 +1765,16 @@
mDeviceIdleController.hasMotionSensor(),
mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_LOCATING:
assertEquals(
mDeviceIdleController.hasMotionSensor(),
mDeviceIdleController.mMotionListener.isActive());
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_IDLE:
if (mDeviceIdleController.hasMotionSensor()) {
@@ -1584,7 +1784,8 @@
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
// Light state should be OVERRIDE at this point.
verifyLightStateConditions(LIGHT_STATE_OVERRIDE);
break;
@@ -1596,14 +1797,16 @@
}
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
case STATE_QUICK_DOZE_DELAY:
// If quick doze is enabled, the motion listener should NOT be active.
assertFalse(mDeviceIdleController.mMotionListener.isActive());
assertFalse(mAnyMotionDetector.isMonitoring);
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + stateToString(expectedState) + " unknown.");
@@ -1632,7 +1835,8 @@
case LIGHT_STATE_IDLE_MAINTENANCE:
case LIGHT_STATE_OVERRIDE:
assertFalse(mDeviceIdleController.isCharging());
- assertFalse(mDeviceIdleController.isScreenOn());
+ assertFalse(mDeviceIdleController.isScreenOn()
+ && !mDeviceIdleController.isKeyguardShowing());
break;
default:
fail("Conditions for " + lightStateToString(expectedLightState) + " unknown.");
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index dc31c0f..fce7599 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -66,6 +66,8 @@
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index a847b6a..2ce4c54 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -65,7 +65,8 @@
public OwnersTestable(MockSystemServices services) {
super(services.userManager, services.userManagerInternal,
- services.packageManagerInternal, new MockInjector(services));
+ services.packageManagerInternal, services.activityTaskManagerInternal,
+ new MockInjector(services));
}
static class MockInjector extends Injector {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 4724f1c..8f0aeea 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -64,6 +64,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -94,6 +95,7 @@
public final IActivityManager iactivityManager;
public final IActivityTaskManager iactivityTaskManager;
public ActivityManagerInternal activityManagerInternal;
+ public ActivityTaskManagerInternal activityTaskManagerInternal;
public final IPackageManager ipackageManager;
public final IBackupManager ibackupManager;
public final IAudioService iaudioService;
@@ -133,6 +135,7 @@
iactivityManager = mock(IActivityManager.class);
iactivityTaskManager = mock(IActivityTaskManager.class);
activityManagerInternal = mock(ActivityManagerInternal.class);
+ activityTaskManagerInternal = mock(ActivityTaskManagerInternal.class);
ipackageManager = mock(IPackageManager.class);
ibackupManager = mock(IBackupManager.class);
iaudioService = mock(IAudioService.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 2de4ae0..23bae88 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -24,6 +24,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
+
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -35,9 +36,7 @@
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.SparseIntArray;
-import android.util.proto.ProtoOutputStream;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 4073ff1..8c36905 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -183,11 +183,14 @@
.thenReturn(navBarPosition);
mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
mActivity.info.maxAspectRatio = aspectRatio;
- mActivity.ensureActivityConfiguration(
- 0 /* globalChanges */, false /* preserveWindow */);
+ ensureActivityConfiguration();
assertEquals(expectedActivityBounds, mActivity.getBounds());
}
+ private void ensureActivityConfiguration() {
+ mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ }
+
@Test
public void testCanBeLaunchedOnDisplay() {
mService.mSupportsMultiWindow = true;
@@ -281,7 +284,7 @@
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
mActivity.mRelaunchReason);
@@ -305,7 +308,7 @@
mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
mActivity.mRelaunchReason);
@@ -327,7 +330,7 @@
mActivity.mRelaunchReason =
ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
- mActivity.ensureActivityConfiguration(0, false, false);
+ ensureActivityConfiguration();
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
mActivity.mRelaunchReason);
@@ -433,4 +436,46 @@
stack.getDisplay().removeChild(stack);
}
}
+
+ @Test
+ public void testFixedScreenConfigurationWhenMovingToDisplay() {
+ // Initialize different bounds on a new display.
+ final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ newDisplay.setBounds(0, 0, 1000, 2000);
+ newDisplay.getConfiguration().densityDpi = 300;
+
+ mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+ mTask.getConfiguration().densityDpi = 200;
+ when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
+ ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ mActivity.info.maxAspectRatio = 1.5f;
+ ensureActivityConfiguration();
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+ final int originalDpi = mActivity.getConfiguration().densityDpi;
+
+ // Move the non-resizable activity to the new display.
+ mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
+ ensureActivityConfiguration();
+
+ assertEquals(originalBounds, mActivity.getBounds());
+ assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
+ }
+
+ @Test
+ public void testFixedScreenBoundsWhenDisplaySizeChanged() {
+ when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
+ ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
+ mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ ensureActivityConfiguration();
+ final Rect originalBounds = new Rect(mActivity.getBounds());
+
+ // Change the size of current display.
+ mStack.getDisplay().setBounds(0, 0, 1000, 2000);
+ ensureActivityConfiguration();
+
+ assertEquals(originalBounds, mActivity.getBounds());
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 60f1ae26..392b010 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -61,7 +61,6 @@
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -643,7 +642,7 @@
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
false, false, false, true, false);
runAndVerifyBackgroundActivityStartsSubtest(
- "disallowed_callingPackageIsDeviceOwner_notAborted", false,
+ "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
false, false, false, false, true);
@@ -655,7 +654,7 @@
boolean hasForegroundActivities, boolean callerIsRecents,
boolean callerIsTempWhitelisted,
boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
- boolean isCallingPackageDeviceOwner) {
+ boolean isCallingPackageNameDeviceOwner) {
// window visibility
doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
.isAnyNonToastWindowVisibleForUid(callingUid);
@@ -681,9 +680,8 @@
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
- // caller is device owner
- DevicePolicyManager dpmMock = mService.getDevicePolicyManager();
- doReturn(isCallingPackageDeviceOwner).when(dpmMock).isDeviceOwnerApp(any());
+ // calling package name is whitelisted
+ doReturn(isCallingPackageNameDeviceOwner).when(mService).isDeviceOwner(any());
final ActivityOptions options = spy(ActivityOptions.makeBasic());
ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 21a4e84..abc0bd6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -42,7 +42,6 @@
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -437,7 +436,6 @@
spyOn(getLifecycleManager());
spyOn(getLockTaskController());
doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
- doReturn(mock(DevicePolicyManager.class)).when(this).getDevicePolicyManager();
// allow background activity starts by default
doReturn(true).when(this).isBackgroundActivityStartsEnabled();
doNothing().when(this).updateCpuStats();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index bc62de1..cd13209 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -44,6 +44,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
+import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
@@ -62,7 +63,6 @@
* Build/Install/Run:
* atest FrameworksServicesTests:AppWindowTokenTests
*/
-@FlakyTest(bugId = 68267650)
@SmallTest
@Presubmit
public class AppWindowTokenTests extends WindowTestsBase {
@@ -79,6 +79,7 @@
mTask = createTaskInStack(mStack, 0 /* userId */);
mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+ mToken.mSkipOnParentChanged = false;
mTask.addChild(mToken, 0);
}
@@ -141,6 +142,7 @@
mToken.removeImmediately();
}
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testLandscapeSeascapeRotationByApp() {
// Some plumbing to get the service ready for rotation updates.
@@ -166,6 +168,8 @@
mDisplayContent.updateOrientationFromAppTokens(
mDisplayContent.getRequestedOverrideConfiguration(),
null /* freezeThisOneIfNeeded */, false /* forceUpdate */);
+ // In this test, DC will not get config update. Set the waiting flag to false.
+ mDisplayContent.mWaitingForConfig = false;
mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
assertTrue(appWindow.mResizeReported);
@@ -211,6 +215,48 @@
}
@Test
+ public void testSizeCompatBounds() {
+ // The real surface transaction is unnecessary.
+ mToken.setSkipPrepareSurfaces(true);
+
+ final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
+ .getBounds();
+ fixedBounds.set(0, 0, 1200, 1600);
+ final Configuration newParentConfig = mTask.getConfiguration();
+
+ // Change the size of the container to two times smaller with insets.
+ newParentConfig.windowConfiguration.setAppBounds(200, 0, 800, 800);
+ final Rect containerAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect containerBounds = newParentConfig.windowConfiguration.getBounds();
+ containerBounds.set(0, 0, 600, 800);
+ mToken.onConfigurationChanged(newParentConfig);
+
+ assertTrue(mToken.inSizeCompatMode());
+ assertEquals(containerAppBounds, mToken.getBounds());
+ assertEquals((float) containerAppBounds.width() / fixedBounds.width(),
+ mToken.getSizeCompatScale(), 0.0001f /* delta */);
+
+ // Change the width of the container to two times bigger.
+ containerAppBounds.set(0, 0, 2400, 1600);
+ containerBounds.set(containerAppBounds);
+ mToken.onConfigurationChanged(newParentConfig);
+
+ assertTrue(mToken.inSizeCompatMode());
+ // Don't scale up, so the bounds keep the same as the fixed width.
+ assertEquals(fixedBounds.width(), mToken.getBounds().width());
+ // Assert the position is horizontal center.
+ assertEquals((containerAppBounds.width() - fixedBounds.width()) / 2,
+ mToken.getBounds().left);
+ assertEquals(1f, mToken.getSizeCompatScale(), 0.0001f /* delta */);
+
+ // Change the width of the container to fit the fixed bounds.
+ containerBounds.set(0, 0, 1200, 2000);
+ mToken.onConfigurationChanged(newParentConfig);
+ // Assert don't use fixed bounds because the region is enough.
+ assertFalse(mToken.inSizeCompatMode());
+ }
+
+ @Test
@Presubmit
public void testGetOrientation() {
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
@@ -300,6 +346,7 @@
assertNoStartingWindow(mToken);
}
+ @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testAddRemoveRace() {
// There was once a race condition between adding and removing starting windows
@@ -384,6 +431,7 @@
// bottom one.
tokenTop.setVisibility(false, false);
tokenBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
+ waitUntilHandlersIdle();
// Assert that the bottom window now has the starting window.
assertNoStartingWindow(tokenTop);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 2f90baa..3f83cae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -71,7 +71,6 @@
* atest WmTests:AssistDataRequesterTest
*/
@MediumTest
-@FlakyTest(bugId = 113616538)
public class AssistDataRequesterTest extends ActivityTestsBase {
private static final String TAG = AssistDataRequesterTest.class.getSimpleName();
@@ -154,6 +153,7 @@
.checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testRequestData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -174,6 +174,7 @@
assertReceivedDataCount(0, 0, 0, 0);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -184,6 +185,7 @@
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testProcessPendingData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -241,6 +243,7 @@
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -254,6 +257,7 @@
assertReceivedDataCount(0, 1, 0, 1);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -264,6 +268,7 @@
assertReceivedDataCount(5, 5, 0, 0);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index 0c363de..a0546d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -19,11 +19,11 @@
import static android.view.InsetsState.TYPE_TOP_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -31,8 +31,6 @@
import android.view.InsetsSource;
import android.view.InsetsState;
-import org.junit.Before;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 11526a8..bc62e8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -35,7 +35,6 @@
import org.junit.Test;
@SmallTest
-@FlakyTest(detail = "Promote once confirmed non-flaky")
@Presubmit
public class InsetsStateControllerTest extends WindowTestsBase {
@@ -48,6 +47,7 @@
assertNotNull(getController().getInsetsForDispatch(app).getSource(TYPE_TOP_BAR));
}
+ @FlakyTest(bugId = 69229402)
@Test
public void testStripForDispatch_own() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -57,6 +57,7 @@
assertEquals(new InsetsState(), getController().getInsetsForDispatch(topBar));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testStripForDispatch_navBar() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -68,6 +69,7 @@
assertEquals(new InsetsState(), getController().getInsetsForDispatch(navBar));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testBarControllingWinChanged() {
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -80,6 +82,7 @@
assertEquals(2, controls.length);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
@@ -91,6 +94,7 @@
assertNull(getController().getControlsForDispatch(app));
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testControlRevoked_animation() {
final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow");
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index 86bf3db..b769fce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -24,7 +24,6 @@
import android.platform.test.annotations.Presubmit;
import android.view.RemoteAnimationAdapter;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.testutils.OffsettableClock;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index c3d2f33..8327440 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -28,7 +28,6 @@
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import org.junit.After;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index dad6c95..7111852 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -21,7 +21,6 @@
import android.app.ActivityOptions;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index dfdbf32..6cce9f0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -167,7 +167,6 @@
verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
}
- @FlakyTest(bugId = 74780584)
@Test
public void testDeferStartingAnimations() throws Exception {
mSurfaceAnimationRunner.deferStartingAnimations();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 8c32e8c..88ac96d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -34,7 +34,6 @@
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -51,7 +50,7 @@
* Test class for {@link SurfaceAnimatorTest}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:SurfaceAnimatorTest
+ * atest WmTests:SurfaceAnimatorTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 12ed3c2..9dfeadf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -29,8 +29,6 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseBooleanArray;
-import androidx.test.filters.FlakyTest;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 8c6ac23..1e58e41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -43,7 +43,6 @@
* Build/Install/Run:
* atest FrameworksServicesTests:TaskPositioningControllerTests
*/
-@FlakyTest(bugId = 117924387)
@SmallTest
@Presubmit
public class TaskPositioningControllerTests extends WindowTestsBase {
@@ -90,6 +89,7 @@
assertNull(mTarget.getDragWindowHandleLocked());
}
+ @FlakyTest(bugId = 69229402)
@Test
public void testHandleTapOutsideTask() {
synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index 4a734e5..dcca316 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -35,9 +35,11 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.annotations.GuardedBy;
@@ -76,6 +78,7 @@
}
@Test
+ @Presubmit
public void testTaskStackChanged_afterFinish() throws Exception {
registerTaskStackChangedListener(new TaskStackListener() {
@Override
@@ -87,7 +90,8 @@
});
Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, ActivityA.class));
+ context.startActivity(
+ new Intent(context, ActivityA.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
UiDevice.getInstance(getInstrumentation()).waitForIdle();
synchronized (sLock) {
assertTrue(sTaskStackChangedCalled);
@@ -96,6 +100,7 @@
}
@Test
+ @FlakyTest(bugId = 119893767)
public void testTaskDescriptionChanged() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -124,6 +129,7 @@
}
@Test
+ @FlakyTest(bugId = 119893767)
public void testActivityRequestedOrientationChanged() throws Exception {
final int[] params = new int[2];
final CountDownLatch latch = new CountDownLatch(1);
@@ -146,6 +152,7 @@
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
+ @FlakyTest(bugId = 119893767)
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
@@ -221,7 +228,8 @@
final ActivityMonitor monitor = new ActivityMonitor(activityClass.getName(), null, false);
getInstrumentation().addMonitor(monitor);
final Context context = getInstrumentation().getContext();
- context.startActivity(new Intent(context, activityClass));
+ context.startActivity(
+ new Intent(context, activityClass).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
final TestActivity activity = (TestActivity) monitor.waitForActivityWithTimeout(1000);
if (activity == null) {
throw new RuntimeException("Timed out waiting for Activity");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index 1c1fe29..e540b3a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -61,7 +61,7 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.quality.Strictness;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* A Test utility class to create a mock {@link WindowManagerService} instance for tests.
@@ -71,6 +71,8 @@
private static WindowManagerService sService;
private static TestWindowManagerPolicy sPolicy;
+ static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false);
+
static void setUpWindowManagerService() {
sMockitoSession = mockitoSession()
.spyStatic(LockGuard.class)
@@ -195,21 +197,23 @@
}
private static void waitHandlerIdle(Handler handler) {
- if (!handler.hasMessagesOrCallbacks()) {
- return;
- }
- final CountDownLatch latch = new CountDownLatch(1);
- // Wait for delayed messages are processed.
- handler.getLooper().getQueue().addIdleHandler(() -> {
- if (handler.hasMessagesOrCallbacks()) {
- return true; // keep idle handler.
+ synchronized (sCurrentMessagesProcessed) {
+ // Add a message to the handler queue and make sure it is fully processed before we move
+ // on. This makes sure all previous messages in the handler are fully processed vs. just
+ // popping them from the message queue.
+ sCurrentMessagesProcessed.set(false);
+ handler.post(() -> {
+ synchronized (sCurrentMessagesProcessed) {
+ sCurrentMessagesProcessed.set(true);
+ sCurrentMessagesProcessed.notifyAll();
+ }
+ });
+ while (!sCurrentMessagesProcessed.get()) {
+ try {
+ sCurrentMessagesProcessed.wait();
+ } catch (InterruptedException e) {
+ }
}
- latch.countDown();
- return false; // remove idle handler.
- });
- try {
- latch.await();
- } catch (InterruptedException e) {
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
index 64ceb1b..d6608f1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -49,7 +49,7 @@
* Test class to for {@link android.app.WindowConfiguration}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowConfigurationTests
+ * atest WmTests:WindowConfigurationTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
index af8ccc9..fc78635 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -26,7 +26,6 @@
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -35,7 +34,7 @@
* Test class for {@link WindowContainerController}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerControllerTests
+ * atest WmTests:WindowContainerControllerTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index a9a76c2..b93c994 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -47,7 +47,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -59,11 +58,10 @@
* Test class for {@link WindowContainer}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowContainerTests
+ * atest WmTests:WindowContainerTests
*/
@SmallTest
@Presubmit
-@FlakyTest(bugId = 74078662)
public class WindowContainerTests extends WindowTestsBase {
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 0a4a8a4..fb30f8b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -449,8 +449,7 @@
// Now simulate switch to fullscreen for letterboxed app.
final int xInset = logicalWidth / 10;
- final int yInset = logicalWidth / 10;
- final Rect cf = new Rect(xInset, yInset, logicalWidth - xInset, logicalHeight - yInset);
+ final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight);
Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration());
config.windowConfiguration.setBounds(cf);
w.mAppToken.onRequestedOverrideConfigurationChanged(config);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index a494889..114eac9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -151,6 +151,7 @@
/** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
public static class TestAppWindowToken extends AppWindowToken {
boolean mOnTop = false;
+ private boolean mSkipPrepareSurfaces;
private Transaction mPendingTransactionOverride;
boolean mSkipOnParentChanged = true;
@@ -213,6 +214,17 @@
return mOnTop;
}
+ @Override
+ void prepareSurfaces() {
+ if (!mSkipPrepareSurfaces) {
+ super.prepareSurfaces();
+ }
+ }
+
+ void setSkipPrepareSurfaces(boolean ignore) {
+ mSkipPrepareSurfaces = ignore;
+ }
+
void setPendingTransaction(Transaction transaction) {
mPendingTransactionOverride = transaction;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d556886..4cdbea0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -28,7 +28,6 @@
import android.platform.test.annotations.Presubmit;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Test;
@@ -37,7 +36,7 @@
* Tests for the {@link WindowToken} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowTokenTests
+ * atest WmTests:WindowTokenTests
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 2970c21..3c6e240 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -58,7 +58,7 @@
* Test class for {@link WindowTracing}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:WindowTracingTest
+ * atest WmTests:WindowTracingTest
*/
@SmallTest
@Presubmit
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 3dcea75..f3b8a62 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -51,9 +51,8 @@
* Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:ZOrderingTests
+ * atest WmTests:ZOrderingTests
*/
-@FlakyTest(bugId = 74078662)
@SmallTest
@Presubmit
public class ZOrderingTests extends WindowTestsBase {
@@ -207,6 +206,7 @@
return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
mDisplayContent.mInputMethodTarget = null;
@@ -224,6 +224,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -243,6 +244,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -269,6 +271,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -292,6 +295,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -319,6 +323,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -333,6 +338,7 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
@@ -398,6 +404,7 @@
assertWindowHigher(mediaOverlayChild, child);
}
+ @FlakyTest(bugId = 124088319)
@Test
public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4539ab3..a1c32b5 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2717,6 +2717,41 @@
Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
RCS_EVENT_QUERY_URI_PATH);
}
+
+ /**
+ * Allows RCS specific canonical address handling.
+ */
+ interface RcsCanonicalAddressHelper {
+ /**
+ * Returns the canonical address ID for a canonical address, if now row exists, this
+ * will add a row and return its ID. This helper works against the same table used by
+ * the SMS and MMS threads, but is accessible only by the phone process for use by RCS
+ * message storage.
+ *
+ * @throws IllegalArgumentException if unable to retrieve or create the canonical
+ * address entry.
+ */
+ static long getOrCreateCanonicalAddressId(
+ ContentResolver contentResolver, String canonicalAddress) {
+
+ Uri.Builder uriBuilder = CONTENT_AND_AUTHORITY.buildUpon();
+ uriBuilder.appendPath("canonical-address");
+ uriBuilder.appendQueryParameter("address", canonicalAddress);
+ Uri uri = uriBuilder.build();
+
+ try (Cursor cursor = contentResolver.query(uri, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getLong(cursor.getColumnIndex(CanonicalAddressesColumns._ID));
+ } else {
+ Rlog.e(TAG, "getOrCreateCanonicalAddressId returned no rows");
+ }
+ }
+
+ Rlog.e(TAG, "getOrCreateCanonicalAddressId failed");
+ throw new IllegalArgumentException(
+ "Unable to find or allocate a canonical address ID");
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index 37847ae..d47b55c 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -27,6 +27,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Contains the list of carrier restrictions.
@@ -93,6 +94,9 @@
value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED})
public @interface CarrierRestrictionDefault {}
+ /* Wild character for comparison */
+ private static final char WILD_CHARACTER = '?';
+
private List<CarrierIdentifier> mAllowedCarriers;
private List<CarrierIdentifier> mExcludedCarriers;
@CarrierRestrictionDefault
@@ -166,6 +170,124 @@
}
/**
+ * Tests an array of carriers with the carrier restriction configuration. The list of carrier
+ * ids passed as argument does not need to be the same as currently present in the device.
+ *
+ * @param carrierIds list of {@link CarrierIdentifier}, one for each SIM slot on the device
+ * @return a list of boolean with the same size as input, indicating if each
+ * {@link CarrierIdentifier} is allowed or not.
+ */
+ public List<Boolean> isCarrierIdentifiersAllowed(@NonNull List<CarrierIdentifier> carrierIds) {
+ ArrayList<Boolean> result = new ArrayList<>(carrierIds.size());
+
+ // First calculate the result for each slot independently
+ for (int i = 0; i < carrierIds.size(); i++) {
+ boolean inAllowedList = isCarrierIdInList(carrierIds.get(i), mAllowedCarriers);
+ boolean inExcludedList = isCarrierIdInList(carrierIds.get(i), mExcludedCarriers);
+ if (mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) {
+ result.add((inAllowedList && !inExcludedList) ? true : false);
+ } else {
+ result.add((inExcludedList && !inAllowedList) ? false : true);
+ }
+ }
+ // Apply the multi-slot policy, if needed.
+ if (mMultiSimPolicy == MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT) {
+ for (boolean b : result) {
+ if (b) {
+ result.replaceAll(x -> true);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Indicates if a certain carrier {@code id} is present inside a {@code list}
+ *
+ * @return true if the carrier {@code id} is present, false otherwise
+ */
+ private static boolean isCarrierIdInList(CarrierIdentifier id, List<CarrierIdentifier> list) {
+ for (CarrierIdentifier listItem : list) {
+ // Compare MCC and MNC
+ if (!patternMatch(id.getMcc(), listItem.getMcc())
+ || !patternMatch(id.getMnc(), listItem.getMnc())) {
+ continue;
+ }
+
+ // Compare SPN. Comparison is on the complete strings, case insensitive and with wild
+ // characters.
+ String listItemValue = convertNullToEmpty(listItem.getSpn());
+ String idValue = convertNullToEmpty(id.getSpn());
+ if (!listItemValue.isEmpty()) {
+ if (!patternMatch(idValue, listItemValue)) {
+ continue;
+ }
+ }
+
+ // The IMSI of the configuration can be shorter than actual IMSI in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getImsi());
+ idValue = convertNullToEmpty(id.getImsi());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // The GID1 of the configuration can be shorter than actual GID1 in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getGid1());
+ idValue = convertNullToEmpty(id.getGid1());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // The GID2 of the configuration can be shorter than actual GID2 in the SIM card.
+ listItemValue = convertNullToEmpty(listItem.getGid2());
+ idValue = convertNullToEmpty(id.getGid2());
+ if (!patternMatch(
+ idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
+ listItemValue)) {
+ continue;
+ }
+
+ // Valid match was found in the list
+ return true;
+ }
+ return false;
+ }
+
+ private static String convertNullToEmpty(String value) {
+ return Objects.toString(value, "");
+ }
+
+ /**
+ * Performs a case insensitive string comparison against a given pattern. The character '?'
+ * is used in the pattern as wild character in the comparison. The string must have the same
+ * length as the pattern.
+ *
+ * @param str string to match
+ * @param pattern string containing the pattern
+ * @return true in case of match, false otherwise
+ */
+ private static boolean patternMatch(String str, String pattern) {
+ if (str.length() != pattern.length()) {
+ return false;
+ }
+ String lowerCaseStr = str.toLowerCase();
+ String lowerCasePattern = pattern.toLowerCase();
+
+ for (int i = 0; i < lowerCasePattern.length(); i++) {
+ if (lowerCasePattern.charAt(i) != lowerCaseStr.charAt(i)
+ && lowerCasePattern.charAt(i) != WILD_CHARACTER) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
* {@link Parcelable#writeToParcel}
*/
@Override
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index fea1b7b..2c9ba1d 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -45,7 +45,8 @@
* <p>
* Override the methods for the state that you wish to receive updates for, and
* pass your PhoneStateListener object, along with bitwise-or of the LISTEN_
- * flags to {@link TelephonyManager#listen TelephonyManager.listen()}.
+ * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. Methods are
+ * called when the state changes, os well as once on initial registration.
* <p>
* Note that access to some telephony information is
* permission-protected. Your application won't receive updates for protected
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f5d452e..2a03924 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10309,11 +10309,14 @@
/**
* Get whether reboot is required or not after making changes to modem configurations.
- * @Return {@code True} if reboot is required after making changes to modem configurations,
- * otherwise return {@code False}.
+ * The modem configuration change refers to switching from single SIM configuration to DSDS
+ * or the other way around.
+ * @Return {@code true} if reboot is required after making changes to modem configurations,
+ * otherwise return {@code false}.
*
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isRebootRequiredForModemConfigChange() {
try {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bc43fea..caa367f 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1837,7 +1837,7 @@
* @hide
*/
boolean isMultisimCarrierRestricted();
-
+
/**
* Switch configs to enable multi-sim or switch back to single-sim
* @hide
@@ -1846,6 +1846,7 @@
/**
* Get if reboot is required upon altering modems configurations
+ * @hide
*/
boolean isRebootRequiredForModemConfigChange();
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
deleted file mode 100644
index 18bde85..0000000
--- a/test-runner/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-# additionally, build unit tests in a separate .apk
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/test-runner/tests/Android.bp b/test-runner/tests/Android.bp
new file mode 100644
index 0000000..03c7398
--- /dev/null
+++ b/test-runner/tests/Android.bp
@@ -0,0 +1,40 @@
+// Copyright 2010, 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.
+
+android_test {
+ name: "FrameworkTestRunnerTests",
+
+ // We only want this apk build for tests.
+ //
+ // Run the tests using the following commands:
+ // adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
+ // adb shell am instrument \
+ // -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
+ // -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner \
+ //
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ static_libs: ["junit"],
+
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+
+ // Because of android.test.mock.
+ platform_apis: true,
+
+}
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
deleted file mode 100644
index f97d1c9..0000000
--- a/test-runner/tests/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2010, 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-#
-# Run the tests using the following commands:
-# adb install -r ${ANDROID_PRODUCT_OUT}/data/app/FrameworkTestRunnerTests/FrameworkTestRunnerTests.apk
-# adb shell am instrument \
- -e notAnnotation android.test.suitebuilder.examples.error.RunAsPartOfSeparateTest \
- -w com.android.frameworks.testrunner.tests/android.test.InstrumentationTestRunner
-#
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests
-# Because of android.test.mock.
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e2d59d6..a7c95c7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -554,7 +554,7 @@
if (mNmValidationRedirectUrl != null) {
mNmCallbacks.showProvisioningNotification(
- "test_provisioning_notif_action");
+ "test_provisioning_notif_action", "com.android.test.package");
mNmProvNotificationRequested = true;
}
} catch (RemoteException e) {
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index b635607..a4a735d 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -35,6 +35,7 @@
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -274,6 +275,11 @@
isTetheringSupportedCalls++;
return true;
}
+
+ @Override
+ public int getDefaultDataSubscriptionId() {
+ return INVALID_SUBSCRIPTION_ID;
+ }
}
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index ec286759..193f380 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -21,6 +21,7 @@
import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -140,7 +141,8 @@
mMockContext = new MockContext(mContext);
mSM = new TestStateMachine();
mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
}
@After
@@ -168,7 +170,8 @@
@Test
public void canRequireProvisioning() {
setupForRequiredProvisioning();
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -177,7 +180,8 @@
setupForRequiredProvisioning();
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
// Therefore provisioning still be required.
assertTrue(mEnMgr.isTetherProvisioningRequired());
@@ -187,7 +191,8 @@
public void toleratesCarrierConfigMissing() {
setupForRequiredProvisioning();
when(mCarrierConfigManager.getConfig()).thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
// We still have a provisioning app configured, so still require provisioning.
assertTrue(mEnMgr.isTetherProvisioningRequired());
}
@@ -197,11 +202,13 @@
setupForRequiredProvisioning();
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(null);
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertFalse(mEnMgr.isTetherProvisioningRequired());
when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
.thenReturn(new String[] {"malformedApp"});
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
assertFalse(mEnMgr.isTetherProvisioningRequired());
}
@@ -223,7 +230,8 @@
assertFalse(mEnMgr.everRunUiEntitlement);
setupForRequiredProvisioning();
- mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog));
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+ INVALID_SUBSCRIPTION_ID));
// 2. No cache value and don't need to run entitlement check.
mEnMgr.everRunUiEntitlement = false;
receiver = new ResultReceiver(null) {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 5217784..01b904d8 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -22,10 +22,12 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_NOT_REQUIRED;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_REQUIRED;
import static com.android.server.connectivity.tethering.TetheringConfiguration.DUN_UNSPECIFIED;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,26 +46,39 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import java.util.Iterator;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Iterator;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TetheringConfigurationTest {
private final SharedLog mLog = new SharedLog("TetheringConfigurationTest");
+
+ private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
@Mock private Context mContext;
@Mock private TelephonyManager mTelephonyManager;
@Mock private Resources mResources;
+ @Mock private Resources mResourcesForSubId;
private MockContentResolver mContentResolver;
private Context mMockContext;
private boolean mHasTelephonyManager;
+ private class MockTetheringConfiguration extends TetheringConfiguration {
+ MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ super(ctx, log, id);
+ }
+
+ @Override
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return mResourcesForSubId;
+ }
+ }
+
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
super(base);
@@ -99,6 +114,9 @@
.thenReturn(new String[0]);
when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
.thenReturn(new int[0]);
+ when(mResources.getStringArray(
+ com.android.internal.R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(new String[0]);
mContentResolver = new MockContentResolver();
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
mMockContext = new MockContext(mContext);
@@ -111,7 +129,8 @@
mHasTelephonyManager = true;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.isDunRequired);
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -127,7 +146,8 @@
mHasTelephonyManager = true;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertFalse(cfg.isDunRequired);
assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -143,7 +163,8 @@
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.isDunRequired);
assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
// Just to prove we haven't clobbered Wi-Fi:
@@ -160,7 +181,8 @@
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
@@ -181,7 +203,8 @@
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_ETHERNET, upstreamIterator.next().intValue());
@@ -199,7 +222,8 @@
mHasTelephonyManager = false;
when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
final Iterator<Integer> upstreamIterator = cfg.preferredUpstreamIfaceTypes.iterator();
assertTrue(upstreamIterator.hasNext());
assertEquals(TYPE_WIFI, upstreamIterator.next().intValue());
@@ -214,7 +238,8 @@
public void testNewDhcpServerDisabled() {
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertTrue(cfg.enableLegacyDhcpServer);
}
@@ -222,7 +247,41 @@
public void testNewDhcpServerEnabled() {
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
- final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
assertFalse(cfg.enableLegacyDhcpServer);
}
+
+ @Test
+ public void testGetResourcesBySubId() {
+ setUpResourceForSubId();
+ final TetheringConfiguration cfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(cfg.provisioningApp.length == 0);
+ final int anyValidSubId = 1;
+ final MockTetheringConfiguration mockCfg =
+ new MockTetheringConfiguration(mMockContext, mLog, anyValidSubId);
+ assertEquals(mockCfg.provisioningApp[0], PROVISIONING_APP_NAME[0]);
+ assertEquals(mockCfg.provisioningApp[1], PROVISIONING_APP_NAME[1]);
+ }
+
+ private void setUpResourceForSubId() {
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_dhcp_range)).thenReturn(new String[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_usb_regexs)).thenReturn(new String[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResourcesForSubId.getIntArray(
+ com.android.internal.R.array.config_tether_upstream_types))
+ .thenReturn(new int[0]);
+ when(mResourcesForSubId.getStringArray(
+ com.android.internal.R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(PROVISIONING_APP_NAME);
+ }
+
}
diff --git a/tools/preload/Android.bp b/tools/preload/Android.bp
new file mode 100644
index 0000000..809ee47
--- /dev/null
+++ b/tools/preload/Android.bp
@@ -0,0 +1,17 @@
+java_library_host {
+ name: "preload",
+ srcs: [
+ "Compile.java",
+ "LoadedClass.java",
+ "MemoryUsage.java",
+ "Operation.java",
+ "Policy.java",
+ "PrintCsv.java",
+ "PrintHtmlDiff.java",
+ "PrintPsTree.java",
+ "Proc.java",
+ "Record.java",
+ "Root.java",
+ "WritePreloadedClassFile.java",
+ ],
+}
diff --git a/tools/preload/Android.mk b/tools/preload/Android.mk
deleted file mode 100644
index 14a4547..0000000
--- a/tools/preload/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- Compile.java \
- LoadedClass.java \
- MemoryUsage.java \
- Operation.java \
- Policy.java \
- PrintCsv.java \
- PrintHtmlDiff.java \
- PrintPsTree.java \
- Proc.java \
- Record.java \
- Root.java \
- WritePreloadedClassFile.java
-
-LOCAL_MODULE:= preload
-
-include $(BUILD_HOST_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/preload/loadclass/Android.bp b/tools/preload/loadclass/Android.bp
new file mode 100644
index 0000000..6f12015
--- /dev/null
+++ b/tools/preload/loadclass/Android.bp
@@ -0,0 +1,4 @@
+java_test {
+ name: "loadclass",
+ srcs: ["**/*.java"],
+}
diff --git a/tools/preload/loadclass/Android.mk b/tools/preload/loadclass/Android.mk
deleted file mode 100644
index 65828be..0000000
--- a/tools/preload/loadclass/Android.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE := loadclass
-
-include $(BUILD_JAVA_LIBRARY)
diff --git a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
new file mode 100644
index 0000000..4ddf872
--- /dev/null
+++ b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.aware;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable {@link PeerHandle}. Can be constructed from a {@code PeerHandle} and then passed
+ * to any of the APIs which take a {@code PeerHandle} as inputs.
+ */
+public final class ParcelablePeerHandle extends PeerHandle implements Parcelable {
+ /**
+ * Construct a parcelable version of {@link PeerHandle}.
+ *
+ * @param peerHandle The {@link PeerHandle} to be made parcelable.
+ */
+ public ParcelablePeerHandle(PeerHandle peerHandle) {
+ super(peerHandle.peerId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(peerId);
+ }
+
+ public static final Creator<ParcelablePeerHandle> CREATOR =
+ new Creator<ParcelablePeerHandle>() {
+ @Override
+ public ParcelablePeerHandle[] newArray(int size) {
+ return new ParcelablePeerHandle[size];
+ }
+
+ @Override
+ public ParcelablePeerHandle createFromParcel(Parcel in) {
+ int peerHandle = in.readInt();
+ return new ParcelablePeerHandle(new PeerHandle(peerHandle));
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index 1603d00..422e177 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -16,9 +16,6 @@
package android.net.wifi.aware;
-import android.os.Parcel;
-import android.os.Parcelable;
-
/**
* Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or
@@ -35,8 +32,9 @@
* configuration's service-specific information field,
* {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter,
* {@link PublishConfig.Builder#setMatchFilter(java.util.List)}.
+ * <p>A parcelable handle object is available with {@link ParcelablePeerHandle}.
*/
-public final class PeerHandle implements Parcelable {
+public class PeerHandle {
/** @hide */
public PeerHandle(int peerId) {
this.peerId = peerId;
@@ -62,29 +60,4 @@
public int hashCode() {
return peerId;
}
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(peerId);
- }
-
- public static final Creator<PeerHandle> CREATOR = new Creator<PeerHandle>() {
- @Override
- public PeerHandle[] newArray(int size) {
- return new PeerHandle[size];
- }
-
- @Override
- public PeerHandle createFromParcel(Parcel in) {
- int peerHandle = in.readInt();
-
- return new PeerHandle(peerHandle);
- }
- };
-
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 6da6d4a..3cc96bf 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1614,23 +1614,31 @@
assertEquals(cap.hashCode(), rereadCap.hashCode());
}
- // PeerHandle tests
+ // ParcelablePeerHandle tests
+ /**
+ * Verify parceling of ParcelablePeerHandle and interoperability with PeerHandle.
+ */
@Test
- public void testPeerHandleParcel() {
+ public void testParcelablePeerHandleParcel() {
final PeerHandle peerHandle = new PeerHandle(5);
+ final ParcelablePeerHandle parcelablePeerHandle = new ParcelablePeerHandle(peerHandle);
Parcel parcelW = Parcel.obtain();
- peerHandle.writeToParcel(parcelW, 0);
+ parcelablePeerHandle.writeToParcel(parcelW, 0);
byte[] bytes = parcelW.marshall();
parcelW.recycle();
Parcel parcelR = Parcel.obtain();
parcelR.unmarshall(bytes, 0, bytes.length);
parcelR.setDataPosition(0);
- PeerHandle rereadPeerHandle = PeerHandle.CREATOR.createFromParcel(parcelR);
+ ParcelablePeerHandle rereadParcelablePeerHandle =
+ ParcelablePeerHandle.CREATOR.createFromParcel(parcelR);
- assertEquals(peerHandle, rereadPeerHandle);
- assertEquals(peerHandle.hashCode(), rereadPeerHandle.hashCode());
+ assertEquals(peerHandle, rereadParcelablePeerHandle);
+ assertEquals(peerHandle.hashCode(), rereadParcelablePeerHandle.hashCode());
+ assertEquals(parcelablePeerHandle, rereadParcelablePeerHandle);
+ assertEquals(parcelablePeerHandle.hashCode(), rereadParcelablePeerHandle.hashCode());
+
}
}