Merge "Add support for illustrations to SimAppDialog."
diff --git a/Android.bp b/Android.bp
index e669307..65f232d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -181,6 +181,7 @@
"core/java/android/hardware/input/IInputManager.aidl",
"core/java/android/hardware/input/IInputDevicesChangedListener.aidl",
"core/java/android/hardware/input/ITabletModeChangedListener.aidl",
+ "core/java/android/hardware/iris/IIrisService.aidl",
"core/java/android/hardware/location/IActivityRecognitionHardware.aidl",
"core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl",
"core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl",
@@ -594,6 +595,8 @@
"telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl",
+ "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl",
"wifi/java/android/net/wifi/ISoftApCallback.aidl",
"wifi/java/android/net/wifi/ITrafficStateCallback.aidl",
"wifi/java/android/net/wifi/IWifiManager.aidl",
@@ -692,6 +695,7 @@
],
static_libs: [
+ "apex_aidl_interface-java",
"framework-protos",
"mediaplayer2-protos",
"android.hidl.base-V1.0-java",
diff --git a/api/current.txt b/api/current.txt
index 3deb15a..dd4c781 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -28690,7 +28690,7 @@
enum_constant public static final android.net.wifi.SupplicantState UNINITIALIZED;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
method public android.net.ProxyInfo getHttpProxy();
@@ -28844,7 +28844,8 @@
}
public class WifiManager {
- method public int addNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int addNetwork(android.net.wifi.WifiConfiguration);
+ method public boolean addNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>, android.app.PendingIntent);
method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration);
method public static int calculateSignalLevel(int, int);
method public deprecated void cancelWps(android.net.wifi.WifiManager.WpsCallback);
@@ -28852,10 +28853,10 @@
method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
method public android.net.wifi.WifiManager.WifiLock createWifiLock(java.lang.String);
- method public boolean disableNetwork(int);
- method public boolean disconnect();
- method public boolean enableNetwork(int, boolean);
- method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
+ method public deprecated boolean disableNetwork(int);
+ method public deprecated boolean disconnect();
+ method public deprecated boolean enableNetwork(int, boolean);
+ method public deprecated java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
@@ -28870,18 +28871,19 @@
method public boolean isTdlsSupported();
method public boolean isWifiEnabled();
method public deprecated boolean pingSupplicant();
- method public boolean reassociate();
- method public boolean reconnect();
- method public boolean removeNetwork(int);
+ method public deprecated boolean reassociate();
+ method public deprecated boolean reconnect();
+ method public deprecated boolean removeNetwork(int);
+ method public boolean removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
method public void removePasspointConfiguration(java.lang.String);
method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
- method public boolean setWifiEnabled(boolean);
+ method public deprecated boolean setWifiEnabled(boolean);
method public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, android.os.Handler);
method public deprecated boolean startScan();
method public deprecated void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
- method public int updateNetwork(android.net.wifi.WifiConfiguration);
+ method public deprecated int updateNetwork(android.net.wifi.WifiConfiguration);
field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
@@ -28955,6 +28957,29 @@
method public abstract deprecated void onSucceeded();
}
+ public class WifiNetworkConfigBuilder {
+ ctor public WifiNetworkConfigBuilder();
+ method public android.net.NetworkSpecifier buildNetworkSpecifier();
+ method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
+ method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
+ method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
+ }
+
+ public final class WifiNetworkSuggestion implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.WifiNetworkSuggestion> CREATOR;
+ }
+
public deprecated class WpsInfo implements android.os.Parcelable {
ctor public deprecated WpsInfo();
ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
@@ -42925,7 +42950,6 @@
method public int getLevel();
method public int getRsrp();
method public int getRsrq();
- method public int getRssi();
method public int getRssnr();
method public int getTimingAdvance();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3074efd..d8da475 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3615,7 +3615,7 @@
field public byte id;
}
- public class WifiConfiguration implements android.os.Parcelable {
+ public deprecated class WifiConfiguration implements android.os.Parcelable {
method public boolean hasNoInternetAccess();
method public boolean isEphemeral();
method public boolean isNoInternetAccessExpected();
@@ -3644,8 +3644,10 @@
method public boolean isPortableHotspotSupported();
method public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
+ method public void registerNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback, android.os.Handler);
method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method public boolean startScan(android.os.WorkSource);
+ method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
field public static final int CHANGE_REASON_CONFIG_CHANGE = 2; // 0x2
field public static final int CHANGE_REASON_REMOVED = 1; // 0x1
@@ -3673,6 +3675,18 @@
method public abstract void onSuccess();
}
+ public static abstract interface WifiManager.NetworkRequestMatchCallback {
+ method public abstract void onMatch(java.util.List<android.net.wifi.WifiConfiguration>);
+ method public abstract void onUserSelectionCallbackRegistration(android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback);
+ method public abstract void onUserSelectionConnectFailure(android.net.wifi.WifiConfiguration);
+ method public abstract void onUserSelectionConnectSuccess(android.net.wifi.WifiConfiguration);
+ }
+
+ public static abstract interface WifiManager.NetworkRequestUserSelectionCallback {
+ method public abstract void reject();
+ method public abstract void select(android.net.wifi.WifiConfiguration);
+ }
+
public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
ctor public WifiNetworkConnectionStatistics(int, int);
ctor public WifiNetworkConnectionStatistics();
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 12e2560a..065f49e 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -276,22 +276,21 @@
*/
void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
- vector<uint8_t>* outData) {
+ ProtoOutputStream* proto) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
- ProtoOutputStream proto;
-
// Start of ConfigKey.
- uint64_t configKeyToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
- proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
- proto.write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
- proto.end(configKeyToken);
+ uint64_t configKeyToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+ proto->write(FIELD_TYPE_INT32 | FIELD_ID_UID, key.GetUid());
+ proto->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)key.GetId());
+ proto->end(configKeyToken);
// End of ConfigKey.
// Then, check stats-data directory to see there's any file containing
// ConfigMetricsReport from previous shutdowns to concatenate to reports.
- StorageManager::appendConfigMetricsReport(key, &proto);
+ StorageManager::appendConfigMetricsReport(key, proto);
auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
@@ -301,14 +300,27 @@
// Start of ConfigMetricsReport (reports).
uint64_t reportsToken =
- proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
+ proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
- dumpReportReason, &proto);
- proto.end(reportsToken);
+ erase_data, dumpReportReason, proto);
+ proto->end(reportsToken);
// End of ConfigMetricsReport (reports).
} else {
ALOGW("Config source %s does not exist", key.ToString().c_str());
}
+}
+
+/*
+ * onDumpReport dumps serialized ConfigMetricsReportList into outData.
+ */
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, const int64_t dumpTimeStampNs,
+ const bool include_current_partial_bucket,
+ const bool erase_data,
+ const DumpReportReason dumpReportReason,
+ vector<uint8_t>* outData) {
+ ProtoOutputStream proto;
+ onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ dumpReportReason, &proto);
if (outData != nullptr) {
outData->clear();
@@ -332,6 +344,7 @@
void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key,
const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
ProtoOutputStream* proto) {
// We already checked whether key exists in mMetricsManagers in
@@ -348,7 +361,7 @@
// First, fill in ConfigMetricsReport using current data on memory, which
// starts from filling in StatsLogReport's.
it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
- &str_set, proto);
+ erase_data, &str_set, proto);
// Fill in UidMap if there is at least one metric to report.
// This skips the uid map if it's an empty config.
@@ -479,7 +492,7 @@
}
ProtoOutputStream proto;
onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
- dumpReportReason, &proto);
+ true /* erase_data */, dumpReportReason, &proto);
string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
(long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
android::base::unique_fd fd(open(file_name.c_str(),
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 3e8b9b8..ecfd819 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -61,8 +61,11 @@
size_t GetMetricsSize(const ConfigKey& key) const;
void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
- const bool include_current_partial_bucket,
+ const bool include_current_partial_bucket, const bool erase_data,
const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
+ void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
+ const bool include_current_partial_bucket, const bool erase_data,
+ const DumpReportReason dumpReportReason, ProtoOutputStream* proto);
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
void onAnomalyAlarmFired(
@@ -141,6 +144,7 @@
void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
const DumpReportReason dumpReportReason,
util::ProtoOutputStream* proto);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index ce28777..27685fc 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -46,6 +46,8 @@
using namespace android;
using android::base::StringPrintf;
+using android::util::FIELD_COUNT_REPEATED;
+using android::util::FIELD_TYPE_MESSAGE;
namespace android {
namespace os {
@@ -58,6 +60,9 @@
#define STATS_SERVICE_DIR "/data/misc/stats-service"
+// for StatsDataDumpProto
+const int FIELD_ID_REPORTS_LIST = 1;
+
static binder::Status ok() {
return binder::Status::ok();
}
@@ -224,31 +229,48 @@
}
/**
- * Write debugging data about statsd.
+ * Write data from statsd.
+ * Format for statsdStats: adb shell dumpsys stats --metadata [-v] [--proto]
+ * Format for data report: adb shell dumpsys stats [anything other than --metadata] [--proto]
+ * Anything ending in --proto will be in proto format.
+ * Anything without --metadata as the first argument will be report information.
+ * (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
+ * TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
if (!checkCallingPermission(String16(kPermissionDump))) {
return PERMISSION_DENIED;
}
-
- bool verbose = false;
- bool proto = false;
- if (args.size() > 0 && !args[0].compare(String16("-v"))) {
- verbose = true;
+ int lastArg = args.size() - 1;
+ bool asProto = false;
+ if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument
+ asProto = true;
+ lastArg--;
}
- if (args.size() > 0 && !args[args.size()-1].compare(String16("--proto"))) {
- proto = true;
+ if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument
+ // Request is to dump statsd stats.
+ bool verbose = false;
+ if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) {
+ verbose = true;
+ lastArg--;
+ }
+ dumpStatsdStats(fd, verbose, asProto);
+ } else {
+ // Request is to dump statsd report data.
+ if (asProto) {
+ dumpIncidentSection(fd);
+ } else {
+ dprintf(fd, "Non-proto format of stats data dump not available; see proto version.\n");
+ }
}
- dump_impl(fd, verbose, proto);
-
return NO_ERROR;
}
/**
* Write debugging data about statsd in text or proto format.
*/
-void StatsService::dump_impl(int out, bool verbose, bool proto) {
+void StatsService::dumpStatsdStats(int out, bool verbose, bool proto) {
if (proto) {
vector<uint8_t> data;
StatsdStats::getInstance().dumpStats(&data, false); // does not reset statsdStats.
@@ -262,6 +284,22 @@
}
/**
+ * Write stats report data in StatsDataDumpProto incident section format.
+ */
+void StatsService::dumpIncidentSection(int out) {
+ ProtoOutputStream proto;
+ for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) {
+ uint64_t reportsListToken =
+ proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
+ mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
+ true /* includeCurrentBucket */, false /* erase_data */,
+ ADB_DUMP, &proto);
+ proto.end(reportsListToken);
+ proto.flush(out);
+ }
+}
+
+/**
* Implementation of the adb shell cmd stats command.
*/
status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
@@ -283,7 +321,7 @@
}
if (!args[0].compare(String8("dump-report"))) {
- return cmd_dump_report(out, err, args);
+ return cmd_dump_report(out, args);
}
if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
@@ -546,7 +584,7 @@
return UNKNOWN_ERROR;
}
-status_t StatsService::cmd_dump_report(int out, int err, const Vector<String8>& args) {
+status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
if (mProcessor != nullptr) {
int argCount = args.size();
bool good = false;
@@ -589,14 +627,13 @@
if (good) {
vector<uint8_t> data;
mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
- includeCurrentBucket, ADB_DUMP, &data);
+ includeCurrentBucket, true /* erase_data */, ADB_DUMP, &data);
if (proto) {
for (size_t i = 0; i < data.size(); i ++) {
dprintf(out, "%c", data[i]);
}
} else {
- dprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
- dprintf(out, "See the StatsLogReport in logcat...\n");
+ dprintf(out, "Non-proto stats data dump not currently supported.\n");
}
return android::OK;
} else {
@@ -888,7 +925,7 @@
VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
ConfigKey configKey(ipc->getCallingUid(), key);
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
- GET_DATA_CALLED, output);
+ true /* erase_data */, GET_DATA_CALLED, output);
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index cbf3429..4a5f05f 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -213,9 +213,14 @@
uint32_t serial);
/**
- * Text or proto output of dumpsys.
+ * Proto output of statsd report data dumpsys, wrapped in a StatsDataDumpProto.
*/
- void dump_impl(int outFd, bool verbose, bool proto);
+ void dumpIncidentSection(int outFd);
+
+ /**
+ * Text or proto output of statsdStats dumpsys.
+ */
+ void dumpStatsdStats(int outFd, bool verbose, bool proto);
/**
* Print usage information for the commands
@@ -240,7 +245,7 @@
/**
* Print the event log.
*/
- status_t cmd_dump_report(int outFd, int err, const Vector<String8>& args);
+ status_t cmd_dump_report(int outFd, const Vector<String8>& args);
/**
* Print the mapping of uids to package names.
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 6b8c12a..eddc86e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -82,7 +82,9 @@
// Create the service
gStatsService = new StatsService(looper);
- if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
+ if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
+ != 0) {
ALOGE("Failed to add service as AIDL service");
return -1;
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index bd94800..5ca8814 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -143,6 +143,7 @@
void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -230,7 +231,9 @@
protoOutput->end(protoToken);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ }
}
void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 39d4ae2..1ac44264 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -56,6 +56,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index dd3402d..35deffe 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -453,6 +453,7 @@
void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (include_current_partial_bucket) {
@@ -541,7 +542,9 @@
}
protoOutput->end(protoToken);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ }
}
void DurationMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 12addb8..1b830a3 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -63,6 +63,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index afd8ec2..a18e406 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -105,6 +105,7 @@
void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
if (mProto->size() <= 0) {
@@ -120,7 +121,9 @@
protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
- mProto->clear();
+ if (erase_data) {
+ mProto->clear();
+ }
}
void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 7f7aa37..96adfdd 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -47,6 +47,7 @@
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index f5a16e9..05103a9 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -182,6 +182,7 @@
void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("Gauge metric %lld report now...", (long long)mMetricId);
@@ -226,7 +227,6 @@
(long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
- mSkippedBuckets.clear();
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
@@ -304,7 +304,11 @@
}
protoOutput->end(protoToken);
- mPastBuckets.clear();
+
+ if (erase_data) {
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+ }
}
void GaugeMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 99827bb..5866139 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -94,6 +94,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index b21fd50..127cbbd 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -133,10 +133,12 @@
// This method clears all the past buckets.
void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) {
std::lock_guard<std::mutex> lock(mMutex);
- return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, str_set, protoOutput);
+ return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
+ str_set, protoOutput);
}
void clearPastBuckets(const int64_t dumpTimeNs) {
@@ -210,6 +212,7 @@
const int64_t eventTime) = 0;
virtual void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) = 0;
virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index f85ba1f..4244d5b 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -197,6 +197,7 @@
void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("=========================Metric Reports Start==========================");
@@ -206,11 +207,11 @@
uint64_t token = protoOutput->start(
FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
if (mHashStringsInReport) {
- producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, str_set,
- protoOutput);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ str_set, protoOutput);
} else {
- producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, nullptr,
- protoOutput);
+ producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
+ nullptr, protoOutput);
}
protoOutput->end(token);
} else {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 649222ff..a4672b6 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -107,6 +107,7 @@
virtual void onDumpReport(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput);
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 192a54b..6367479 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -170,6 +170,7 @@
void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
ProtoOutputStream* protoOutput) {
VLOG("metric %lld dump report now...", (long long)mMetricId);
@@ -211,7 +212,6 @@
(long long)(NanoToMillis(pair.second)));
protoOutput->end(wrapperToken);
}
- mSkippedBuckets.clear();
for (const auto& pair : mPastBuckets) {
const MetricDimensionKey& dimensionKey = pair.first;
@@ -271,7 +271,10 @@
protoOutput->end(protoToken);
VLOG("metric %lld dump report now...", (long long)mMetricId);
- mPastBuckets.clear();
+ if (erase_data) {
+ mPastBuckets.clear();
+ mSkippedBuckets.clear();
+ }
}
void ValueMetricProducer::onConditionChangedLocked(const bool condition,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b2f0b6f..8db2d95 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -94,6 +94,7 @@
private:
void onDumpReportLocked(const int64_t dumpTimeNs,
const bool include_current_partial_bucket,
+ const bool erase_data,
std::set<string> *str_set,
android::util::ProtoOutputStream* protoOutput) override;
void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index b6f635c..8864252 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -168,7 +168,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -197,7 +197,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
@@ -227,7 +227,7 @@
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
- p.onDumpReport(key, 1, false, ADB_DUMP, &bytes);
+ p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
ConfigMetricsReportList output;
output.ParseFromArray(bytes.data(), bytes.size());
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a8fcc81..5c47af7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -144,8 +144,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -290,8 +290,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index 75bd40f..a8914da 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -212,7 +212,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -548,7 +548,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -798,7 +798,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index c5a8a2e..621b6ed 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -130,8 +130,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -346,8 +346,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -530,8 +530,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -732,8 +732,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 5bcc9ee..9f8acaf 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -143,7 +143,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -438,7 +438,7 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
- ADB_DUMP, &buffer);
+ true, ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -658,8 +658,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index d7b9c11..2d090e0 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -123,8 +123,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -246,8 +246,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -350,8 +350,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 5c1ef01..71afedf 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -149,8 +149,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 0f13a4a..29e86f3 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -167,8 +167,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index cc8894b..9349c85 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -199,8 +199,8 @@
}
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -318,8 +318,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 67acd61..3cb553f 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
- ADB_DUMP, &output);
+ true /* erase_data */, ADB_DUMP, &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index f2e8f58..fed5a3f 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -117,8 +117,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -224,8 +224,8 @@
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index b9d0c62..6d1317c 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -127,8 +127,8 @@
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -164,8 +164,8 @@
FeedEvents(config, processor);
vector<uint8_t> buffer;
ConfigMetricsReportList reports;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -215,8 +215,8 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -248,8 +248,8 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -277,8 +277,8 @@
FeedEvents(config, processor);
ConfigMetricsReportList reports;
vector<uint8_t> buffer;
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
@@ -323,8 +323,8 @@
processor->OnLogEvent(event.get());
}
- processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, ADB_DUMP,
- &buffer);
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
+ ADB_DUMP, &buffer);
EXPECT_TRUE(buffer.size() > 0);
EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
backfillDimensionPath(&reports);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 508ea3b..f267169 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -66,6 +66,8 @@
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.input.InputManager;
+import android.hardware.iris.IrisManager;
+import android.hardware.iris.IIrisService;
import android.hardware.location.ContextHubManager;
import android.hardware.radio.RadioManager;
import android.hardware.usb.IUsbManager;
@@ -836,6 +838,18 @@
}
});
+ registerService(Context.IRIS_SERVICE, IrisManager.class,
+ new CachedServiceFetcher<IrisManager>() {
+ @Override
+ public IrisManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ final IBinder binder =
+ ServiceManager.getServiceOrThrow(Context.IRIS_SERVICE);
+ IIrisService service = IIrisService.Stub.asInterface(binder);
+ return new IrisManager(ctx.getOuterContext(), service);
+ }
+ });
+
registerService(Context.BIOMETRIC_SERVICE, BiometricManager.class,
new CachedServiceFetcher<BiometricManager>() {
@Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e378800..6a7829b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3706,6 +3706,17 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.hardware.iris.IrisManager} for handling management
+ * of iris authentication.
+ *
+ * @hide
+ * @see #getSystemService
+ * @see android.hardware.iris.IrisManager
+ */
+ public static final String IRIS_SERVICE = "iris";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.hardware.biometrics.BiometricManager} for handling management
* of face authentication.
*
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1f700f7..67b86c0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -855,6 +855,14 @@
*/
public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that this package
+ * is an APEX package
+ *
+ * @hide
+ */
+ public static final int INSTALL_APEX = 0x00020000;
+
/** @hide */
@IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
DONT_KILL_APP
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index a8bbeab..096301c 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -25,6 +25,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -78,6 +79,7 @@
private final @Type int mType;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
+ private List<SharedLibraryInfo> mDependencies;
/**
* Creates a new instance.
@@ -91,7 +93,8 @@
* @hide
*/
public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
- VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
+ VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
+ List<SharedLibraryInfo> dependencies) {
mPath = path;
mPackageName = packageName;
mName = name;
@@ -99,11 +102,13 @@
mType = type;
mDeclaringPackage = declaringPackage;
mDependentPackages = dependentPackages;
+ mDependencies = dependencies;
}
private SharedLibraryInfo(Parcel parcel) {
this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
- parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null));
+ parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
+ parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
}
/**
@@ -150,6 +155,47 @@
}
/**
+ * Add a library dependency to that library. Note that this
+ * should be called under the package manager lock.
+ *
+ * @hide
+ */
+ public void addDependency(@Nullable SharedLibraryInfo info) {
+ if (info == null) {
+ // For convenience of the caller, allow null to be passed.
+ // This can happen when we create the dependencies of builtin
+ // libraries.
+ return;
+ }
+ if (mDependencies == null) {
+ mDependencies = new ArrayList<>();
+ }
+ mDependencies.add(info);
+ }
+
+ /**
+ * Clear all dependencies.
+ *
+ * @hide
+ */
+ public void clearDependencies() {
+ mDependencies = null;
+ }
+
+ /**
+ * Gets the libraries this library directly depends on. Note that
+ * the package manager prevents recursive dependencies when installing
+ * a package.
+ *
+ * @return The dependencies.
+ *
+ * @hide
+ */
+ public @Nullable List<SharedLibraryInfo> getDependencies() {
+ return mDependencies;
+ }
+
+ /**
* @deprecated Use {@link #getLongVersion()} instead.
*/
@Deprecated
@@ -232,6 +278,7 @@
parcel.writeInt(mType);
parcel.writeParcelable(mDeclaringPackage, flags);
parcel.writeList(mDependentPackages);
+ parcel.writeTypedList(mDependencies);
}
private static String typeToString(int type) {
diff --git a/core/java/android/content/pm/SharedLibraryNames.java b/core/java/android/content/pm/SharedLibraryNames.java
index 387d29e8..5afc8a9 100644
--- a/core/java/android/content/pm/SharedLibraryNames.java
+++ b/core/java/android/content/pm/SharedLibraryNames.java
@@ -22,15 +22,15 @@
*/
public class SharedLibraryNames {
- static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
+ public static final String ANDROID_HIDL_BASE = "android.hidl.base-V1.0-java";
- static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
+ public static final String ANDROID_HIDL_MANAGER = "android.hidl.manager-V1.0-java";
- static final String ANDROID_TEST_BASE = "android.test.base";
+ public static final String ANDROID_TEST_BASE = "android.test.base";
- static final String ANDROID_TEST_MOCK = "android.test.mock";
+ public static final String ANDROID_TEST_MOCK = "android.test.mock";
- static final String ANDROID_TEST_RUNNER = "android.test.runner";
+ public static final String ANDROID_TEST_RUNNER = "android.test.runner";
- static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
+ public static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0350eff..5f23749 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1064,6 +1064,17 @@
}
}
+ @UnsupportedAppUsage
+ void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) {
+ synchronized (this) {
+ ensureValidLocked();
+ synchronized (srcAssetManager) {
+ srcAssetManager.ensureValidLocked();
+ nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr);
+ }
+ }
+ }
+
@Override
protected void finalize() throws Throwable {
if (DEBUG_REFS && mNumRefs != 0) {
@@ -1375,7 +1386,8 @@
private static native void nativeThemeDestroy(long themePtr);
private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
boolean force);
- static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
+ private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr,
+ long srcAssetManagerPtr, long srcThemePtr);
static native void nativeThemeClear(long themePtr);
private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
@AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 1d1eaf3..2ad4f62 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -1336,7 +1336,7 @@
void setTo(ThemeImpl other) {
synchronized (mKey) {
synchronized (other.mKey) {
- AssetManager.nativeThemeCopy(mTheme, other.mTheme);
+ mAssets.setThemeTo(mTheme, other.mAssets, other.mTheme);
mThemeResId = other.mThemeResId;
mKey.setTo(other.getKey());
diff --git a/core/java/android/hardware/iris/IIrisService.aidl b/core/java/android/hardware/iris/IIrisService.aidl
new file mode 100644
index 0000000..8cf3c13
--- /dev/null
+++ b/core/java/android/hardware/iris/IIrisService.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.iris;
+
+/**
+ * Communication channel from client to the iris service. These methods are all require the
+ * MANAGE_BIOMETRIC signature permission.
+ * @hide
+ */
+interface IIrisService {
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/iris/IrisManager.java b/core/java/android/hardware/iris/IrisManager.java
new file mode 100644
index 0000000..281ac47
--- /dev/null
+++ b/core/java/android/hardware/iris/IrisManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.hardware.iris;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * A class that coordinates access to the iris authentication hardware.
+ * @hide
+ */
+@SystemService(Context.IRIS_SERVICE)
+public class IrisManager {
+
+ /**
+ * @hide
+ */
+ public IrisManager(Context context, IIrisService service) {
+ }
+}
diff --git a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java b/core/java/android/hardware/location/ContextHubBroadcastReceiver.java
deleted file mode 100644
index e0cc8b7..0000000
--- a/core/java/android/hardware/location/ContextHubBroadcastReceiver.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.location;
-
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-
-/**
- * A BroadcastReceiver that can be used with the Context Hub Service notifications.
- *
- * @hide
- */
-public class ContextHubBroadcastReceiver extends BroadcastReceiver {
- // The context at which this receiver operates in
- private Context mContext;
-
- // The handler to post callbacks to when receiving Context Hub Service intents
- private Handler mHandler;
-
- // The callback to be invoked when receiving Context Hub Service intents
- private ContextHubClientCallback mCallback;
-
- // The string to use as the broadcast action for this receiver
- private String mAction;
-
- // True when this receiver is registered to receive Intents, false otherwise
- private boolean mRegistered = false;
-
- public ContextHubBroadcastReceiver(Context context, Handler handler,
- ContextHubClientCallback callback, String tag) {
- mContext = context;
- mHandler = handler;
- mCallback = callback;
- mAction = tag;
- }
-
- /**
- * Registers this receiver to receive Intents from the Context Hub Service. This method must
- * only be invoked when the receiver is not registered.
- *
- * @throws IllegalStateException if the receiver is already registered
- */
- public void register() throws IllegalStateException {
- if (mRegistered) {
- throw new IllegalStateException(
- "Cannot register ContextHubBroadcastReceiver multiple times");
- }
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(mAction);
- mContext.registerReceiver(this, intentFilter, null /* broadcastPermission */, mHandler);
- mRegistered = true;
- }
-
- /**
- * Unregisters this receiver. This method must only be invoked if {@link #register()} is
- * previously invoked.
- *
- * @throws IllegalStateException if the receiver is not yet registered
- */
- public void unregister() throws IllegalStateException {
- if (!mRegistered) {
- throw new IllegalStateException(
- "Cannot unregister ContextHubBroadcastReceiver when not registered");
- }
- mContext.unregisterReceiver(this);
- mRegistered = false;
- }
-
- /**
- * Creates a new PendingIntent associated with this receiver.
- *
- * @param flags the flags {@link PendingIntent.Flags} to use for the PendingIntent
- *
- * @return a PendingIntent to receive notifications for this receiver
- */
- public PendingIntent getPendingIntent(@PendingIntent.Flags int flags) {
- return PendingIntent.getBroadcast(
- mContext, 0 /* requestCode */, new Intent(mAction), flags);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- // TODO: Implement this
- }
-}
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 56da719..9f11246 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -19,6 +19,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.PendingIntent;
+import android.content.Intent;
import android.os.RemoteException;
import com.android.internal.util.Preconditions;
@@ -113,7 +114,8 @@
* describes the Context Hub the intent event was for. The intent will also have an extra
* {@link ContextHubManager.EXTRA_EVENT_TYPE} of type {@link ContextHubManager.Event}, which
* will contain the type of the event. See {@link ContextHubManager.Event} for description of
- * each event type, along with event-specific extra fields.
+ * each event type, along with event-specific extra fields. A client can use
+ * {@link ContextHubIntentEvent.fromIntent(Intent)} to parse the Intent generated by the event.
*
* When the intent is received, this client can be recreated through
* {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo,
@@ -126,10 +128,6 @@
* continued to be maintained at the Context Hub Service until
* {@link #unregisterIntent(PendingIntent)} is called for registered intents.
*
- * See {@link ContextHubBroadcastReceiver} for a helper class to generate the
- * {@link PendingIntent} through a {@link BroadcastReceiver}, and maps an {@link Intent} to a
- * {@link ContextHubClientCallback}.
- *
* @param pendingIntent the PendingIntent to register for this client
* @param nanoAppId the unique ID of the nanoapp to receive events for
* @return true on success, false otherwise
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index b0b77f3..9acefa5 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -808,7 +808,7 @@
*
* @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
* was not associated with a client
- * @throws IllegalStateException if there were too many registered clients at the service
+ * @throws IllegalStateException if the client is already registered to a valid callback
* @throws NullPointerException if pendingIntent, hubInfo, callback, or executor is null
*
* @hide
@@ -818,8 +818,24 @@
@NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
- // TODO: Implement this
- throw new UnsupportedOperationException("Not implemented yet");
+ Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
+ Preconditions.checkNotNull(callback, "Callback cannot be null");
+ Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
+ Preconditions.checkNotNull(executor, "Executor cannot be null");
+
+ ContextHubClient client = new ContextHubClient(hubInfo);
+ IContextHubClientCallback clientInterface = createClientCallback(
+ client, callback, executor);
+
+ IContextHubClient clientProxy;
+ try {
+ clientProxy = mService.bindClient(pendingIntent, clientInterface, hubInfo.getId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+
+ client.setClientProxy(clientProxy);
+ return client;
}
/**
@@ -833,7 +849,7 @@
*
* @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
* was not associated with a client
- * @throws IllegalStateException if there were too many registered clients at the service
+ * @throws IllegalStateException if the client is already registered to a valid callback
* @throws NullPointerException if pendingIntent, hubInfo, or callback is null
*
* @hide
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index 233e857..9b0acdf 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -17,6 +17,7 @@
package android.hardware.location;
// Declare any non-default types here with import statements
+import android.app.PendingIntent;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
import android.hardware.location.NanoApp;
@@ -60,6 +61,11 @@
// Creates a client to send and receive messages
IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);
+ // Binds an existing client to a new callback interface, provided a previously registered
+ // PendingIntent
+ IContextHubClient bindClient(
+ in PendingIntent pendingIntent, in IContextHubClientCallback client, int contextHubId);
+
// Returns a list of ContextHub objects of available hubs
List<ContextHubInfo> getContextHubs();
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 98f3567..4cd0001 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -393,4 +393,19 @@
}
return out;
}
+
+ /**
+ * Checks if this MAC Address matches the provided range.
+ *
+ * @param baseAddress MacAddress representing the base address to compare with.
+ * @param mask MacAddress representing the mask to use during comparison.
+ * @return true if this MAC Address matches the given range.
+ *
+ * @hide
+ */
+ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ Preconditions.checkNotNull(baseAddress);
+ Preconditions.checkNotNull(mask);
+ return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index eead3dff..689f975 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10285,6 +10285,18 @@
public static final String WIFI_LINK_SPEED_METRICS_ENABLED =
"wifi_link_speed_metrics_enabled";
+ /**
+ * Setting to enable the PNO frequency culling optimization.
+ * Disabled by default, and setting it to 1 will enable it.
+ * The value is boolean (0 or 1).
+ * @hide
+ */
+ public static final String WIFI_PNO_FREQUENCY_CULLING_ENABLED =
+ "wifi_pno_frequency_culling_enabled";
+
+ private static final Validator WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
/**
* The maximum number of times we will retry a connection to an access
* point for which we have failed in acquiring an IP address from DHCP.
@@ -12692,6 +12704,8 @@
VALIDATORS.put(DEVICE_PROVISIONING_MOBILE_DATA_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(REQUIRE_PASSWORD_TO_DECRYPT, BOOLEAN_VALIDATOR);
VALIDATORS.put(DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(WIFI_PNO_FREQUENCY_CULLING_ENABLED,
+ WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR);
}
/**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 2d67d79..769dd1b 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -36,6 +36,7 @@
public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX;
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String EMERGENCY_DIAL_SHORTCUTS = "settings_emergency_dial_shortcuts";
+ public static final String SAFETY_HUB = "settings_safety_hub";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -51,6 +52,7 @@
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(EMERGENCY_DIAL_SHORTCUTS, "true");
DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false");
+ DEFAULT_FLAGS.put(SAFETY_HUB, "false");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
}
diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java
index cbe73ef..5513ce2f 100644
--- a/core/java/android/view/intelligence/IntelligenceManager.java
+++ b/core/java/android/view/intelligence/IntelligenceManager.java
@@ -44,7 +44,7 @@
}
/**
- * Returns the component name of the {@link android.service.intelligence.IntelligenceService}
+ * Returns the component name of the {@code android.service.intelligence.IntelligenceService}
* that is enabled for the current user.
*/
@Nullable
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index e7ac566..19d8a83 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -1396,6 +1396,11 @@
return as;
}
+ // See b/118826162 -- to avoid logspaming, we rate limit the WTF.
+ private static final long INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS = 10_000L;
+ private long mNextInverseProcStateWtfUptime;
+ private int mSkippedInverseProcStateWtfCount;
+
public void updateTrackingAssociationsLocked(int curSeq, long now) {
final int NUM = mTrackingAssociations.size();
for (int i = NUM - 1; i >= 0; i--) {
@@ -1417,12 +1422,24 @@
} else {
act.stopActive(now);
if (act.mProcState < procState) {
- Slog.w(TAG, "Tracking association " + act + " whose proc state "
- + act.mProcState + " is better than process " + proc
- + " proc state " + procState);
+ final long nowUptime = SystemClock.uptimeMillis();
+ if (mNextInverseProcStateWtfUptime > nowUptime) {
+ mSkippedInverseProcStateWtfCount++;
+ } else {
+ // TODO We still see it during boot related to GMS-core.
+ // b/118826162
+ Slog.wtf(TAG, "Tracking association " + act + " whose proc state "
+ + act.mProcState + " is better than process " + proc
+ + " proc state " + procState
+ + " (" + mSkippedInverseProcStateWtfCount + " skipped)");
+ mSkippedInverseProcStateWtfCount = 0;
+ mNextInverseProcStateWtfUptime =
+ nowUptime + INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS;
+ }
}
}
} else {
+ // Don't need rate limiting on it.
Slog.wtf(TAG, "Tracking association without process: " + act
+ " in " + act.getAssociationState());
}
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index b799728..25a5a07 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -69,7 +69,7 @@
private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
private static final boolean PROFILE_DRAWING = false;
- private static final float LINE_FADE_ALPHA_MULTIPLIER = 3.5f;
+ private static final float LINE_FADE_ALPHA_MULTIPLIER = 1.5f;
private final CellState[][] mCellStates;
private final int mDotSize;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 830ca83..b2d44e7 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1208,13 +1208,23 @@
// jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
}
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
- jlong src_theme_ptr) {
+static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
+ jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
- if (!dst_theme->SetTo(*src_theme)) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "Themes are from different AssetManagers");
+
+ if (dst_asset_manager_ptr != src_asset_manager_ptr) {
+ ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
+ CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
+ (void) dst_assetmanager;
+
+ ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+ CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
+ (void) src_assetmanager;
+
+ dst_theme->SetTo(*src_theme);
+ } else {
+ dst_theme->SetTo(*src_theme);
}
}
@@ -1255,10 +1265,11 @@
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- (void) theme;
(void) priority;
(void) tag;
(void) prefix;
+
+ theme->Dump();
}
static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
@@ -1377,7 +1388,7 @@
{"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
{"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
{"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
- {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
+ {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
{"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
{"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
(void*)NativeThemeGetAttributeValue},
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 8f28970..0b9e347 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -26,6 +26,7 @@
import "frameworks/base/core/proto/android/os/pagetypeinfo.proto";
import "frameworks/base/core/proto/android/os/procrank.proto";
import "frameworks/base/core/proto/android/os/ps.proto";
+import "frameworks/base/core/proto/android/os/statsdata.proto";
import "frameworks/base/core/proto/android/os/system_properties.proto";
import "frameworks/base/core/proto/android/providers/settings.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
@@ -301,6 +302,12 @@
(section).userdebug_and_eng_only = true
];
+ optional android.os.StatsDataDumpProto stats_data = 3023 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "stats --proto",
+ (section).userdebug_and_eng_only = true
+ ];
+
// Reserved for OEMs.
extensions 50000 to 100000;
}
diff --git a/core/proto/android/os/statsdata.proto b/core/proto/android/os/statsdata.proto
new file mode 100644
index 0000000..25d76b8
--- /dev/null
+++ b/core/proto/android/os/statsdata.proto
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_multiple_files = true;
+
+package android.os;
+
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Dump of statsd report data (dumpsys stats --proto).
+message StatsDataDumpProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // The following is an android.os.statsd.ConfigMetricsReportList, which is defined
+ // in frameworks/base/cmds/statsd/src/stats_log.proto. It should not be imported (even weakly)
+ // in AOSP because it would drag with it atoms.proto, which is enormous and awkward.
+ repeated bytes config_metrics_report_list = 1;
+
+}
\ No newline at end of file
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7b3d940..7163769 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -187,7 +187,7 @@
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
- <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
+ <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
<!-- Nigeria -->
<shortcode country="ng" pattern="\\d{1,5}" free="2441" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c298770..4980210 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -486,6 +486,7 @@
Settings.Global.WIFI_IDLE_MS,
Settings.Global.WIFI_IS_UNUSABLE_EVENT_METRICS_ENABLED,
Settings.Global.WIFI_LINK_SPEED_METRICS_ENABLED,
+ Settings.Global.WIFI_PNO_FREQUENCY_CULLING_ENABLED,
Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
Settings.Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
Settings.Global.WIFI_NETWORK_SHOW_RSSI,
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 04cc5bb..288ba32 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -21,6 +21,7 @@
#include <algorithm>
#include <iterator>
#include <set>
+#include <map>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
@@ -869,6 +870,17 @@
}
}
+uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
+ for (auto& package_group : package_groups_) {
+ for (auto& package2 : package_group.packages_) {
+ if (package2.loaded_package_ == package) {
+ return package_group.dynamic_ref_table.mAssignedPackageId;
+ }
+ }
+ }
+ return 0;
+}
+
std::unique_ptr<Theme> AssetManager2::NewTheme() {
return std::unique_ptr<Theme>(new Theme(this));
}
@@ -1054,44 +1066,231 @@
}
}
-bool Theme::SetTo(const Theme& o) {
+void Theme::SetTo(const Theme& o) {
if (this == &o) {
- return true;
+ return;
}
type_spec_flags_ = o.type_spec_flags_;
- const bool copy_only_system = asset_manager_ != o.asset_manager_;
-
- for (size_t p = 0; p < packages_.size(); p++) {
- const Package* package = o.packages_[p].get();
- if (package == nullptr || (copy_only_system && p != 0x01)) {
- // The other theme doesn't have this package, clear ours.
- packages_[p].reset();
- continue;
- }
-
- if (packages_[p] == nullptr) {
- // The other theme has this package, but we don't. Make one.
- packages_[p].reset(new Package());
- }
-
- for (size_t t = 0; t < package->types.size(); t++) {
- const ThemeType* type = package->types[t].get();
- if (type == nullptr) {
- // The other theme doesn't have this type, clear ours.
- packages_[p]->types[t].reset();
+ if (asset_manager_ == o.asset_manager_) {
+ // The theme comes from the same asset manager so all theme data can be copied exactly
+ for (size_t p = 0; p < packages_.size(); p++) {
+ const Package *package = o.packages_[p].get();
+ if (package == nullptr) {
+ // The other theme doesn't have this package, clear ours.
+ packages_[p].reset();
continue;
}
- // Create a new type and update it to theirs.
- const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
- void* copied_data = malloc(type_alloc_size);
- memcpy(copied_data, type, type_alloc_size);
- packages_[p]->types[t].reset(reinterpret_cast<ThemeType*>(copied_data));
+ if (packages_[p] == nullptr) {
+ // The other theme has this package, but we don't. Make one.
+ packages_[p].reset(new Package());
+ }
+
+ for (size_t t = 0; t < package->types.size(); t++) {
+ const ThemeType *type = package->types[t].get();
+ if (type == nullptr) {
+ // The other theme doesn't have this type, clear ours.
+ packages_[p]->types[t].reset();
+ continue;
+ }
+
+ // Create a new type and update it to theirs.
+ const size_t type_alloc_size = sizeof(ThemeType) + (type->entry_count * sizeof(ThemeEntry));
+ void *copied_data = malloc(type_alloc_size);
+ memcpy(copied_data, type, type_alloc_size);
+ packages_[p]->types[t].reset(reinterpret_cast<ThemeType *>(copied_data));
+ }
+ }
+ } else {
+ std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+ typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
+ std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+
+ // Determine which ApkAssets are loaded in both theme AssetManagers
+ std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
+ for (size_t i = 0; i < src_assets.size(); i++) {
+ const ApkAssets* src_asset = src_assets[i];
+
+ std::vector<const ApkAssets*> dest_assets = asset_manager_->GetApkAssets();
+ for (size_t j = 0; j < dest_assets.size(); j++) {
+ const ApkAssets* dest_asset = dest_assets[j];
+
+ // Map the runtime package of the source apk asset to the destination apk asset
+ if (src_asset->GetPath() == dest_asset->GetPath()) {
+ const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
+ src_asset->GetLoadedArsc()->GetPackages();
+ const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
+ dest_asset->GetLoadedArsc()->GetPackages();
+
+ SourceToDestinationRuntimePackageMap package_map;
+
+ // The source and destination package should have the same number of packages loaded in
+ // the same order.
+ const size_t N = src_packages.size();
+ CHECK(N == dest_packages.size())
+ << " LoadedArsc " << src_asset->GetPath() << " differs number of packages.";
+ for (size_t p = 0; p < N; p++) {
+ auto& src_package = src_packages[p];
+ auto& dest_package = dest_packages[p];
+ CHECK(src_package->GetPackageName() == dest_package->GetPackageName())
+ << " Package " << src_package->GetPackageName() << " differs in load order.";
+
+ int src_package_id = o.asset_manager_->GetAssignedPackageId(src_package.get());
+ int dest_package_id = asset_manager_->GetAssignedPackageId(dest_package.get());
+ package_map[src_package_id] = dest_package_id;
+ }
+
+ src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j));
+ src_asset_cookie_id_map.insert(
+ std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map));
+ break;
+ }
+ }
+ }
+
+ // Reset the data in the destination theme
+ for (size_t p = 0; p < packages_.size(); p++) {
+ if (packages_[p] != nullptr) {
+ packages_[p].reset();
+ }
+ }
+
+ for (size_t p = 0; p < packages_.size(); p++) {
+ const Package *package = o.packages_[p].get();
+ if (package == nullptr) {
+ continue;
+ }
+
+ for (size_t t = 0; t < package->types.size(); t++) {
+ const ThemeType *type = package->types[t].get();
+ if (type == nullptr) {
+ continue;
+ }
+
+ for (size_t e = 0; e < type->entry_count; e++) {
+ const ThemeEntry &entry = type->entries[e];
+ if (entry.value.dataType == Res_value::TYPE_NULL &&
+ entry.value.data != Res_value::DATA_NULL_EMPTY) {
+ continue;
+ }
+
+ // The package id of the attribute needs to be rewritten to the package id of the value in
+ // the destination
+ int attribute_dest_package_id = p;
+ if (attribute_dest_package_id != 0x01) {
+ // Find the cookie of the attribute resource id
+ FindEntryResult attribute_entry_result;
+ ApkAssetsCookie attribute_cookie =
+ o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ , false,
+ &attribute_entry_result);
+
+ // Determine the package id of the attribute in the destination AssetManager
+ auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
+ if (attribute_package_map == src_asset_cookie_id_map.end()) {
+ continue;
+ }
+ auto attribute_dest_package = attribute_package_map->second.find(
+ attribute_dest_package_id);
+ if (attribute_dest_package == attribute_package_map->second.end()) {
+ continue;
+ }
+ attribute_dest_package_id = attribute_dest_package->second;
+ }
+
+ // If the attribute value represents an attribute or reference, the package id of the
+ // value needs to be rewritten to the package id of the value in the destination
+ uint32_t attribue_data = entry.value.data;
+ if (entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE
+ || entry.value.dataType == Res_value::TYPE_ATTRIBUTE
+ || entry.value.dataType == Res_value::TYPE_REFERENCE) {
+
+ // Determine the package id of the reference in the destination AssetManager
+ auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
+ if (value_package_map == src_asset_cookie_id_map.end()) {
+ continue;
+ }
+
+ auto value_dest_package = value_package_map->second.find(
+ get_package_id(entry.value.data));
+ if (value_dest_package == value_package_map->second.end()) {
+ continue;
+ }
+
+ attribue_data = fix_package_id(entry.value.data, value_dest_package->second);
+ }
+
+ // Lazily instantiate the destination package
+ std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
+ if (dest_package == nullptr) {
+ dest_package.reset(new Package());
+ }
+
+ // Lazily instantiate and resize the destination type
+ util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
+ if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
+ const size_t type_alloc_size = sizeof(ThemeType)
+ + (type->entry_count * sizeof(ThemeEntry));
+ void* dest_data = malloc(type_alloc_size);
+ memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
+
+ // Copy the existing destination type values if the type is resized
+ if (dest_type != nullptr) {
+ memcpy(dest_data, type, sizeof(ThemeType)
+ + (dest_type->entry_count * sizeof(ThemeEntry)));
+ }
+
+ dest_type.reset(reinterpret_cast<ThemeType *>(dest_data));
+ dest_type->entry_count = type->entry_count;
+ }
+
+ // Find the cookie of the value in the destination
+ auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+ if (value_dest_cookie == src_to_dest_asset_cookies.end()) {
+ continue;
+ }
+
+ dest_type->entries[e].cookie = value_dest_cookie->second;
+ dest_type->entries[e].value.dataType = entry.value.dataType;
+ dest_type->entries[e].value.data = attribue_data;
+ dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
+ }
+ }
}
}
- return true;
+}
+
+void Theme::Dump() const {
+ base::ScopedLogSeverity _log(base::INFO);
+ LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
+
+ for (int p = 0; p < packages_.size(); p++) {
+ auto& package = packages_[p];
+ if (package == nullptr) {
+ continue;
+ }
+
+ for (int t = 0; t < package->types.size(); t++) {
+ auto& type = package->types[t];
+ if (type == nullptr) {
+ continue;
+ }
+
+ for (int e = 0; e < type->entry_count; e++) {
+ auto& entry = type->entries[e];
+ if (entry.value.dataType == Res_value::TYPE_NULL &&
+ entry.value.data != Res_value::DATA_NULL_EMPTY) {
+ continue;
+ }
+
+ LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
+ make_resid(p, t, e), entry.value.data,
+ entry.value.dataType, entry.cookie);
+ }
+ }
+ }
}
} // namespace android
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 2f0ee01..5312b06 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -74,6 +74,8 @@
// AssetManager2 is the main entry point for accessing assets and resources.
// AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
class AssetManager2 {
+ friend Theme;
+
public:
struct ResourceName {
const char* package = nullptr;
@@ -285,6 +287,9 @@
// been seen while traversing bag parents.
const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);
+ // Retrieve the assigned package id of the package if loaded into this AssetManager
+ uint8_t GetAssignedPackageId(const LoadedPackage* package);
+
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
std::vector<const ApkAssets*> apk_assets_;
@@ -355,11 +360,14 @@
bool ApplyStyle(uint32_t resid, bool force = false);
// Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
- // Returns false if the AssetManagers of the Themes were not compatible.
- bool SetTo(const Theme& o);
+ // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded
+ // into both AssetManagers will be copied to this theme.
+ void SetTo(const Theme& o);
void Clear();
+ void Dump() const;
+
inline const AssetManager2* GetAssetManager() const {
return asset_manager_;
}
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 55d53ed..2c39cee 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -21,12 +21,14 @@
#include "TestHelpers.h"
#include "androidfw/ResourceUtils.h"
#include "data/lib_one/R.h"
+#include "data/lib_two/R.h"
#include "data/libclient/R.h"
#include "data/styles/R.h"
#include "data/system/R.h"
namespace app = com::android::app;
namespace lib_one = com::android::lib_one;
+namespace lib_two = com::android::lib_two;
namespace libclient = com::android::libclient;
namespace android {
@@ -263,7 +265,7 @@
ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
// Copy the theme to theme_one.
- ASSERT_TRUE(theme_one->SetTo(*theme_two));
+ theme_one->SetTo(*theme_two);
// Clear theme_two to make sure we test that there WAS a copy.
theme_two->Clear();
@@ -279,12 +281,14 @@
EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
}
-TEST_F(ThemeTest, OnlyCopySystemThemeWhenAssetManagersDiffer) {
+TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
AssetManager2 assetmanager_one;
- assetmanager_one.SetApkAssets({system_assets_.get(), style_assets_.get()});
+ assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
+ libclient_assets_.get()});
AssetManager2 assetmanager_two;
- assetmanager_two.SetApkAssets({system_assets_.get(), style_assets_.get()});
+ assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
+ style_assets_.get()});
auto theme_one = assetmanager_one.NewTheme();
ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
@@ -292,17 +296,34 @@
auto theme_two = assetmanager_two.NewTheme();
ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One));
ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
+ false /*force*/));
+ ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
+ false /*force*/));
- EXPECT_TRUE(theme_one->SetTo(*theme_two));
+ theme_one->SetTo(*theme_two);
Res_value value;
uint32_t flags;
- // No app resources.
- EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ // System resources (present in destination asset manager)
+ EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
- // Only system.
- EXPECT_NE(kInvalidCookie, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
+ // The cookie of the style asset is 3 in the source and 2 in the destination.
+ // Check that the cookie has been rewritten to the destination values
+ EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+
+ // The cookie of the lib_one asset is 2 in the source and 1 in the destination.
+ // The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
+ // Check that the cookie and packages have been rewritten to the destination values
+ EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
+ &flags));
+ EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
+ &flags));
+
+ // attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
+ // correct after the value of attr2 had its package id rewritten to the destination package id
+ EXPECT_EQ(700, value.data);
}
} // namespace android
diff --git a/libs/androidfw/tests/data/lib_two/R.h b/libs/androidfw/tests/data/lib_two/R.h
index c04a9d3..92b9cc1 100644
--- a/libs/androidfw/tests/data/lib_two/R.h
+++ b/libs/androidfw/tests/data/lib_two/R.h
@@ -24,12 +24,24 @@
namespace lib_two {
struct R {
+ struct attr {
+ enum : uint32_t {
+ attr3 = 0x02010000, // default
+ };
+ };
+
struct string {
enum : uint32_t {
LibraryString = 0x02020000, // default
foo = 0x02020001, // default
};
};
+
+ struct style {
+ enum : uint32_t {
+ Theme = 0x02030000, // default
+ };
+ };
};
} // namespace lib_two
diff --git a/libs/androidfw/tests/data/lib_two/lib_two.apk b/libs/androidfw/tests/data/lib_two/lib_two.apk
index ad44f9c..486c230 100644
--- a/libs/androidfw/tests/data/lib_two/lib_two.apk
+++ b/libs/androidfw/tests/data/lib_two/lib_two.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/lib_two/res/values/values.xml b/libs/androidfw/tests/data/lib_two/res/values/values.xml
index f4eea26..340d14c 100644
--- a/libs/androidfw/tests/data/lib_two/res/values/values.xml
+++ b/libs/androidfw/tests/data/lib_two/res/values/values.xml
@@ -15,9 +15,17 @@
-->
<resources>
+ <public type="attr" name="attr3" id="0x00010000" />
+ <attr name="attr3" format="integer" />
+
<public type="string" name="LibraryString" id="0x00020000" />
<string name="LibraryString">Hi from library two</string>
<public type="string" name="foo" id="0x00020001" />
<string name="foo">Foo from lib_two</string>
+
+ <public type="style" name="Theme" id="0x02030000" />
+ <style name="Theme">
+ <item name="com.android.lib_two:attr3">800</item>
+ </style>
</resources>
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 753557c..75a6e72 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -286,7 +286,6 @@
}
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
- outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
if (isHardware()) {
outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
info().colorType(), info().alphaType(), nullptr));
@@ -321,7 +320,6 @@
SkBitmap skiaBitmap;
skiaBitmap.setInfo(info(), rowBytes());
skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
- skiaBitmap.setHasHardwareMipMap(mHasHardwareMipMap);
// Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
// internally and ~Bitmap won't be invoked.
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index 33c5551..a8ce196 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -164,7 +164,7 @@
### [com.android.systemui.biometrics.BiometricDialogImpl](/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java)
-Fingerprint UI.
+Biometric UI.
---
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 0462347..9baeaaa 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -64,6 +64,7 @@
<item name="android:paddingBottom">@dimen/bottom_text_spacing_digital</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyLight</item>
<item name="android:fontFeatureSettings">@*android:string/config_headlineFontFeatureSettings</item>
+ <item name="android:ellipsize">none</item>
</style>
<style name="BouncerSecurityContainer">
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 003f158d..c47d408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1107,7 +1107,9 @@
mIsClipped = clipped;
}
- if (mAmbientState.isDarkAtAll()) {
+ if (mPulsing) {
+ setClipBounds(null);
+ } else if (mAmbientState.isDarkAtAll()) {
setClipBounds(mBackgroundAnimationRect);
} else if (clipped) {
setClipBounds(mRequestedClipBounds);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 793a177..26e22bf 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1258,8 +1258,6 @@
private final class VibratorShellCommand extends ShellCommand {
- private static final long MAX_VIBRATION_MS = 200;
-
private final IBinder mToken;
private VibratorShellCommand(IBinder token) {
@@ -1303,9 +1301,6 @@
}
final long duration = Long.parseLong(getNextArgRequired());
- if (duration > MAX_VIBRATION_MS) {
- throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
- }
String description = getNextArg();
if (description == null) {
description = "Shell command";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d631fa8..52b0275 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17355,8 +17355,6 @@
}
}
- mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
-
incrementProcStateSeqAndNotifyAppsLocked();
mNumServiceProcs = mNewNumServiceProcs;
@@ -17618,6 +17616,9 @@
mHandler.post(new ProcStatsRunnable(ActivityManagerService.this, mProcessStats));
}
+ // Run this after making sure all procstates are updated.
+ mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+
if (DEBUG_OOM_ADJ) {
final long duration = SystemClock.uptimeMillis() - now;
if (false) {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 5d4263b..bc3cc3b 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -70,7 +70,7 @@
/**
* A service to manage multiple clients that want to access the face HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
- * face -related events.
+ * face-related events.
*
* @hide
*/
diff --git a/services/core/java/com/android/server/biometrics/iris/IrisService.java b/services/core/java/com/android/server/biometrics/iris/IrisService.java
new file mode 100644
index 0000000..37cdc2a
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/iris/IrisService.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.biometrics.iris;
+
+import android.content.Context;
+
+import com.android.server.biometrics.BiometricServiceBase;
+import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.Metrics;
+
+/**
+ * A service to manage multiple clients that want to access the Iris HAL API.
+ * The service is responsible for maintaining a list of clients and dispatching all
+ * iris-related events.
+ *
+ * TODO: The vendor is expected to fill in the service. See
+ * {@link com.android.server.biometrics.fingerprint.FingerprintService}
+ *
+ * @hide
+ */
+public class IrisService extends BiometricServiceBase {
+
+ private static final String TAG = "IrisService";
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public IrisService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ }
+
+ @Override
+ protected String getTag() {
+ return TAG;
+ }
+
+ @Override
+ protected BiometricUtils getBiometricUtils() {
+ return null;
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutTimed() {
+ return 0;
+ }
+
+ @Override
+ protected int getFailedAttemptsLockoutPermanent() {
+ return 0;
+ }
+
+ @Override
+ protected Metrics getMetrics() {
+ return null;
+ }
+
+ @Override
+ protected boolean hasReachedEnrollmentLimit(int userId) {
+ return false;
+ }
+
+ @Override
+ protected void updateActiveGroup(int userId, String clientPackage) {
+
+ }
+
+ @Override
+ protected String getLockoutResetIntent() {
+ return null;
+ }
+
+ @Override
+ protected String getLockoutBroadcastPermission() {
+ return null;
+ }
+
+ @Override
+ protected long getHalDeviceId() {
+ return 0;
+ }
+
+ @Override
+ protected void handleUserSwitching(int userId) {
+
+ }
+
+ @Override
+ protected boolean hasEnrolledBiometrics(int userId) {
+ return false;
+ }
+
+ @Override
+ protected String getManageBiometricPermission() {
+ return null;
+ }
+
+ @Override
+ protected void checkUseBiometricPermission() {
+
+ }
+
+ @Override
+ protected boolean checkAppOps(int uid, String opPackageName) {
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 60f70c7..6423470 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -159,25 +159,12 @@
/* package */ ContextHubClientBroker(
Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
- ContextHubInfo contextHubInfo, short hostEndPointId,
- IContextHubClientCallback callback) {
+ ContextHubInfo contextHubInfo, short hostEndPointId) {
mContext = context;
mContextHubProxy = contextHubProxy;
mClientManager = clientManager;
mAttachedContextHubInfo = contextHubInfo;
mHostEndPointId = hostEndPointId;
- mCallbackInterface = callback;
- }
-
- /**
- * Attaches a death recipient for this client
- *
- * @throws RemoteException if the client has already died
- */
- /* package */ synchronized void attachDeathRecipient() throws RemoteException {
- if (mCallbackInterface != null) {
- mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
- }
}
/**
@@ -245,9 +232,15 @@
public boolean unregisterIntent(PendingIntent pendingIntent) {
ContextHubServiceUtil.checkPermissions(mContext);
+ boolean success = false;
synchronized (this) {
- return mPendingIntentRequest.unregister(pendingIntent);
+ success = mPendingIntentRequest.unregister(pendingIntent);
+ if (mCallbackInterface == null) {
+ close();
+ }
}
+
+ return success;
}
/**
@@ -276,6 +269,37 @@
}
/**
+ * Sets the callback interface for this client, only if the callback is currently unregistered.
+ *
+ * Also attaches a death recipient to a ContextHubClientBroker object. If unsuccessful, the
+ * connection is closed.
+ *
+ * @param callback the callback interface
+ * @return true if the callback was successfully set, false otherwise
+ *
+ * @throws IllegalStateException if the client has already been registered to a callback
+ */
+ /* package */
+ synchronized boolean setCallback(IContextHubClientCallback callback) {
+ boolean success = false;
+ if (mCallbackInterface != null) {
+ throw new IllegalStateException("Client is already registered with a callback");
+ } else {
+ mCallbackInterface = callback;
+ try {
+ mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
+ success = true;
+ } catch (RemoteException e) {
+ // The client process has died, so we close the connection.
+ Log.e(TAG, "Failed to attach death recipient to client");
+ close();
+ }
+ }
+
+ return success;
+ }
+
+ /**
* @return the ID of the context hub this client is attached to
*/
/* package */ int getAttachedContextHubId() {
@@ -347,6 +371,18 @@
}
/**
+ * @param intent the PendingIntent to compare to
+ * @return true if the given PendingIntent is currently registered, false otherwise
+ */
+ /* package */ boolean hasPendingIntent(PendingIntent intent) {
+ PendingIntent pendingIntent = null;
+ synchronized (this) {
+ pendingIntent = mPendingIntentRequest.getPendingIntent();
+ }
+ return (pendingIntent != null) && pendingIntent.equals(intent);
+ }
+
+ /**
* Helper function to invoke a specified client callback, if the connection is open.
*
* @param consumer the consumer specifying the callback to invoke
@@ -407,6 +443,9 @@
Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
+ " (host endpoint ID " + mHostEndPointId + ")");
mPendingIntentRequest.clear();
+ if (mCallbackInterface == null) {
+ close();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java
index eda8c6f..72879dd 100644
--- a/services/core/java/com/android/server/location/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/ContextHubClientManager.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.IContexthub;
@@ -88,15 +89,9 @@
*/
/* package */ IContextHubClient registerClient(
IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
- ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubInfo);
-
- try {
- broker.attachDeathRecipient();
- } catch (RemoteException e) {
- // The client process has died, so we close the connection and return null.
- Log.e(TAG, "Failed to attach death recipient to client");
- broker.close();
- return null;
+ ContextHubClientBroker broker = createNewClientBroker(contextHubInfo);
+ if (!broker.setCallback(clientCallback)) {
+ return null; // Client process has died, so we return null
}
Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId());
@@ -104,6 +99,36 @@
}
/**
+ * Binds a existing and registered client with a new callback interface, provided a previously
+ * registered PendingIntent.
+ *
+ * @param pendingIntent a previously registered PendingIntent for a registered client
+ * @param clientCallback the callback interface of the client to bind to
+ * @param contextHubId the ID of the hub this client is attached to
+ *
+ * @return the client interface
+ *
+ * @throws IllegalArgumentException if no matching client is found
+ * @throws IllegalStateException if the client has already been registered to a callback
+ */
+ /* package */ IContextHubClient bindClient(
+ PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
+ int contextHubId) {
+ ContextHubClientBroker broker = getClientBroker(pendingIntent, contextHubId);
+ if (broker == null) {
+ throw new IllegalArgumentException("Could not find client of Context Hub (ID = "
+ + contextHubId + ") with PendingIntent");
+ }
+
+ if (!broker.setCallback(clientCallback)) {
+ return null; // Client process has died, so we return null
+ }
+
+ Log.d(TAG, "Re-registered client with host endpoint ID " + broker.getHostEndPointId());
+ return IContextHubClient.Stub.asInterface(broker);
+ }
+
+ /**
* Handles a message sent from a nanoapp.
*
* @param contextHubId the ID of the hub where the nanoapp sent the message from
@@ -182,7 +207,6 @@
* Creates a new ContextHubClientBroker object for a client and registers it with the client
* manager.
*
- * @param clientCallback the callback interface of the client to register
* @param contextHubInfo the object describing the hub this client is attached to
*
* @return the ContextHubClientBroker object
@@ -190,7 +214,7 @@
* @throws IllegalStateException if max number of clients have already registered
*/
private synchronized ContextHubClientBroker createNewClientBroker(
- IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
+ ContextHubInfo contextHubInfo) {
if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) {
throw new IllegalStateException("Could not register client - max limit exceeded");
}
@@ -200,8 +224,7 @@
for (int i = 0; i <= MAX_CLIENT_ID; i++) {
if (!mHostEndPointIdToClientMap.containsKey((short) id)) {
broker = new ContextHubClientBroker(
- mContext, mContextHubProxy, this, contextHubInfo, (short) id,
- clientCallback);
+ mContext, mContextHubProxy, this, contextHubInfo, (short) id);
mHostEndPointIdToClientMap.put((short) id, broker);
mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
break;
@@ -236,4 +259,22 @@
}
}
}
+
+ /**
+ * Retrieves a ContextHubClientBroker object with a matching PendingIntent and Context Hub ID.
+ *
+ * @param pendingIntent the PendingIntent to match
+ * @param contextHubId the ID of the Context Hub the client is attached to
+ * @return the matching ContextHubClientBroker, null if not found
+ */
+ private ContextHubClientBroker getClientBroker(PendingIntent pendingIntent, int contextHubId) {
+ for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
+ if (broker.hasPendingIntent(pendingIntent)
+ && broker.getAttachedContextHubId() == contextHubId) {
+ return broker;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index e3c2863..215e67c 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
@@ -631,6 +632,37 @@
}
/**
+ * Recreates and binds a IContextHubClientCallback interface to an existing and registered
+ * client at the service for the specified Context Hub, provided a previously registered
+ * PendingIntent.
+ *
+ * @param pendingIntent the PendingIntent previously registered for the client
+ * @param clientCallback the client interface to register with the service
+ * @param contextHubId the ID of the hub this client is attached to
+ * @return the generated client interface, null if registration was unsuccessful
+ *
+ * @throws IllegalArgumentException if contextHubId is not a valid ID
+ * @throws NullPointerException if clientCallback or pendingIntent is null
+ */
+ @Override
+ public IContextHubClient bindClient(
+ PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
+ int contextHubId) throws RemoteException {
+ checkPermissions();
+ if (!isValidContextHubId(contextHubId)) {
+ throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
+ }
+ if (pendingIntent == null) {
+ throw new NullPointerException("Cannot create client with null pending intent");
+ }
+ if (clientCallback == null) {
+ throw new NullPointerException("Cannot create client with null callback");
+ }
+
+ return mClientManager.bindClient(pendingIntent, clientCallback, contextHubId);
+ }
+
+ /**
* Loads a nanoapp binary at the specified Context hub.
*
* @param contextHubId the ID of the hub to load the binary
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 0b32d1a..6ccd040 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -58,7 +58,6 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
@@ -646,8 +645,8 @@
}
try {
- Os.mkdir(stageDir.getAbsolutePath(), 0755);
- Os.chmod(stageDir.getAbsolutePath(), 0755);
+ Os.mkdir(stageDir.getAbsolutePath(), 0775);
+ Os.chmod(stageDir.getAbsolutePath(), 0775);
} catch (ErrnoException e) {
// This purposefully throws if directory already exists
throw new IOException("Failed to prepare session dir: " + stageDir, e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 51225a7..6e45013 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -43,6 +43,7 @@
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.apex.IApexService;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
@@ -75,6 +76,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.RevocableFileDescriptor;
+import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.storage.StorageManager;
@@ -838,12 +840,15 @@
resolveStageDirLocked();
mSealed = true;
-
- // Verify that stage looks sane with respect to existing application.
- // This currently only ensures packageName, versionCode, and certificate
- // consistency.
try {
- validateInstallLocked(pkgInfo);
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ validateApexInstallLocked(pkgInfo);
+ } else {
+ // Verify that stage looks sane with respect to existing application.
+ // This currently only ensures packageName, versionCode, and certificate
+ // consistency.
+ validateApkInstallLocked(pkgInfo);
+ }
} catch (PackageManagerException e) {
throw e;
} catch (Throwable e) {
@@ -926,6 +931,31 @@
Preconditions.checkNotNull(mSigningDetails);
Preconditions.checkNotNull(mResolvedBaseFile);
+ if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+ commitApexLocked();
+ } else {
+ commitApkLocked();
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitApexLocked() throws PackageManagerException {
+ try {
+ IApexService apex = IApexService.Stub.asInterface(
+ ServiceManager.getService("apexservice"));
+ apex.installPackage(mResolvedBaseFile.toString());
+ } catch (Throwable e) {
+ // Convert all exceptions into package manager exceptions as only those are handled
+ // in the code above
+ throw new PackageManagerException(e);
+ } finally {
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void commitApkLocked() throws PackageManagerException {
if (needToAskForPermissionsLocked()) {
// User needs to confirm installation; give installer an intent they can use to involve
// user.
@@ -1047,6 +1077,57 @@
(params.installFlags & PackageManager.DONT_KILL_APP) != 0;
}
+ @GuardedBy("mLock")
+ private void validateApexInstallLocked(@Nullable PackageInfo pkgInfo)
+ throws PackageManagerException {
+ mResolvedStagedFiles.clear();
+ mResolvedInheritedFiles.clear();
+
+ try {
+ resolveStageDirLocked();
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
+ "Failed to resolve stage location", e);
+ }
+
+ final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+ if (ArrayUtils.isEmpty(addedFiles)) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
+ }
+
+ if (addedFiles.length > 1) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Only one APEX file at a time might be installed");
+ }
+ File addedFile = addedFiles[0];
+ final ApkLite apk;
+ try {
+ apk = PackageParser.parseApkLite(
+ addedFile, PackageParser.PARSE_COLLECT_CERTIFICATES);
+ } catch (PackageParserException e) {
+ throw PackageManagerException.from(e);
+ }
+
+ mPackageName = apk.packageName;
+ mVersionCode = apk.getLongVersionCode();
+ mSigningDetails = apk.signingDetails;
+ mResolvedBaseFile = addedFile;
+
+ assertApkConsistentLocked(String.valueOf(addedFile), apk);
+
+ if (mSigningDetails == PackageParser.SigningDetails.UNKNOWN) {
+ try {
+ // STOPSHIP: For APEX we should also implement proper APK Signature verification.
+ mSigningDetails = ApkSignatureVerifier.plsCertsNoVerifyOnlyCerts(
+ pkgInfo.applicationInfo.sourceDir,
+ PackageParser.SigningDetails.SignatureSchemeVersion.JAR);
+ } catch (PackageParserException e) {
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Couldn't obtain signatures from base APK");
+ }
+ }
+ }
+
/**
* Validate install by confirming that all application packages are have
* consistent package name, version code, and signing certificates.
@@ -1060,7 +1141,7 @@
* {@link PackageManagerService}.
*/
@GuardedBy("mLock")
- private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
+ private void validateApkInstallLocked(@Nullable PackageInfo pkgInfo)
throws PackageManagerException {
ApkLite baseApk = null;
mPackageName = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9210d46..0e37bca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -85,6 +85,11 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageParser.isApkFile;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_HIDL_MANAGER;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
+import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
@@ -366,6 +371,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.BiConsumer;
import java.util.function.Predicate;
/**
@@ -2090,6 +2096,28 @@
}
}
+ @GuardedBy("mPackages")
+ private void setupBuiltinSharedLibraryDependenciesLocked() {
+ // Builtin libraries don't have versions.
+ long version = SharedLibraryInfo.VERSION_UNDEFINED;
+
+ SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(ANDROID_HIDL_MANAGER, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_HIDL_BASE, version));
+ }
+
+ libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_RUNNER, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version));
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+ }
+
+ libraryInfo = getSharedLibraryInfoLPr(ANDROID_TEST_MOCK, version);
+ if (libraryInfo != null) {
+ libraryInfo.addDependency(getSharedLibraryInfoLPr(ANDROID_TEST_BASE, version));
+ }
+ }
+
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
@@ -2205,6 +2233,9 @@
addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}
+ // Builtin libraries cannot encode their dependency where they are
+ // defined, so fix that now.
+ setupBuiltinSharedLibraryDependenciesLocked();
SELinuxMMAC.readInstallPolicy();
@@ -4867,7 +4898,10 @@
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), libInfo.getDeclaringPackage(),
- getPackagesUsingSharedLibraryLPr(libInfo, flags, userId));
+ getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+ (libInfo.getDependencies() == null
+ ? null
+ : new ArrayList(libInfo.getDependencies())));
if (result == null) {
result = new ArrayList<>();
@@ -9598,16 +9632,34 @@
}
@GuardedBy("mPackages")
- private void addSharedLibraryLPr(Set<String> usesLibraryFiles,
- SharedLibraryInfo file,
- PackageParser.Package changingLib) {
+ private void applyDefiningSharedLibraryUpdateLocked(
+ PackageParser.Package pkg, SharedLibraryInfo libInfo,
+ BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
+ if (pkg.isLibrary()) {
+ if (pkg.staticSharedLibName != null) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ pkg.staticSharedLibName, pkg.staticSharedLibVersion);
+ action.accept(definedLibrary, libInfo);
+ } else {
+ for (String libraryName : pkg.libraryNames) {
+ SharedLibraryInfo definedLibrary = getSharedLibraryInfoLPr(
+ libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
+ action.accept(definedLibrary, libInfo);
+ }
+ }
+ }
+ }
- if (file.getPath() != null) {
- usesLibraryFiles.add(file.getPath());
+ @GuardedBy("mPackages")
+ private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
+ SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
+
+ if (libInfo.getPath() != null) {
+ usesLibraryFiles.add(libInfo.getPath());
return;
}
- PackageParser.Package p = mPackages.get(file.getPackageName());
- if (changingLib != null && changingLib.packageName.equals(file.getPackageName())) {
+ PackageParser.Package p = mPackages.get(libInfo.getPackageName());
+ if (changingLib != null && changingLib.packageName.equals(libInfo.getPackageName())) {
// If we are doing this while in the middle of updating a library apk,
// then we need to make sure to use that new apk for determining the
// dependencies here. (We haven't yet finished committing the new apk
@@ -9618,6 +9670,10 @@
}
if (p != null) {
usesLibraryFiles.addAll(p.getAllCodePaths());
+ // If the package provides libraries, add the dependency to them.
+ applyDefiningSharedLibraryUpdateLocked(pkg, libInfo, (definingLibrary, dependency) -> {
+ definingLibrary.addDependency(dependency);
+ });
if (p.usesLibraryFiles != null) {
Collections.addAll(usesLibraryFiles, p.usesLibraryFiles);
}
@@ -9630,6 +9686,12 @@
if (pkg == null) {
return;
}
+
+ // If the package provides libraries, clear their old dependencies.
+ // This method will set them up again.
+ applyDefiningSharedLibraryUpdateLocked(pkg, null, (definingLibrary, dependency) -> {
+ definingLibrary.clearDependencies();
+ });
// The collection used here must maintain the order of addition (so
// that libraries are searched in the correct order) and must have no
// duplicates.
@@ -9656,7 +9718,7 @@
// usesLibraryFiles while eliminating duplicates.
Set<String> usesLibraryFiles = new LinkedHashSet<>();
for (SharedLibraryInfo libInfo : usesLibraryInfos) {
- addSharedLibraryLPr(usesLibraryFiles, libInfo, changingLib);
+ addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib);
}
pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[usesLibraryFiles.size()]);
} else {
@@ -11201,7 +11263,7 @@
}
SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name,
version, type, new VersionedPackage(declaringPackageName, declaringVersionCode),
- null);
+ null, null);
versionedLib.put(version, libraryInfo);
return true;
}
@@ -15153,14 +15215,8 @@
pkgList.add(oldPackage.applicationInfo.packageName);
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
-
- clearAppDataLIF(pkg, UserHandle.USER_ALL, StorageManager.FLAG_STORAGE_DE
- | StorageManager.FLAG_STORAGE_CE
- | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
-
-
// Update the in-memory copy of the previous code paths.
PackageSetting ps1 = mSettings.mPackages.get(
reconciledPkg.prepareResult.existingPackage.packageName);
@@ -15364,7 +15420,8 @@
/**
* On successful install, executes remaining steps after commit completes and the package lock
- * is released.
+ * is released. These are typically more expensive or require calls to installd, which often
+ * locks on {@link #mPackages}.
*/
private void executePostCommitSteps(CommitRequest commitRequest) {
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
@@ -16093,7 +16150,6 @@
try {
final PackageParser.Package existingPackage;
String renamedPackage = null;
- boolean clearCodeCache = false;
boolean sysPkg = false;
String targetVolumeUuid = volumeUuid;
int targetScanFlags = scanFlags;
@@ -16314,7 +16370,6 @@
Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
+ ", old=" + oldPackage);
}
- clearCodeCache = true;
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP);
@@ -16370,7 +16425,7 @@
shouldCloseFreezerBeforeReturn = false;
return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
- clearCodeCache, sysPkg, renamedPackage, freezer);
+ replace /* clearCodeCache */, sysPkg, renamedPackage, freezer);
} finally {
if (shouldCloseFreezerBeforeReturn) {
freezer.close();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e25cca4..38bd172 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -920,7 +920,10 @@
pw.println("Error: must either specify a package size or an APK file");
return 1;
}
- if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+ final boolean isApex =
+ (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+ String splitName = "base." + (isApex ? "apex" : "apk");
+ if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
return 1;
}
@@ -2262,6 +2265,9 @@
case "--force-sdk":
sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
break;
+ case "--apex":
+ sessionParams.installFlags |= PackageManager.INSTALL_APEX;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 392d4d8..753c283 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -30,6 +30,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;
@@ -74,7 +75,7 @@
private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
"pm.dexopt.priv-apps-oob-list";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
@@ -192,6 +193,16 @@
String[] classLoaderContexts = DexoptUtils.processContextForDexLoad(
classLoaderNames, classPaths);
+ // A null classLoaderContexts means that there are unsupported class loaders in the
+ // chain.
+ if (classLoaderContexts == null) {
+ if (DEBUG) {
+ Slog.i(TAG, loadingAppInfo.packageName +
+ " uses unsupported class loader in " + classLoaderNames);
+ }
+ return;
+ }
+
int dexPathIndex = 0;
for (String dexPath : dexPathsToRegister) {
// Find the owning package name.
@@ -219,14 +230,10 @@
}
// Record dex file usage. If the current usage is a new pattern (e.g. new secondary,
- // or UsedBytOtherApps), record will return true and we trigger an async write
+ // or UsedByOtherApps), record will return true and we trigger an async write
// to disk to make sure we don't loose the data in case of a reboot.
- // A null classLoaderContexts means that there are unsupported class loaders in the
- // chain.
- String classLoaderContext = classLoaderContexts == null
- ? PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT
- : classLoaderContexts[dexPathIndex];
+ String classLoaderContext = classLoaderContexts[dexPathIndex];
if (mPackageDexUsage.record(searchResult.mOwningPackageName,
dexPath, loaderUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
loadingAppInfo.packageName, classLoaderContext)) {
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 602ce3b..86f7380 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -21,6 +21,7 @@
import android.os.Build;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastPrintWriter;
import com.android.server.pm.AbstractStatsBase;
import com.android.server.pm.PackageManagerServiceUtils;
@@ -78,14 +79,16 @@
// skip optimizations on that dex files.
/*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT =
"=VariableClassLoaderContext=";
- // The marker used for unsupported class loader contexts.
- /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
- "=UnsupportedClassLoaderContext=";
// The markers used for unknown class loader contexts. This can happen if the dex file was
// recorded in a previous version and we didn't have a chance to update its usage.
/*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT =
"=UnknownClassLoaderContext=";
+ // The marker used for unsupported class loader contexts (no longer written, may occur in old
+ // files so discarded on read).
+ private static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
+ "=UnsupportedClassLoaderContext=";
+
// Map which structures the information we have on a package.
// Maps package name to package data (which stores info about UsedByOtherApps and
// secondary dex files.).
@@ -365,6 +368,12 @@
Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
String classLoaderContext = maybeReadClassLoaderContext(in, version);
+ if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(classLoaderContext)) {
+ // We used to record use of unsupported class loaders, but we no longer do.
+ // Discard such entries; they will be deleted when we next write the file.
+ continue;
+ }
+
int ownerUserId = Integer.parseInt(elems[0]);
boolean isUsedByOtherApps = readBoolean(elems[1]);
DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId,
@@ -709,13 +718,13 @@
// the compiled code will be private.
private boolean mUsedByOtherAppsBeforeUpgrade;
- public PackageUseInfo() {
+ /*package*/ PackageUseInfo() {
mCodePathsUsedByOtherApps = new HashMap<>();
mDexUseInfoMap = new HashMap<>();
}
// Creates a deep copy of the `other`.
- public PackageUseInfo(PackageUseInfo other) {
+ private PackageUseInfo(PackageUseInfo other) {
mCodePathsUsedByOtherApps = new HashMap<>();
for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) {
mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue()));
@@ -796,8 +805,9 @@
// Packages who load this dex file.
private final Set<String> mLoadingPackages;
- public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext,
- String loaderIsa) {
+ @VisibleForTesting
+ /* package */ DexUseInfo(boolean isUsedByOtherApps, int ownerUserId,
+ String classLoaderContext, String loaderIsa) {
mIsUsedByOtherApps = isUsedByOtherApps;
mOwnerUserId = ownerUserId;
mClassLoaderContext = classLoaderContext;
@@ -809,7 +819,7 @@
}
// Creates a deep copy of the `other`.
- public DexUseInfo(DexUseInfo other) {
+ private DexUseInfo(DexUseInfo other) {
mIsUsedByOtherApps = other.mIsUsedByOtherApps;
mOwnerUserId = other.mOwnerUserId;
mClassLoaderContext = other.mClassLoaderContext;
@@ -827,11 +837,7 @@
if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
// Can happen if we read a previous version.
mClassLoaderContext = dexUseInfo.mClassLoaderContext;
- } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) {
- // We detected an unsupported context.
- mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT;
- } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) &&
- !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
+ } else if (!Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
// We detected a context change.
mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
}
@@ -846,7 +852,7 @@
return mIsUsedByOtherApps;
}
- public int getOwnerUserId() {
+ /* package */ int getOwnerUserId() {
return mOwnerUserId;
}
@@ -860,17 +866,15 @@
public String getClassLoaderContext() { return mClassLoaderContext; }
- public boolean isUnsupportedClassLoaderContext() {
- return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
- }
-
- public boolean isUnknownClassLoaderContext() {
+ @VisibleForTesting
+ /* package */ boolean isUnknownClassLoaderContext() {
// The class loader context may be unknown if we loaded the data from a previous version
// which didn't save the context.
return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
}
- public boolean isVariableClassLoaderContext() {
+ @VisibleForTesting
+ /* package */ boolean isVariableClassLoaderContext() {
return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 49f410d..f432c8d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -68,6 +68,7 @@
import com.android.server.appbinding.AppBindingService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.BiometricService;
+import com.android.server.biometrics.iris.IrisService;
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
@@ -1589,6 +1590,8 @@
final boolean hasFeatureFace
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE);
+ final boolean hasFeatureIris
+ = mPackageManager.hasSystemFeature(PackageManager.FEATURE_IRIS);
final boolean hasFeatureFingerprint
= mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
@@ -1598,13 +1601,19 @@
traceEnd();
}
+ if (hasFeatureIris) {
+ traceBeginAndSlog("StartIrisSensor");
+ mSystemServiceManager.startService(IrisService.class);
+ traceEnd();
+ }
+
if (hasFeatureFingerprint) {
traceBeginAndSlog("StartFingerprintSensor");
mSystemServiceManager.startService(FingerprintService.class);
traceEnd();
}
- if (hasFeatureFace || hasFeatureFingerprint) {
+ if (hasFeatureFace || hasFeatureIris || hasFeatureFingerprint) {
// Start this service after all biometric services.
traceBeginAndSlog("StartBiometricPromptService");
mSystemServiceManager.startService(BiometricService.class);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b0b7def..ebac8fb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -38,12 +38,12 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import libcore.io.IoUtils;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import libcore.io.IoUtils;
-
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
@@ -490,7 +490,7 @@
pkg.usesLibraryFiles = new String[] { "foo13"};
pkg.usesLibraryInfos = new ArrayList<>();
- pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null));
+ pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null));
pkg.mOriginalPackages = new ArrayList<>();
pkg.mOriginalPackages.add("foo14");
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 416a616..bd42b73 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -401,15 +401,7 @@
List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
- PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
- assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
- // We expect that all the contexts are unsupported.
- String[] expectedContexts =
- Collections.nCopies(secondaries.size(),
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
+ assertNoUseInfo(mBarUser0UnsupportedClassLoader);
}
@Test
@@ -438,27 +430,18 @@
}
@Test
- public void testNotifyUnsupportedClassLoaderDoesNotChange() {
- List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths();
+ public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() {
+ List<String> secondaries = mBarUser0.getSecondaryDexPaths();
+
+ notifyDexLoad(mBarUser0, secondaries, mUser0);
+ PackageUseInfo pui = getPackageUseInfo(mBarUser0);
+ assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
+
+ // Record bar secondaries again with an unsupported class loader. This should not change the
+ // context.
notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0);
-
- PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false);
- assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
- // We expect that all the contexts are unsupported.
- String[] expectedContexts =
- Collections.nCopies(secondaries.size(),
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
- // Record bar secondaries again with a different class loader. This will change the context.
- // However, because the context was already marked as unsupported we should not chage it.
- notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0);
- pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader);
- assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries,
- /*isUsedByOtherApps*/false, mUser0, expectedContexts);
-
+ pui = getPackageUseInfo(mBarUser0);
+ assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
index 3e93dcf..7755e94 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/PackageDexUsageTests.java
@@ -399,20 +399,6 @@
}
@Test
- public void testRecordClassLoaderContextUnsupportedContext() {
- // Record a secondary dex file.
- assertTrue(record(mFooSecondary1User0));
- // Now update its context.
- TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext(
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
- assertTrue(record(unsupportedContext));
-
- assertPackageDexUsage(null, unsupportedContext);
- writeAndReadBack();
- assertPackageDexUsage(null, unsupportedContext);
- }
-
- @Test
public void testRecordClassLoaderContextTransitionFromUnknown() {
// Record a secondary dex file.
TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext(
@@ -440,29 +426,41 @@
PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId,
"valid_context", "arm");
assertFalse(validContext.isUnknownClassLoaderContext());
- assertFalse(validContext.isUnsupportedClassLoaderContext());
assertFalse(validContext.isVariableClassLoaderContext());
- PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId,
- PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm");
- assertFalse(unsupportedContext.isUnknownClassLoaderContext());
- assertTrue(unsupportedContext.isUnsupportedClassLoaderContext());
- assertFalse(unsupportedContext.isVariableClassLoaderContext());
-
PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId,
PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm");
assertFalse(variableContext.isUnknownClassLoaderContext());
- assertFalse(variableContext.isUnsupportedClassLoaderContext());
assertTrue(variableContext.isVariableClassLoaderContext());
PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId,
PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm");
assertTrue(unknownContext.isUnknownClassLoaderContext());
- assertFalse(unknownContext.isUnsupportedClassLoaderContext());
assertFalse(unknownContext.isVariableClassLoaderContext());
}
@Test
+ public void testUnsupportedClassLoaderDiscardedOnRead() throws Exception {
+ String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n"
+ + mBarSecondary1User0.mPackageName + "\n"
+ + "#" + mBarSecondary1User0.mDexFile + "\n"
+ + "0,0," + mBarSecondary1User0.mLoaderIsa + "\n"
+ + "@\n"
+ + "=UnsupportedClassLoaderContext=\n"
+
+ + mFooSecondary1User0.mPackageName + "\n"
+ + "#" + mFooSecondary1User0.mDexFile + "\n"
+ + "0,0," + mFooSecondary1User0.mLoaderIsa + "\n"
+ + "@\n"
+ + mFooSecondary1User0.mClassLoaderContext + "\n";
+
+ mPackageDexUsage.read(new StringReader(content));
+
+ assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0);
+ assertPackageDexUsage(mBarBaseUser0);
+ }
+
+ @Test
public void testReadVersion1() {
String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
// Equivalent to
diff --git a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index b5fe8b1..a907161 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -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.wm;
@@ -29,11 +29,9 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -41,12 +39,11 @@
* Tests for the {@link TaskStack} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.AnimatingAppWindowTokenRegistryTest
+ * atest FrameworksServicesTests:AnimatingAppWindowTokenRegistryTest
*/
@SmallTest
@Presubmit
@FlakyTest(detail = "Promote once confirmed non-flaky")
-@RunWith(AndroidJUnit4.class)
public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
@Mock
@@ -56,14 +53,14 @@
Runnable mMockEndDeferFinishCallback1;
@Mock
Runnable mMockEndDeferFinishCallback2;
+
@Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
}
@Test
- public void testDeferring() throws Exception {
+ public void testDeferring() {
final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
@@ -85,7 +82,7 @@
}
@Test
- public void testContainerRemoved() throws Exception {
+ public void testContainerRemoved() {
final AppWindowToken window1 = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken window2 = createAppWindow(window1.getTask(), ACTIVITY_TYPE_STANDARD,
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
index fc3ca93..5e12a95 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -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.wm;
@@ -27,28 +27,28 @@
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
+/**
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:AppTransitionControllerTest
+ */
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class AppTransitionControllerTest extends WindowTestsBase {
private AppTransitionController mAppTransitionController;
@Before
public void setUp() throws Exception {
- super.setUp();
- mAppTransitionController = new AppTransitionController(sWm, mDisplayContent);
+ mAppTransitionController = new AppTransitionController(mWm, mDisplayContent);
}
@Test
- public void testTranslucentOpen() throws Exception {
- synchronized (sWm.mGlobalLock) {
+ public void testTranslucentOpen() {
+ synchronized (mWm.mGlobalLock) {
final AppWindowToken behind = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
@@ -64,8 +64,8 @@
}
@Test
- public void testTranslucentClose() throws Exception {
- synchronized (sWm.mGlobalLock) {
+ public void testTranslucentClose() {
+ synchronized (mWm.mGlobalLock) {
final AppWindowToken behind = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index ee6fbac..f12619c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -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.wm;
@@ -32,81 +32,75 @@
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
-import android.content.Context;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
import android.view.IApplicationToken;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link AppTransition}.
*
- * atest AppTransitionTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:AppTransitionTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class AppTransitionTests extends WindowTestsBase {
private DisplayContent mDc;
@Before
public void setUp() throws Exception {
- super.setUp();
- final Context context = InstrumentationRegistry.getTargetContext();
- mDc = sWm.getDefaultDisplayContentLocked();
+ mDc = mWm.getDefaultDisplayContentLocked();
// For unit test, we don't need to test performSurfacePlacement to prevent some
// abnormal interaction with surfaceflinger native side.
- sWm.mRoot = spy(sWm.mRoot);
- doNothing().when(sWm.mRoot).performSurfacePlacement(anyBoolean());
+ mWm.mRoot = spy(mWm.mRoot);
+ doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
}
@Test
- public void testKeyguardOverride() throws Exception {
- sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
- sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ public void testKeyguardOverride() {
+ mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
}
@Test
- public void testKeyguardKeep() throws Exception {
- sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
- sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ public void testKeyguardKeep() {
+ mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
}
@Test
- public void testForceOverride() throws Exception {
- sWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
+ public void testForceOverride() {
+ mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
}
@Test
- public void testCrashing() throws Exception {
- sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
- sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+ public void testCrashing() {
+ mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mDc.mAppTransition.getAppTransition());
}
@Test
- public void testKeepKeyguard_withCrashing() throws Exception {
- sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
- sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+ public void testKeepKeyguard_withCrashing() {
+ mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
}
@Test
- public void testAppTransitionStateForMultiDisplay() throws Exception {
+ public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
@@ -149,7 +143,7 @@
}
@Test
- public void testCleanAppTransitionWhenTaskStackReparent() throws Exception {
+ public void testCleanAppTransitionWhenTaskStackReparent() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index fcd8a39e4..415b5d9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -21,6 +21,8 @@
import static android.content.res.Configuration.EMPTY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -29,10 +31,8 @@
import android.platform.test.annotations.Presubmit;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.WindowTestUtils.TestTaskWindowContainerController;
@@ -41,16 +41,17 @@
/**
* Test class for {@link AppWindowContainerController}.
*
- * atest FrameworksServicesTests:com.android.server.wm.AppWindowContainerControllerTests
+ * atest FrameworksServicesTests:AppWindowContainerControllerTests
*/
+@FlakyTest(bugId = 74078662)
@SmallTest
@Presubmit
-@FlakyTest(bugId = 74078662)
-@org.junit.runner.RunWith(AndroidJUnit4.class)
public class AppWindowContainerControllerTests extends WindowTestsBase {
+ private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
+
@Test
- public void testRemoveContainer() throws Exception {
+ public void testRemoveContainer() {
final WindowTestUtils.TestAppWindowContainerController controller =
createAppWindowController();
@@ -68,7 +69,7 @@
}
@Test
- public void testSetOrientation() throws Exception {
+ public void testSetOrientation() {
final WindowTestUtils.TestAppWindowContainerController controller =
createAppWindowController();
@@ -84,7 +85,7 @@
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, controller.getOrientation());
// Reset display frozen state
- sWm.mDisplayFrozen = false;
+ mWm.mDisplayFrozen = false;
}
private void assertHasStartingWindow(AppWindowToken atoken) {
@@ -103,10 +104,10 @@
}
@Test
- public void testCreateRemoveStartingWindow() throws Exception {
+ public void testCreateRemoveStartingWindow() {
final WindowTestUtils.TestAppWindowContainerController controller =
createAppWindowController();
- controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
waitUntilHandlersIdle();
@@ -118,34 +119,34 @@
}
@Test
- public void testAddRemoveRace() throws Exception {
-
+ public void testAddRemoveRace() {
// There was once a race condition between adding and removing starting windows
for (int i = 0; i < 1000; i++) {
final WindowTestUtils.TestAppWindowContainerController controller =
createAppWindowController();
- controller.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
controller.removeStartingWindow();
waitUntilHandlersIdle();
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
- controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
+ controller.getAppWindowToken(
+ mDisplayContent).getParent().getParent().removeImmediately();
}
}
@Test
- public void testTransferStartingWindow() throws Exception {
+ public void testTransferStartingWindow() {
final WindowTestUtils.TestAppWindowContainerController controller1 =
createAppWindowController();
final WindowTestUtils.TestAppWindowContainerController controller2 =
createAppWindowController();
- controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
waitUntilHandlersIdle();
- controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
true, true, false, true, false, false);
waitUntilHandlersIdle();
@@ -154,19 +155,19 @@
}
@Test
- public void testTransferStartingWindowWhileCreating() throws Exception {
+ public void testTransferStartingWindowWhileCreating() {
final WindowTestUtils.TestAppWindowContainerController controller1 =
createAppWindowController();
final WindowTestUtils.TestAppWindowContainerController controller2 =
createAppWindowController();
- ((TestWindowManagerPolicy) sWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> {
+ ((TestWindowManagerPolicy) mWm.mPolicy).setRunnableWhenAddingSplashScreen(() -> {
// Surprise, ...! Transfer window in the middle of the creation flow.
- controller2.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller2.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, controller1.mToken.asBinder(),
true, true, false, true, false, false);
});
- controller1.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controller1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
waitUntilHandlersIdle();
@@ -175,7 +176,7 @@
}
@Test
- public void testTryTransferStartingWindowFromHiddenAboveToken() throws Exception {
+ public void testTryTransferStartingWindowFromHiddenAboveToken() {
// Add two tasks on top of each other.
TestTaskWindowContainerController taskController =
@@ -186,7 +187,7 @@
createAppWindowController(taskController);
// Add a starting window.
- controllerTop.addStartingWindow(InstrumentationRegistry.getContext().getPackageName(),
+ controllerTop.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
waitUntilHandlersIdle();
@@ -202,7 +203,7 @@
}
@Test
- public void testReparent() throws Exception {
+ public void testReparent() {
final StackWindowController stackController =
createStackControllerOnDisplay(mDisplayContent);
final WindowTestUtils.TestTaskWindowContainerController taskController1 =
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index e3ab5cf..4522494 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -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.wm;
@@ -26,15 +26,14 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import android.view.SurfaceControl;
+import androidx.test.filters.SmallTest;
+
import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -43,10 +42,9 @@
* Animation related tests for the {@link AppWindowToken} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenAnimationTests
+ * atest FrameworksServicesTests:AppWindowTokenAnimationTests
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class AppWindowTokenAnimationTests extends WindowTestsBase {
private TestAppWindowToken mToken;
@@ -56,9 +54,8 @@
@Mock
private AnimationAdapter mSpec;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
@@ -67,7 +64,7 @@
}
@Test
- public void clipAfterAnim_boundsLayerIsCreated() throws Exception {
+ public void clipAfterAnim_boundsLayerIsCreated() {
mToken.mNeedsAnimationBoundsLayer = true;
mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
@@ -78,7 +75,7 @@
}
@Test
- public void clipAfterAnim_boundsLayerIsDestroyed() throws Exception {
+ public void clipAfterAnim_boundsLayerIsDestroyed() {
mToken.mNeedsAnimationBoundsLayer = true;
mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
@@ -95,7 +92,7 @@
}
@Test
- public void clipAfterAnimCancelled_boundsLayerIsDestroyed() throws Exception {
+ public void clipAfterAnimCancelled_boundsLayerIsDestroyed() {
mToken.mNeedsAnimationBoundsLayer = true;
mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final SurfaceControl leash = mToken.mSurfaceAnimator.mLeash;
@@ -108,7 +105,7 @@
}
@Test
- public void clipNoneAnim_boundsLayerIsNotCreated() throws Exception {
+ public void clipNoneAnim_boundsLayerIsNotCreated() {
mToken.mNeedsAnimationBoundsLayer = false;
mToken.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 7935ec1..a8e1ed4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -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.wm;
@@ -47,31 +47,27 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link AppWindowToken} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
+ * atest FrameworksServicesTests:AppWindowTokenTests
*/
+@FlakyTest(bugId = 68267650)
@SmallTest
-// TODO: b/68267650
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
+@Presubmit
public class AppWindowTokenTests extends WindowTestsBase {
TaskStack mStack;
Task mTask;
WindowTestUtils.TestAppWindowToken mToken;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
mStack = createTaskStackOnDisplay(mDisplayContent);
mTask = createTaskInStack(mStack, 0 /* userId */);
mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
@@ -81,7 +77,7 @@
@Test
@Presubmit
- public void testAddWindow_Order() throws Exception {
+ public void testAddWindow_Order() {
assertEquals(0, mToken.getWindowsCount());
final WindowState win1 = createWindow(null, TYPE_APPLICATION, mToken, "win1");
@@ -107,7 +103,7 @@
@Test
@Presubmit
- public void testFindMainWindow() throws Exception {
+ public void testFindMainWindow() {
assertNull(mToken.findMainWindow());
final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
@@ -123,7 +119,7 @@
@Test
@Presubmit
- public void testGetTopFullscreenWindow() throws Exception {
+ public void testGetTopFullscreenWindow() {
assertNull(mToken.getTopFullscreenWindow());
final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, mToken, "window1");
@@ -138,10 +134,10 @@
}
@Test
- public void testLandscapeSeascapeRotationByApp() throws Exception {
+ public void testLandscapeSeascapeRotationByApp() {
// Some plumbing to get the service ready for rotation updates.
- sWm.mDisplayReady = true;
- sWm.mDisplayEnabled = true;
+ mWm.mDisplayReady = true;
+ mWm.mDisplayEnabled = true;
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
@@ -151,26 +147,26 @@
// Set initial orientation and update.
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
- sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
+ mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
mDisplayContent.getDisplayId());
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
appWindow.resizeReported = false;
// Update the orientation to perform 180 degree rotation and check that resize was reported.
mToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
- sWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
+ mWm.updateOrientationFromAppTokens(mDisplayContent.getOverrideConfiguration(), null,
mDisplayContent.getDisplayId());
- sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
assertTrue(appWindow.resizeReported);
appWindow.removeImmediately();
}
@Test
- public void testLandscapeSeascapeRotationByPolicy() throws Exception {
+ public void testLandscapeSeascapeRotationByPolicy() {
// Some plumbing to get the service ready for rotation updates.
- sWm.mDisplayReady = true;
- sWm.mDisplayEnabled = true;
+ mWm.mDisplayReady = true;
+ mWm.mDisplayEnabled = true;
final DisplayRotation spiedRotation = spy(mDisplayContent.getDisplayRotation());
mDisplayContent.setDisplayRotation(spiedRotation);
@@ -194,15 +190,15 @@
private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
- sWm.updateRotation(false, false);
+ mWm.updateRotation(false, false);
// Prevent the next rotation from being deferred by animation.
- sWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
- sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+ mWm.mAnimator.setScreenRotationAnimationLocked(mDisplayContent.getDisplayId(), null);
+ mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
}
@Test
@Presubmit
- public void testGetOrientation() throws Exception {
+ public void testGetOrientation() {
mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
mToken.setFillsParent(false);
@@ -220,7 +216,7 @@
@Test
@Presubmit
- public void testKeyguardFlagsDuringRelaunch() throws Exception {
+ public void testKeyguardFlagsDuringRelaunch() {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
TYPE_BASE_APPLICATION);
attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
@@ -246,7 +242,7 @@
@Test
@FlakyTest(detail = "Promote once confirmed non-flaky")
- public void testStuckExitingWindow() throws Exception {
+ public void testStuckExitingWindow() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
closingWindow.mAnimatingExit = true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index d65055c..1c5391e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -11,12 +11,12 @@
* 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.wm;
-import static android.view.Display.DEFAULT_DISPLAY;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
@@ -24,11 +24,11 @@
import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -37,16 +37,14 @@
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
-import androidx.test.InstrumentationRegistry;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.BoundsAnimationController.BoundsAnimator;
import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
+import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks
@@ -59,21 +57,20 @@
* appropriately.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests
+ * atest FrameworksServicesTests:BoundsAnimationControllerTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class BoundsAnimationControllerTests extends WindowTestsBase {
/**
* Mock value animator to simulate updates with.
*/
- private class MockValueAnimator extends ValueAnimator {
+ private static class MockValueAnimator extends ValueAnimator {
private float mFraction;
- public MockValueAnimator getWithValue(float fraction) {
+ MockValueAnimator getWithValue(float fraction) {
mFraction = fraction;
return this;
}
@@ -87,12 +84,12 @@
/**
* Mock app transition to fire notifications to the bounds animator.
*/
- private class MockAppTransition extends AppTransition {
+ private static class MockAppTransition extends AppTransition {
private AppTransitionListener mListener;
- MockAppTransition(Context context) {
- super(context, sWm, mDisplayContent);
+ MockAppTransition(Context context, WindowManagerService wm, DisplayContent displayContent) {
+ super(context, wm, displayContent);
}
@Override
@@ -120,7 +117,7 @@
/**
* A test animate bounds user to track callbacks from the bounds animation.
*/
- private class TestBoundsAnimationTarget implements BoundsAnimationTarget {
+ private static class TestBoundsAnimationTarget implements BoundsAnimationTarget {
boolean mAwaitingAnimationStart;
boolean mMovedToFullscreen;
@@ -193,21 +190,23 @@
/**
* Drives the animations, makes common assertions along the way.
*/
- private class BoundsAnimationDriver {
+ private static class BoundsAnimationDriver {
- private BoundsAnimationController mController;
- private TestBoundsAnimationTarget mTarget;
+ private final BoundsAnimationController mController;
+ private final TestBoundsAnimationTarget mTarget;
+ private final MockValueAnimator mMockAnimator;
+
private BoundsAnimator mAnimator;
-
private Rect mFrom;
private Rect mTo;
private Rect mLargerBounds;
private Rect mExpectedFinalBounds;
BoundsAnimationDriver(BoundsAnimationController controller,
- TestBoundsAnimationTarget target) {
+ TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) {
mController = controller;
mTarget = target;
+ mMockAnimator = mockValueAnimator;
}
BoundsAnimationDriver start(Rect from, Rect to) {
@@ -222,7 +221,7 @@
// Started, not running
assertTrue(mTarget.mAwaitingAnimationStart);
- assertTrue(!mTarget.mAnimationStarted);
+ assertFalse(mTarget.mAnimationStarted);
startImpl(from, to);
@@ -236,7 +235,7 @@
}
// Started and running
- assertTrue(!mTarget.mAwaitingAnimationStart);
+ assertFalse(mTarget.mAwaitingAnimationStart);
assertTrue(mTarget.mAnimationStarted);
return this;
@@ -268,7 +267,7 @@
assertTrue(mTarget.mForcePipModeChangedCallback);
} else {
// No animation start for replacing animation
- assertTrue(!mTarget.mAnimationStarted);
+ assertFalse(mTarget.mAnimationStarted);
}
mTarget.mAnimationStarted = true;
return this;
@@ -297,7 +296,7 @@
// Animating to larger size
if (mFrom.equals(mLargerBounds)) {
- assertTrue(!mAnimator.animatingToLargerSize());
+ assertFalse(mAnimator.animatingToLargerSize());
} else if (mTo.equals(mLargerBounds)) {
assertTrue(mAnimator.animatingToLargerSize());
}
@@ -339,10 +338,10 @@
mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f));
// Not started, not running, cancel reset
- assertTrue(!mTarget.mCancelRequested);
+ assertFalse(mTarget.mCancelRequested);
// Stack/task bounds not updated
- assertTrue(!mTarget.mBoundsUpdated);
+ assertFalse(mTarget.mBoundsUpdated);
// Callback made
assertTrue(mTarget.mAnimationEnded);
@@ -372,14 +371,10 @@
return this;
}
- private Rect getLargerBounds(Rect r1, Rect r2) {
+ private static Rect getLargerBounds(Rect r1, Rect r2) {
int r1Area = r1.width() * r1.height();
int r2Area = r2.width() * r2.height();
- if (r1Area <= r2Area) {
- return r2;
- } else {
- return r1;
- }
+ return (r1Area <= r2Area) ? r2 : r1;
}
}
@@ -395,32 +390,29 @@
// Common
private MockAppTransition mMockAppTransition;
- private MockValueAnimator mMockAnimator;
private TestBoundsAnimationTarget mTarget;
private BoundsAnimationController mController;
private BoundsAnimationDriver mDriver;
// Temp
- private Rect mTmpRect = new Rect();
+ private static final Rect sTmpRect = new Rect();
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
-
- final Context context = InstrumentationRegistry.getTargetContext();
+ final Context context = getInstrumentation().getTargetContext();
final Handler handler = new Handler(Looper.getMainLooper());
- mMockAppTransition = new MockAppTransition(context);
- mMockAnimator = new MockValueAnimator();
+ mMockAppTransition = new MockAppTransition(context, mWm, mDisplayContent);
mTarget = new TestBoundsAnimationTarget();
mController = new BoundsAnimationController(context, mMockAppTransition, handler, null);
- mDriver = new BoundsAnimationDriver(mController, mTarget);
+ final MockValueAnimator mockValueAnimator = new MockValueAnimator();
+ mDriver = new BoundsAnimationDriver(mController, mTarget, mockValueAnimator);
}
/** BASE TRANSITIONS **/
@UiThreadTest
@Test
- public void testFullscreenToFloatingTransition() throws Exception {
+ public void testFullscreenToFloatingTransition() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
@@ -432,7 +424,7 @@
@UiThreadTest
@Test
- public void testFloatingToFullscreenTransition() throws Exception {
+ public void testFloatingToFullscreenTransition() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
@@ -444,7 +436,7 @@
@UiThreadTest
@Test
- public void testFloatingToSmallerFloatingTransition() throws Exception {
+ public void testFloatingToSmallerFloatingTransition() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
@@ -456,7 +448,7 @@
@UiThreadTest
@Test
- public void testFloatingToLargerFloatingTransition() throws Exception {
+ public void testFloatingToLargerFloatingTransition() {
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0f)
@@ -470,7 +462,7 @@
@UiThreadTest
@Test
- public void testFullscreenToFloatingCancelFromTarget() throws Exception {
+ public void testFullscreenToFloatingCancelFromTarget() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -480,7 +472,7 @@
@UiThreadTest
@Test
- public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception {
+ public void testFullscreenToFloatingCancelFromAnimationToSameBounds() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -491,7 +483,7 @@
@UiThreadTest
@Test
- public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception {
+ public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -503,7 +495,7 @@
@UiThreadTest
@Test
- public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception {
+ public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() {
// When animating from fullscreen and the animation is interruped, we expect the animation
// start callback to be made, with a forced pip mode change callback
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
@@ -518,7 +510,7 @@
@UiThreadTest
@Test
- public void testFloatingToFullscreenCancelFromTarget() throws Exception {
+ public void testFloatingToFullscreenCancelFromTarget() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -528,7 +520,7 @@
@UiThreadTest
@Test
- public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception {
+ public void testFloatingToFullscreenCancelFromAnimationToSameBounds() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -539,7 +531,7 @@
@UiThreadTest
@Test
- public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception {
+ public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -553,7 +545,7 @@
@UiThreadTest
@Test
- public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception {
+ public void testFloatingToSmallerFloatingCancelFromTarget() {
mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -563,7 +555,7 @@
@UiThreadTest
@Test
- public void testFloatingToLargerFloatingCancelFromTarget() throws Exception {
+ public void testFloatingToLargerFloatingCancelFromTarget() {
mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
@@ -575,7 +567,7 @@
@UiThreadTest
@Test
- public void testBoundsAreCopied() throws Exception {
+ public void testBoundsAreCopied() {
Rect from = new Rect(0, 0, 100, 100);
Rect to = new Rect(25, 25, 75, 75);
mDriver.start(from, to)
@@ -588,9 +580,9 @@
/**
* @return whether the task and stack bounds would be the same if they were at the same offset.
*/
- private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) {
- mTmpRect.set(taskBounds);
- mTmpRect.offsetTo(stackBounds.left, stackBounds.top);
- return stackBounds.equals(mTmpRect);
+ private static boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) {
+ sTmpRect.set(taskBounds);
+ sTmpRect.offsetTo(stackBounds.left, stackBounds.top);
+ return stackBounds.equals(sTmpRect);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
index 21555e3..b6a7cfb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DimmerTests.java
@@ -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.wm;
@@ -32,26 +32,22 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.DimmerTests;
+ * atest FrameworksServicesTests:DimmerTests;
*/
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class DimmerTests extends WindowTestsBase {
- private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
+ private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
final SurfaceControl mControl = mock(SurfaceControl.class);
final SurfaceControl.Transaction mTransaction = mock(SurfaceControl.Transaction.class);
- TestWindowContainer() {
- super(sWm);
+ TestWindowContainer(WindowManagerService wm) {
+ super(wm);
}
@Override
@@ -65,13 +61,13 @@
}
}
- private class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
+ private static class MockSurfaceBuildingContainer extends WindowContainer<TestWindowContainer> {
final SurfaceSession mSession = new SurfaceSession();
final SurfaceControl mHostControl = mock(SurfaceControl.class);
final SurfaceControl.Transaction mHostTransaction = mock(SurfaceControl.Transaction.class);
- MockSurfaceBuildingContainer() {
- super(sWm);
+ MockSurfaceBuildingContainer(WindowManagerService wm) {
+ super(wm);
}
class MockSurfaceBuilder extends SurfaceControl.Builder {
@@ -116,15 +112,14 @@
@Before
public void setUp() throws Exception {
- super.setUp();
- mHost = new MockSurfaceBuildingContainer();
+ mHost = new MockSurfaceBuildingContainer(mWm);
mSurfaceAnimatorStarter = spy(new SurfaceAnimatorStarterImpl());
mTransaction = mock(SurfaceControl.Transaction.class);
mDimmer = new Dimmer(mHost, mSurfaceAnimatorStarter);
}
@Test
- public void testDimAboveNoChildCreatesSurface() throws Exception {
+ public void testDimAboveNoChildCreatesSurface() {
final float alpha = 0.8f;
mDimmer.dimAbove(mTransaction, alpha);
@@ -137,7 +132,7 @@
}
@Test
- public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() throws Exception {
+ public void testDimAboveNoChildRedundantlyUpdatesAlphaOnExistingSurface() {
float alpha = 0.8f;
mDimmer.dimAbove(mTransaction, alpha);
final SurfaceControl firstSurface = getDimLayer();
@@ -150,7 +145,7 @@
}
@Test
- public void testUpdateDimsAppliesSize() throws Exception {
+ public void testUpdateDimsAppliesSize() {
mDimmer.dimAbove(mTransaction, 0.8f);
int width = 100;
@@ -163,7 +158,7 @@
}
@Test
- public void testDimAboveNoChildNotReset() throws Exception {
+ public void testDimAboveNoChildNotReset() {
mDimmer.dimAbove(mTransaction, 0.8f);
SurfaceControl dimLayer = getDimLayer();
mDimmer.resetDimStates();
@@ -174,8 +169,8 @@
}
@Test
- public void testDimAboveWithChildCreatesSurfaceAboveChild() throws Exception {
- TestWindowContainer child = new TestWindowContainer();
+ public void testDimAboveWithChildCreatesSurfaceAboveChild() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
final float alpha = 0.8f;
@@ -189,8 +184,8 @@
}
@Test
- public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() throws Exception {
- TestWindowContainer child = new TestWindowContainer();
+ public void testDimBelowWithChildSurfaceCreatesSurfaceBelowChild() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
final float alpha = 0.8f;
@@ -204,8 +199,8 @@
}
@Test
- public void testDimBelowWithChildSurfaceDestroyedWhenReset() throws Exception {
- TestWindowContainer child = new TestWindowContainer();
+ public void testDimBelowWithChildSurfaceDestroyedWhenReset() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
final float alpha = 0.8f;
@@ -220,8 +215,8 @@
}
@Test
- public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() throws Exception {
- TestWindowContainer child = new TestWindowContainer();
+ public void testDimBelowWithChildSurfaceNotDestroyedWhenPersisted() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
final float alpha = 0.8f;
@@ -236,9 +231,9 @@
}
@Test
- public void testDimUpdateWhileDimming() throws Exception {
+ public void testDimUpdateWhileDimming() {
Rect bounds = new Rect();
- TestWindowContainer child = new TestWindowContainer();
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
final float alpha = 0.8f;
@@ -258,8 +253,8 @@
}
@Test
- public void testRemoveDimImmediately() throws Exception {
- TestWindowContainer child = new TestWindowContainer();
+ public void testRemoveDimImmediately() {
+ TestWindowContainer child = new TestWindowContainer(mWm);
mHost.addChild(child, 0);
mDimmer.dimAbove(mTransaction, child, 1);
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 8b75570..dd374e9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -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.wm;
@@ -53,7 +53,6 @@
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
-import android.util.SparseIntArray;
import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.MotionEvent;
@@ -61,12 +60,10 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.Arrays;
@@ -78,16 +75,15 @@
* Tests for the {@link DisplayContent} class.
*
* Build/Install/Run:
- * atest com.android.server.wm.DisplayContentTests
+ * atest FrameworksServicesTests:DisplayContentTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class DisplayContentTests extends WindowTestsBase {
@Test
@FlakyTest(bugId = 77772044)
- public void testForAllWindows() throws Exception {
+ public void testForAllWindows() {
final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
mDisplayContent, "exiting app");
final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
@@ -108,11 +104,11 @@
}
@Test
- public void testForAllWindows_WithAppImeTarget() throws Exception {
+ public void testForAllWindows_WithAppImeTarget() {
final WindowState imeAppTarget =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
- sWm.mInputMethodTarget = imeAppTarget;
+ mWm.mInputMethodTarget = imeAppTarget;
assertForAllWindowsOrder(Arrays.asList(
mWallpaperWindow,
@@ -128,8 +124,8 @@
}
@Test
- public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
- sWm.mInputMethodTarget = mChildAppWindowAbove;
+ public void testForAllWindows_WithChildWindowImeTarget() {
+ mWm.mInputMethodTarget = mChildAppWindowAbove;
assertForAllWindowsOrder(Arrays.asList(
mWallpaperWindow,
@@ -144,8 +140,8 @@
}
@Test
- public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
- sWm.mInputMethodTarget = mStatusBarWindow;
+ public void testForAllWindows_WithStatusBarImeTarget() {
+ mWm.mInputMethodTarget = mStatusBarWindow;
assertForAllWindowsOrder(Arrays.asList(
mWallpaperWindow,
@@ -160,7 +156,7 @@
}
@Test
- public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
+ public void testForAllWindows_WithInBetweenWindowToken() {
// This window is set-up to be z-ordered between some windows that go in the same token like
// the nav bar and status bar.
final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
@@ -180,7 +176,7 @@
}
@Test
- public void testComputeImeTarget() throws Exception {
+ public void testComputeImeTarget() {
// Verify that an app window can be an ime target.
final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
appWin.setHasSurface(true);
@@ -203,7 +199,7 @@
* container references updates.
*/
@Test
- public void testMoveStackBetweenDisplays() throws Exception {
+ public void testMoveStackBetweenDisplays() {
// Create a second display.
final DisplayContent dc = createNewDisplay();
@@ -233,7 +229,7 @@
* This tests override configuration updates for display content.
*/
@Test
- public void testDisplayOverrideConfigUpdate() throws Exception {
+ public void testDisplayOverrideConfigUpdate() {
final int displayId = mDisplayContent.getDisplayId();
final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
@@ -242,7 +238,7 @@
newOverrideConfig.densityDpi += 120;
newOverrideConfig.fontScale += 0.3;
- sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
// Check that override config is applied.
assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
@@ -252,7 +248,7 @@
* This tests global configuration updates when default display config is updated.
*/
@Test
- public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
+ public void testDefaultDisplayOverrideConfigUpdate() {
final Configuration currentConfig = mDisplayContent.getConfiguration();
// Create new, slightly changed override configuration and apply it to the display.
@@ -260,16 +256,16 @@
newOverrideConfig.densityDpi += 120;
newOverrideConfig.fontScale += 0.3;
- sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
+ mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
// Check that global configuration is updated, as we've updated default display's config.
- Configuration globalConfig = sWm.mRoot.getConfiguration();
+ Configuration globalConfig = mWm.mRoot.getConfiguration();
assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
// Return back to original values.
- sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
- globalConfig = sWm.mRoot.getConfiguration();
+ mWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
+ globalConfig = mWm.mRoot.getConfiguration();
assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
}
@@ -278,8 +274,8 @@
* Tests tapping on a stack in different display results in window gaining focus.
*/
@Test
- public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
- DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
+ public void testInputEventBringsCorrectDisplayInFocus() {
+ DisplayContent dc0 = mWm.getDefaultDisplayContentLocked();
// Create a second display
final DisplayContent dc1 = createNewDisplay();
@@ -303,51 +299,51 @@
// tap on primary display.
tapOnDisplay(dc0);
// Check focus is on primary display.
- assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+ assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc0.findFocusedWindow());
// Tap on secondary display.
tapOnDisplay(dc1);
// Check focus is on secondary.
- assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
+ assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
dc1.findFocusedWindow());
}
@Test
- public void testFocusedWindowMultipleDisplays() throws Exception {
+ public void testFocusedWindowMultipleDisplays() {
// Create a focusable window and check that focus is calculated correctly
final WindowState window1 =
createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
updateFocusedWindow();
assertTrue(window1.isFocused());
- assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
// Check that a new display doesn't affect focus
final DisplayContent dc = createNewDisplay();
updateFocusedWindow();
assertTrue(window1.isFocused());
- assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
// Add a window to the second display, and it should be focused
final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
updateFocusedWindow();
assertTrue(window1.isFocused());
assertTrue(window2.isFocused());
- assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+ assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
// Move the first window to the to including parents, and make sure focus is updated
window1.getParent().positionChildAt(POSITION_TOP, window1, true);
updateFocusedWindow();
assertTrue(window1.isFocused());
assertTrue(window2.isFocused());
- assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
+ assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
}
/**
* This tests setting the maximum ui width on a display.
*/
@Test
- public void testMaxUiWidth() throws Exception {
+ public void testMaxUiWidth() {
// Prevent base display metrics for test from being updated to the value of real display.
final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
final int baseWidth = 1440;
@@ -439,8 +435,8 @@
}
@Test
- public void testDisplayCutout_rot0() throws Exception {
- synchronized (sWm.getWindowManagerLock()) {
+ public void testDisplayCutout_rot0() {
+ synchronized (mWm.getWindowManagerLock()) {
final DisplayContent dc = createNewDisplay();
dc.mInitialDisplayWidth = 200;
dc.mInitialDisplayHeight = 400;
@@ -458,8 +454,8 @@
}
@Test
- public void testDisplayCutout_rot90() throws Exception {
- synchronized (sWm.getWindowManagerLock()) {
+ public void testDisplayCutout_rot90() {
+ synchronized (mWm.getWindowManagerLock()) {
// Prevent mInitialDisplayCutout from being updated from real display (e.g. null
// if the device has no cutout).
final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
@@ -476,7 +472,8 @@
final Rect r1 = new Rect(left, top, right, bottom);
final DisplayCutout cutout = new WmDisplayCutout(
- fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
+ fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP),
+ null)
.computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
dc.mInitialDisplayCutout = cutout;
@@ -500,8 +497,8 @@
}
@Test
- public void testLayoutSeq_assignedDuringLayout() throws Exception {
- synchronized (sWm.getWindowManagerLock()) {
+ public void testLayoutSeq_assignedDuringLayout() {
+ synchronized (mWm.getWindowManagerLock()) {
final DisplayContent dc = createNewDisplay();
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
@@ -533,7 +530,7 @@
assertEquals("Visible keyguard must influence device orientation",
SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
- sWm.setKeyguardGoingAway(true);
+ mWm.setKeyguardGoingAway(true);
assertEquals("Keyguard that is going away must not influence device orientation",
SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
}
@@ -543,10 +540,10 @@
final DisplayContent dc = createNewDisplay();
assertTrue(dc.mShouldOverrideDisplayConfiguration);
- sWm.dontOverrideDisplayInfo(dc.getDisplayId());
+ mWm.dontOverrideDisplayInfo(dc.getDisplayId());
assertFalse(dc.mShouldOverrideDisplayConfiguration);
- verify(sWm.mDisplayManagerInternal, times(1))
+ verify(mWm.mDisplayManagerInternal, times(1))
.setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
}
@@ -572,7 +569,7 @@
}
private boolean isOptionsPanelAtRight(int displayId) {
- return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
+ return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
}
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
@@ -583,8 +580,8 @@
}
private void updateFocusedWindow() {
- synchronized (sWm.mGlobalLock) {
- sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
+ synchronized (mWm.mGlobalLock) {
+ mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
index 3be1258..f0c49c8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplaySettingsTests.java
@@ -12,11 +12,12 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *
*/
package com.android.server.wm;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -31,15 +32,13 @@
import android.view.DisplayInfo;
import android.view.Surface;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.policy.WindowManagerPolicy;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.io.File;
@@ -47,14 +46,13 @@
* Tests for the {@link DisplaySettings} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.DisplaySettingsTests
+ * atest FrameworksServicesTests:DisplaySettingsTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class DisplaySettingsTests extends WindowTestsBase {
- private File mTestFolder;
+ private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
private DisplaySettings mTarget;
private DisplayContent mPrimaryDisplay;
@@ -62,21 +60,23 @@
@Before
public void setUp() throws Exception {
- super.setUp();
+ deleteRecursively(TEST_FOLDER);
- mTestFolder = InstrumentationRegistry.getContext().getCacheDir();
- deleteRecursively(mTestFolder);
+ mWm.setSupportsFreeformWindowManagement(false);
+ mWm.setIsPc(false);
- sWm.setSupportsFreeformWindowManagement(false);
- sWm.setIsPc(false);
+ mTarget = new DisplaySettings(mWm, TEST_FOLDER);
- mTarget = new DisplaySettings(sWm, mTestFolder);
-
- mPrimaryDisplay = sWm.getDefaultDisplayContentLocked();
+ mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
mSecondaryDisplay = mDisplayContent;
assertNotEquals(Display.DEFAULT_DISPLAY, mSecondaryDisplay.getDisplayId());
}
+ @After
+ public void tearDown() {
+ deleteRecursively(TEST_FOLDER);
+ }
+
@Test
public void testPrimaryDisplayDefaultToFullscreenWithoutFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -87,7 +87,7 @@
@Test
public void testPrimaryDisplayDefaultToFullscreenWithFreeformSupportNonPc() {
- sWm.setSupportsFreeformWindowManagement(true);
+ mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -97,8 +97,8 @@
@Test
public void testPrimaryDisplayDefaultToFreeformWithFreeformIsPc() {
- sWm.setSupportsFreeformWindowManagement(true);
- sWm.setIsPc(true);
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setIsPc(true);
mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
@@ -116,7 +116,7 @@
@Test
public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportNonPc() {
- sWm.setSupportsFreeformWindowManagement(true);
+ mWm.setSupportsFreeformWindowManagement(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -126,8 +126,8 @@
@Test
public void testSecondaryDisplayDefaultToFreeformWithFreeformSupportIsPc() {
- sWm.setSupportsFreeformWindowManagement(true);
- sWm.setIsPc(true);
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setIsPc(true);
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
@@ -157,7 +157,7 @@
doAnswer(invocation -> {
((DisplayInfo) invocation.getArguments()[1]).copyFrom(originalInfo);
return null;
- }).when(sWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
+ }).when(mWm.mDisplayManagerInternal).getNonOverrideDisplayInfo(anyInt(), any());
mTarget.setForcedSize(mSecondaryDisplay, 1000 /* width */, 2000 /* height */);
applySettingsToDisplayByNewInstance(mSecondaryDisplay);
@@ -165,7 +165,7 @@
assertEquals(1000 /* width */, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(2000 /* height */, mSecondaryDisplay.mBaseDisplayHeight);
- sWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId());
+ mWm.clearForcedDisplaySize(mSecondaryDisplay.getDisplayId());
assertEquals(mSecondaryDisplay.mInitialDisplayWidth, mSecondaryDisplay.mBaseDisplayWidth);
assertEquals(mSecondaryDisplay.mInitialDisplayHeight, mSecondaryDisplay.mBaseDisplayHeight);
}
@@ -177,7 +177,7 @@
assertEquals(600 /* density */, mSecondaryDisplay.mBaseDisplayDensity);
- sWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */);
+ mWm.clearForcedDisplayDensityForUser(mSecondaryDisplay.getDisplayId(), 0 /* userId */);
assertEquals(mSecondaryDisplay.mInitialDisplayDensity,
mSecondaryDisplay.mBaseDisplayDensity);
}
@@ -189,7 +189,7 @@
assertTrue(mSecondaryDisplay.mDisplayScalingDisabled);
- sWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(),
+ mWm.setForcedDisplayScalingMode(mSecondaryDisplay.getDisplayId(),
DisplayContent.FORCE_SCALING_MODE_AUTO);
assertFalse(mSecondaryDisplay.mDisplayScalingDisabled);
}
@@ -298,20 +298,20 @@
* that also means the previous state must be written correctly.
*/
private void applySettingsToDisplayByNewInstance(DisplayContent display) {
- new DisplaySettings(sWm, mTestFolder).applySettingsToDisplayLocked(display);
+ new DisplaySettings(mWm, TEST_FOLDER).applySettingsToDisplayLocked(display);
}
private static boolean deleteRecursively(File file) {
+ boolean fullyDeleted = true;
if (file.isFile()) {
return file.delete();
+ } else if (file.isDirectory()) {
+ final File[] files = file.listFiles();
+ for (File child : files) {
+ fullyDeleted &= deleteRecursively(child);
+ }
+ fullyDeleted &= file.delete();
}
-
- boolean fullyDeleted = true;
- final File[] files = file.listFiles();
- for (File child : files) {
- fullyDeleted &= deleteRecursively(child);
- }
- fullyDeleted &= file.delete();
return fullyDeleted;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 31b2fef..55e766d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -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.wm;
@@ -40,23 +40,24 @@
import android.view.SurfaceSession;
import android.view.View;
-import com.android.internal.annotations.GuardedBy;
+import androidx.test.filters.SmallTest;
+
import com.android.server.LocalServices;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import androidx.test.filters.SmallTest;
-
/**
* Tests for the {@link DragDropController} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
+ * atest FrameworksServicesTests:DragDropControllerTests
*/
@SmallTest
@Presubmit
@@ -67,7 +68,6 @@
private IBinder mToken;
static class TestDragDropController extends DragDropController {
- @GuardedBy("sWm.mWindowMap")
private Runnable mCloseCallback;
TestDragDropController(WindowManagerService service, Looper looper) {
@@ -107,31 +107,34 @@
return window;
}
- @Override
- @Before
- public void setUp() throws Exception {
+ @BeforeClass
+ public static void setUpOnce() {
final UserManagerInternal userManager = mock(UserManagerInternal.class);
LocalServices.addService(UserManagerInternal.class, userManager);
+ }
- super.setUp();
+ @AfterClass
+ public static void tearDownOnce() {
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
+ }
- mTarget = new TestDragDropController(sWm, sWm.mH.getLooper());
+ @Before
+ public void setUp() throws Exception {
+ mTarget = new TestDragDropController(mWm, mWm.mH.getLooper());
mDisplayContent = spy(mDisplayContent);
mWindow = createDropTargetWindow("Drag test window", 0);
doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
- when(sWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
+ when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
- synchronized (sWm.mGlobalLock) {
- sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+ synchronized (mWm.mGlobalLock) {
+ mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
}
}
- @Override
@After
public void tearDown() throws Exception {
- LocalServices.removeServiceForTest(UserManagerInternal.class);
final CountDownLatch latch;
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
if (!mTarget.dragDropActiveLocked()) {
return;
}
@@ -142,8 +145,6 @@
mTarget.setOnClosedCallbackLocked(latch::countDown);
}
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- super.tearDown();
}
@Test
@@ -174,7 +175,7 @@
.setFormat(PixelFormat.TRANSLUCENT)
.build();
- assertTrue(sWm.mInputManager.transferTouchFocus(null, null));
+ assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
mToken = mTarget.performDrag(
new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
data);
diff --git a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
index 7222a99..1fae317 100644
--- a/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/PinnedStackControllerTest.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -16,17 +32,18 @@
import android.view.IPinnedStackListener;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+/**
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:PinnedStackControllerTest
+ */
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class PinnedStackControllerTest extends WindowTestsBase {
@Mock private IPinnedStackListener mIPinnedStackListener;
@@ -34,15 +51,15 @@
@Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
+
when(mIPinnedStackListener.asBinder()).thenReturn(mIPinnedStackListenerStub);
}
@Test
public void setShelfHeight_shelfVisibilityChangedTriggered() throws RemoteException {
- sWm.mSupportsPictureInPicture = true;
- sWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
+ mWm.mSupportsPictureInPicture = true;
+ mWm.registerPinnedStackListener(DEFAULT_DISPLAY, mIPinnedStackListener);
verify(mIPinnedStackListener).onImeVisibilityChanged(false, 0);
verify(mIPinnedStackListener).onShelfVisibilityChanged(false, 0);
@@ -55,7 +72,7 @@
final int SHELF_HEIGHT = 300;
- sWm.setShelfHeight(true, SHELF_HEIGHT);
+ mWm.setShelfHeight(true, SHELF_HEIGHT);
verify(mIPinnedStackListener).onShelfVisibilityChanged(true, SHELF_HEIGHT);
verify(mIPinnedStackListener).onMovementBoundsChanged(any(), any(), any(), eq(false),
eq(true), anyInt());
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 088e229..fe5fc06 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -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.wm;
@@ -24,9 +24,9 @@
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
-import static org.junit.Assert.fail;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
@@ -42,22 +42,20 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * atest FrameworksServicesTests:com.android.server.wm.RecentsAnimationControllerTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:RecentsAnimationControllerTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class RecentsAnimationControllerTest extends WindowTestsBase {
@Mock SurfaceControl mMockLeash;
@@ -69,10 +67,10 @@
@Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
+
when(mMockRunner.asBinder()).thenReturn(new Binder());
- mController = new RecentsAnimationController(sWm, mMockRunner, mAnimationCallbacks,
+ mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
DEFAULT_DISPLAY);
}
@@ -96,7 +94,7 @@
}
@Test
- public void testCancelAfterRemove_expectIgnored() throws Exception {
+ public void testCancelAfterRemove_expectIgnored() {
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(),
@@ -114,10 +112,10 @@
}
}
- @Test
@FlakyTest(bugId = 117117823)
- public void testIncludedApps_expectTargetAndVisible() throws Exception {
- sWm.setRecentsAnimationController(mController);
+ @Test
+ public void testIncludedApps_expectTargetAndVisible() {
+ mWm.setRecentsAnimationController(mController);
final AppWindowToken homeAppWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index ae92984..fa53795 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -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.wm;
@@ -39,7 +39,6 @@
import android.view.SurfaceControl.Transaction;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.testutils.OffsettableClock;
import com.android.server.testutils.TestHandler;
@@ -47,17 +46,16 @@
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:RemoteAnimationControllerTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class RemoteAnimationControllerTest extends WindowTestsBase {
@Mock SurfaceControl mMockLeash;
@@ -71,15 +69,13 @@
@Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
+
when(mMockRunner.asBinder()).thenReturn(new Binder());
mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
mAdapter.setCallingPid(123);
- sWm.mH.runWithScissors(() -> {
- mHandler = new TestHandler(null, mClock);
- }, 0);
- mController = new RemoteAnimationController(sWm, mAdapter, mHandler);
+ mWm.mH.runWithScissors(() -> mHandler = new TestHandler(null, mClock), 0);
+ mController = new RemoteAnimationController(mWm, mAdapter, mHandler);
}
@Test
@@ -91,7 +87,7 @@
new Point(50, 100), new Rect(50, 100, 150, 150));
adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
mController.goodToGo();
- sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
@@ -146,7 +142,7 @@
@Test
public void testTimeout_scaled() throws Exception {
- sWm.setAnimationScale(2, 5.0f);
+ mWm.setAnimationScale(2, 5.0f);
try{
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
@@ -165,19 +161,19 @@
verify(mMockRunner).onAnimationCancelled();
verify(mFinishedCallback).onAnimationFinished(eq(adapter));
} finally {
- sWm.setAnimationScale(2, 1.0f);
+ mWm.setAnimationScale(2, 1.0f);
}
}
@Test
- public void testZeroAnimations() throws Exception {
+ public void testZeroAnimations() {
mController.goodToGo();
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
@Test
- public void testNotReallyStarted() throws Exception {
+ public void testNotReallyStarted() {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mController.createAnimationAdapter(win.mAppToken,
new Point(50, 100), new Rect(50, 100, 150, 150));
@@ -195,7 +191,7 @@
new Point(50, 100), new Rect(50, 100, 150, 150));
adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
mController.goodToGo();
- sWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
final ArgumentCaptor<IRemoteAnimationFinishedCallback> finishedCaptor =
@@ -206,7 +202,7 @@
}
@Test
- public void testRemovedBeforeStarted() throws Exception {
+ public void testRemovedBeforeStarted() {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
new Point(50, 100), new Rect(50, 100, 150, 150));
diff --git a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
index 001bed9..62a617d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -1,30 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.wm;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link RootWindowContainer} class.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.RootWindowContainerTests
+ * atest FrameworksServicesTests:RootWindowContainerTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class RootWindowContainerTests extends WindowTestsBase {
@Test
- public void testSetDisplayOverrideConfigurationIfNeeded() throws Exception {
- synchronized (sWm.mGlobalLock) {
+ public void testSetDisplayOverrideConfigurationIfNeeded() {
+ synchronized (mWm.mGlobalLock) {
// Add first stack we expect to be updated with configuration change.
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
stack.getOverrideConfiguration().windowConfiguration.setBounds(new Rect(0, 0, 5, 5));
@@ -41,12 +54,12 @@
override.windowConfiguration.setBounds(new Rect(0, 0, 10, 10));
// Set display override.
- final int[] results = sWm.mRoot.setDisplayOverrideConfigurationIfNeeded(override,
+ final int[] results = mWm.mRoot.setDisplayOverrideConfigurationIfNeeded(override,
mDisplayContent.getDisplayId());
// Ensure only first stack is returned.
- assertTrue(results.length == 1);
- assertTrue(results[0] == stack.mStackId);
+ assertEquals(1, results.length);
+ assertEquals(stack.mStackId, results[0]);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
index 9f2645c..ce5b13c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/StackWindowControllerTests.java
@@ -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.wm;
@@ -25,10 +25,8 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link StackWindowController}.
@@ -38,10 +36,9 @@
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class StackWindowControllerTests extends WindowTestsBase {
@Test
- public void testRemoveContainer() throws Exception {
+ public void testRemoveContainer() {
final StackWindowController stackController =
createStackControllerOnDisplay(mDisplayContent);
final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -61,7 +58,7 @@
}
@Test
- public void testRemoveContainer_deferRemoval() throws Exception {
+ public void testRemoveContainer_deferRemoval() {
final StackWindowController stackController =
createStackControllerOnDisplay(mDisplayContent);
final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -87,7 +84,7 @@
}
@Test
- public void testReparent() throws Exception {
+ public void testReparent() {
// Create first stack on primary display.
final StackWindowController stack1Controller =
createStackControllerOnDisplay(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index 4551c36..584f269 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -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.wm;
@@ -27,6 +27,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static java.util.concurrent.TimeUnit.SECONDS;
+
import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
import android.animation.ValueAnimator;
import android.graphics.Matrix;
@@ -42,30 +44,27 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import static java.util.concurrent.TimeUnit.SECONDS;
-
import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimationRunner}.
*
- * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimationRunnerTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:SurfaceAnimationRunnerTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class SurfaceAnimationRunnerTest extends WindowTestsBase {
@Mock SurfaceControl mMockSurface;
@@ -79,7 +78,8 @@
@Before
public void setUp() throws Exception {
- super.setUp();
+ MockitoAnnotations.initMocks(this);
+
mFinishCallbackLatch = new CountDownLatch(1);
mSurfaceAnimationRunner = new SurfaceAnimationRunner(null /* callbackProvider */, null,
mMockTransaction, mMockPowerManager);
@@ -112,7 +112,7 @@
}
@Test
- public void testCancel_notStarted() throws Exception {
+ public void testCancel_notStarted() {
mSurfaceAnimationRunner = new SurfaceAnimationRunner(new NoOpFrameCallbackProvider(), null,
mMockTransaction, mMockPowerManager);
mSurfaceAnimationRunner
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 7b5e8de..6833dc5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -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.wm;
@@ -35,14 +35,13 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -50,11 +49,11 @@
/**
* Test class for {@link SurfaceAnimatorTest}.
*
- * atest FrameworksServicesTests:com.android.server.wm.SurfaceAnimatorTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:SurfaceAnimatorTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class SurfaceAnimatorTest extends WindowTestsBase {
@Mock AnimationAdapter mSpec;
@@ -68,15 +67,24 @@
@Before
public void setUp() throws Exception {
- super.setUp();
MockitoAnnotations.initMocks(this);
- mAnimatable = new MyAnimatable();
- mAnimatable2 = new MyAnimatable();
- mDeferFinishAnimatable = new DeferFinishAnimatable();
+
+ mAnimatable = new MyAnimatable(mWm, mSession, mTransaction);
+ mAnimatable2 = new MyAnimatable(mWm, mSession, mTransaction);
+ mDeferFinishAnimatable = new DeferFinishAnimatable(mWm, mSession, mTransaction);
+ }
+
+ @After
+ public void tearDown() {
+ mAnimatable = null;
+ mAnimatable2 = null;
+ mDeferFinishAnimatable = null;
+ mSession.kill();
+ mSession = null;
}
@Test
- public void testRunAnimation() throws Exception {
+ public void testRunAnimation() {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
@@ -92,7 +100,7 @@
}
@Test
- public void testOverrideAnimation() throws Exception {
+ public void testOverrideAnimation() {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
@@ -117,7 +125,7 @@
}
@Test
- public void testCancelAnimation() throws Exception {
+ public void testCancelAnimation() {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
assertAnimating(mAnimatable);
mAnimatable.mSurfaceAnimator.cancelAnimation();
@@ -128,7 +136,7 @@
}
@Test
- public void testDelayingAnimationStart() throws Exception {
+ public void testDelayingAnimationStart() {
mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
verifyZeroInteractions(mSpec);
@@ -139,7 +147,7 @@
}
@Test
- public void testDelayingAnimationStartAndCancelled() throws Exception {
+ public void testDelayingAnimationStartAndCancelled() {
mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
mAnimatable.mSurfaceAnimator.cancelAnimation();
@@ -150,7 +158,7 @@
}
@Test
- public void testTransferAnimation() throws Exception {
+ public void testTransferAnimation() {
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -171,7 +179,7 @@
@Test
@FlakyTest(detail = "Promote once confirmed non-flaky")
- public void testDeferFinish() throws Exception {
+ public void testDeferFinish() {
// Start animation
mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec,
@@ -186,7 +194,7 @@
assertAnimating(mDeferFinishAnimatable);
// Now end defer finishing.
- mDeferFinishAnimatable.endDeferFinishCallback.run();
+ mDeferFinishAnimatable.mEndDeferFinishCallback.run();
assertNotAnimating(mAnimatable2);
assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
verify(mTransaction).destroy(eq(mDeferFinishAnimatable.mLeash));
@@ -202,26 +210,30 @@
assertNull(animatable.mSurfaceAnimator.getAnimation());
}
- private class MyAnimatable implements Animatable {
+ private static class MyAnimatable implements Animatable {
+ private final SurfaceSession mSession;
+ private final Transaction mTransaction;
final SurfaceControl mParent;
final SurfaceControl mSurface;
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
- MyAnimatable() {
- mParent = sWm.makeSurfaceBuilder(mSession)
+ MyAnimatable(WindowManagerService wm, SurfaceSession session, Transaction transaction) {
+ mSession = session;
+ mTransaction = transaction;
+ mParent = wm.makeSurfaceBuilder(mSession)
.setName("test surface parent")
.setSize(3000, 3000)
.build();
- mSurface = sWm.makeSurfaceBuilder(mSession)
+ mSurface = wm.makeSurfaceBuilder(mSession)
.setName("test surface")
.setSize(1, 1)
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, wm);
}
@Override
@@ -281,13 +293,18 @@
private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true;
}
- private class DeferFinishAnimatable extends MyAnimatable {
+ private static class DeferFinishAnimatable extends MyAnimatable {
- Runnable endDeferFinishCallback;
+ Runnable mEndDeferFinishCallback;
+
+ DeferFinishAnimatable(WindowManagerService wm, SurfaceSession session,
+ Transaction transaction) {
+ super(wm, session, transaction);
+ }
@Override
public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
- this.endDeferFinishCallback = endDeferFinishCallback;
+ mEndDeferFinishCallback = endDeferFinishCallback;
return true;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 17b7fc1..785b955 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -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.wm;
@@ -35,24 +35,22 @@
import android.view.Display;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Mockito;
/**
* Tests for the {@link TaskPositioner} class.
*
- * runtest frameworks-services -c com.android.server.wm.TaskPositionerTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskPositionerTests
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
public class TaskPositionerTests extends WindowTestsBase {
- private final boolean DEBUGGING = false;
- private final String TAG = "TaskPositionerTest";
+ private static final boolean DEBUGGING = false;
+ private static final String TAG = "TaskPositionerTest";
private final static int MOUSE_DELTA_X = 5;
private final static int MOUSE_DELTA_Y = 5;
@@ -65,8 +63,6 @@
@Before
public void setUp() throws Exception {
- super.setUp();
-
TaskPositioner.setFactory(null);
final Display display = mDisplayContent.getDisplay();
@@ -77,7 +73,7 @@
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
- mPositioner = new TaskPositioner(sWm, Mockito.mock(IActivityTaskManager.class));
+ mPositioner = new TaskPositioner(mWm, Mockito.mock(IActivityTaskManager.class));
mPositioner.register(mDisplayContent);
mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window"));
@@ -94,7 +90,7 @@
}
@Test
- public void testOverrideFactory() throws Exception {
+ public void testOverrideFactory() {
final boolean[] created = new boolean[1];
created[0] = false;
TaskPositioner.setFactory(new TaskPositioner.Factory() {
@@ -105,7 +101,7 @@
}
});
- assertNull(TaskPositioner.create(sWm));
+ assertNull(TaskPositioner.create(mWm));
assertTrue(created[0]);
}
@@ -114,7 +110,7 @@
* as does some basic tests (e.g. dragging in Y only will keep X stable).
*/
@Test
- public void testBasicFreeWindowResizing() throws Exception {
+ public void testBasicFreeWindowResizing() {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
mDimBounds.set(r);
@@ -175,7 +171,7 @@
* This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
*/
@Test
- public void testFreeWindowResizingTestAllEdges() throws Exception {
+ public void testFreeWindowResizingTestAllEdges() {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
final int midY = (r.top + r.bottom) / 2;
@@ -260,7 +256,7 @@
* right things upon resizing when dragged from the top left corner.
*/
@Test
- public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception {
+ public void testLandscapePreservedWindowResizingDragTopLeft() {
final Rect r = new Rect(100, 220, 700, 520);
mDimBounds.set(r);
@@ -298,7 +294,7 @@
* right things upon resizing when dragged from the left corner.
*/
@Test
- public void testLandscapePreservedWindowResizingDragLeft() throws Exception {
+ public void testLandscapePreservedWindowResizingDragLeft() {
final Rect r = new Rect(100, 220, 700, 520);
final int midY = (r.top + r.bottom) / 2;
mDimBounds.set(r);
@@ -339,7 +335,7 @@
* right things upon resizing when dragged from the top corner.
*/
@Test
- public void testLandscapePreservedWindowResizingDragTop() throws Exception {
+ public void testLandscapePreservedWindowResizingDragTop() {
final Rect r = new Rect(100, 220, 700, 520);
final int midX = (r.left + r.right) / 2;
mDimBounds.set(r);
@@ -376,7 +372,7 @@
* right things upon resizing when dragged from the top left corner.
*/
@Test
- public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception {
+ public void testPortraitPreservedWindowResizingDragTopLeft() {
final Rect r = new Rect(330, 100, 630, 600);
mDimBounds.set(r);
@@ -409,7 +405,7 @@
* right things upon resizing when dragged from the left corner.
*/
@Test
- public void testPortraitPreservedWindowResizingDragLeft() throws Exception {
+ public void testPortraitPreservedWindowResizingDragLeft() {
final Rect r = new Rect(330, 100, 630, 600);
final int midY = (r.top + r.bottom) / 2;
mDimBounds.set(r);
@@ -452,7 +448,7 @@
* right things upon resizing when dragged from the top corner.
*/
@Test
- public void testPortraitPreservedWindowResizingDragTop() throws Exception {
+ public void testPortraitPreservedWindowResizingDragTop() {
final Rect r = new Rect(330, 100, 630, 600);
final int midX = (r.left + r.right) / 2;
mDimBounds.set(r);
@@ -485,7 +481,7 @@
mPositioner.getWindowDragBounds());
}
- private void assertBoundsEquals(Rect expected, Rect actual) {
+ private static void assertBoundsEquals(Rect expected, Rect actual) {
if (DEBUGGING) {
if (!expected.equals(actual)) {
Log.e(TAG, "rect(" + actual.toString() + ") != isRect(" + actual.toString()
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
index d1480c5..00b4629 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -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.wm;
@@ -32,70 +32,66 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link TaskPositioningController} class.
*
- * atest com.android.server.wm.TaskPositioningControllerTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskPositioningControllerTests
*/
-@SmallTest
@FlakyTest(bugId = 117924387)
-@RunWith(AndroidJUnit4.class)
+@SmallTest
@Presubmit
public class TaskPositioningControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 1000;
+
private TaskPositioningController mTarget;
private WindowState mWindow;
@Before
public void setUp() throws Exception {
- super.setUp();
+ assertNotNull(mWm.mTaskPositioningController);
+ mTarget = mWm.mTaskPositioningController;
- assertNotNull(sWm.mTaskPositioningController);
- mTarget = sWm.mTaskPositioningController;
-
- when(sWm.mInputManager.transferTouchFocus(
+ when(mWm.mInputManager.transferTouchFocus(
any(InputChannel.class),
any(InputChannel.class))).thenReturn(true);
mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
mWindow.mInputChannel = new InputChannel();
- synchronized (sWm.mGlobalLock) {
- sWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+ synchronized (mWm.mGlobalLock) {
+ mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
}
}
@Test
- public void testStartAndFinishPositioning() throws Exception {
- synchronized (sWm.mGlobalLock) {
+ public void testStartAndFinishPositioning() {
+ synchronized (mWm.mGlobalLock) {
assertFalse(mTarget.isPositioningLocked());
assertNull(mTarget.getDragWindowHandleLocked());
}
assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
assertTrue(mTarget.isPositioningLocked());
assertNotNull(mTarget.getDragWindowHandleLocked());
}
mTarget.finishTaskPositioning();
// Wait until the looper processes finishTaskPositioning.
- assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+ assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
assertFalse(mTarget.isPositioningLocked());
assertNull(mTarget.getDragWindowHandleLocked());
}
@Test
- public void testHandleTapOutsideTask() throws Exception {
- synchronized (sWm.mGlobalLock) {
-
+ public void testHandleTapOutsideTask() {
+ synchronized (mWm.mGlobalLock) {
assertFalse(mTarget.isPositioningLocked());
assertNull(mTarget.getDragWindowHandleLocked());
}
@@ -106,16 +102,16 @@
mTarget.handleTapOutsideTask(content, 0, 0);
// Wait until the looper processes finishTaskPositioning.
- assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+ assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
assertTrue(mTarget.isPositioningLocked());
assertNotNull(mTarget.getDragWindowHandleLocked());
}
mTarget.finishTaskPositioning();
// Wait until the looper processes finishTaskPositioning.
- assertTrue(sWm.mH.runWithScissors(() -> {}, TIMEOUT_MS));
+ assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
assertFalse(mTarget.isPositioningLocked());
assertNull(mTarget.getDragWindowHandleLocked());
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index c9d8004..1c6afd54 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -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.wm;
@@ -24,32 +24,32 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link TaskSnapshotCache}.
*
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskSnapshotCacheTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
private TaskSnapshotCache mCache;
+ @Override
@Before
- public void setUp() throws Exception {
+ public void setUp() {
super.setUp();
- mCache = new TaskSnapshotCache(sWm, mLoader);
+
+ mCache = new TaskSnapshotCache(mWm, mLoader);
}
@Test
- public void testAppRemoved() throws Exception {
+ public void testAppRemoved() {
final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
mCache.putSnapshot(window.getTask(), createSnapshot());
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -60,7 +60,7 @@
}
@Test
- public void testAppDied() throws Exception {
+ public void testAppDied() {
final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
mCache.putSnapshot(window.getTask(), createSnapshot());
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -71,7 +71,7 @@
}
@Test
- public void testTaskRemoved() throws Exception {
+ public void testTaskRemoved() {
final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
mCache.putSnapshot(window.getTask(), createSnapshot());
assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, 0 /* userId */,
@@ -82,32 +82,32 @@
}
@Test
- public void testReduced_notCached() throws Exception {
+ public void testReduced_notCached() {
final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
- mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot());
+ mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot());
mPersister.waitForQueueEmpty();
- assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+ assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
false /* restoreFromDisk */, false /* reducedResolution */));
// Load it from disk
- assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+ assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
true /* restoreFromDisk */, true /* reducedResolution */));
// Make sure it's not in the cache now.
- assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+ assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
false /* restoreFromDisk */, false /* reducedResolution */));
}
@Test
- public void testRestoreFromDisk() throws Exception {
+ public void testRestoreFromDisk() {
final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
- mPersister.persistSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId, createSnapshot());
+ mPersister.persistSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId, createSnapshot());
mPersister.waitForQueueEmpty();
- assertNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+ assertNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
false /* restoreFromDisk */, false /* reducedResolution */));
// Load it from disk
- assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, sWm.mCurrentUserId,
+ assertNotNull(mCache.getSnapshot(window.getTask().mTaskId, mWm.mCurrentUserId,
true /* restoreFromDisk */, false /* reducedResolution */));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index efce063..d2c0765 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -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.wm;
@@ -20,7 +20,8 @@
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.TRANSIT_UNSET;
-import static com.android.server.wm.TaskSnapshotController.*;
+import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_APP_THEME;
+import static com.android.server.wm.TaskSnapshotController.SNAPSHOT_MODE_REAL;
import static junit.framework.Assert.assertEquals;
@@ -28,25 +29,23 @@
import android.util.ArraySet;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.google.android.collect.Sets;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link TaskSnapshotController}.
*
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotControllerTest
+ * Build/Install/Run:
+ * * atest FrameworksServicesTests:TaskSnapshotControllerTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskSnapshotControllerTest extends WindowTestsBase {
@Test
- public void testGetClosingApps_closing() throws Exception {
+ public void testGetClosingApps_closing() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
@@ -54,13 +53,13 @@
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mAppToken);
final ArraySet<Task> closingTasks = new ArraySet<>();
- sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
assertEquals(1, closingTasks.size());
assertEquals(closingWindow.mAppToken.getTask(), closingTasks.valueAt(0));
}
@Test
- public void testGetClosingApps_notClosing() throws Exception {
+ public void testGetClosingApps_notClosing() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
final WindowState openingWindow = createAppWindow(closingWindow.getTask(),
@@ -72,12 +71,12 @@
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mAppToken);
final ArraySet<Task> closingTasks = new ArraySet<>();
- sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
assertEquals(0, closingTasks.size());
}
@Test
- public void testGetClosingApps_skipClosingAppsSnapshotTasks() throws Exception {
+ public void testGetClosingApps_skipClosingAppsSnapshotTasks() {
final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
"closingWindow");
closingWindow.mAppToken.setVisibility(null, false /* visible */, TRANSIT_UNSET,
@@ -85,29 +84,29 @@
final ArraySet<AppWindowToken> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mAppToken);
final ArraySet<Task> closingTasks = new ArraySet<>();
- sWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
+ mWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
Sets.newArraySet(closingWindow.mAppToken.getTask()));
- sWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
assertEquals(0, closingTasks.size());
}
@Test
- public void testGetSnapshotMode() throws Exception {
+ public void testGetSnapshotMode() {
final WindowState disabledWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "disabledWindow");
disabledWindow.mAppToken.setDisablePreviewScreenshots(true);
assertEquals(SNAPSHOT_MODE_APP_THEME,
- sWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
+ mWm.mTaskSnapshotController.getSnapshotMode(disabledWindow.getTask()));
final WindowState normalWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "normalWindow");
assertEquals(SNAPSHOT_MODE_REAL,
- sWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
+ mWm.mTaskSnapshotController.getSnapshotMode(normalWindow.getTask()));
final WindowState secureWindow = createWindow(null,
FIRST_APPLICATION_WINDOW, mDisplayContent, "secureWindow");
secureWindow.mAttrs.flags |= FLAG_SECURE;
assertEquals(SNAPSHOT_MODE_APP_THEME,
- sWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
+ mWm.mTaskSnapshotController.getSnapshotMode(secureWindow.getTask()));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
index 600b2e5..b0eafee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterLoaderTest.java
@@ -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.wm;
@@ -34,23 +34,22 @@
import android.view.View;
import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.io.File;
+import java.util.function.Predicate;
/**
* Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
*
- * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
*/
@MediumTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
@@ -59,9 +58,9 @@
public void testPersistAndLoadSnapshot() {
mPersister.persistSnapshot(1 , mTestUserId, createSnapshot());
mPersister.waitForQueueEmpty();
- final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
+ final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
assertTrueForFiles(files, File::exists, " must exist");
final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* reduced */);
assertNotNull(snapshot);
@@ -70,9 +69,10 @@
assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
}
- private void assertTrueForFiles(File[] files, Predicate<File> predicate, String message) {
+ private static void assertTrueForFiles(File[] files, Predicate<File> predicate,
+ String message) {
for (File file : files) {
- assertTrue(file.getName() + message, predicate.apply(file));
+ assertTrue(file.getName() + message, predicate.test(file));
}
}
@@ -81,9 +81,9 @@
mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
mPersister.onTaskRemovedFromRecents(1, mTestUserId);
mPersister.waitForQueueEmpty();
- assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.proto").exists());
- assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.jpg").exists());
- assertFalse(new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg").exists());
+ assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.proto").exists());
+ assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1.jpg").exists());
+ assertFalse(new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg").exists());
}
/**
@@ -120,12 +120,12 @@
// Make sure 1,2 were purged but removeObsoleteFiles wasn't.
final File[] existsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/3.proto"),
- new File(sFilesDir.getPath() + "/snapshots/4.proto")};
+ new File(FILES_DIR.getPath() + "/snapshots/3.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/4.proto")};
final File[] nonExistsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/100.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1.proto")};
+ new File(FILES_DIR.getPath() + "/snapshots/100.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.proto")};
assertTrueForFiles(existsFiles, File::exists, " must exist");
assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
}
@@ -149,10 +149,10 @@
assertTrue(a.isReducedResolution());
mPersister.persistSnapshot(1 , mTestUserId, a);
mPersister.waitForQueueEmpty();
- final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
+ final File[] files = new File[] { new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg")};
final File[] nonExistsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
};
assertTrueForFiles(files, File::exists, " must exist");
assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
@@ -195,8 +195,8 @@
TaskSnapshot b = new TaskSnapshotBuilder()
.setWindowingMode(WINDOWING_MODE_PINNED)
.build();
- assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
- assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED);
+ assertEquals(WINDOWING_MODE_FULLSCREEN, a.getWindowingMode());
+ assertEquals(WINDOWING_MODE_PINNED, b.getWindowingMode());
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty();
@@ -204,8 +204,8 @@
final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
assertNotNull(snapshotA);
assertNotNull(snapshotB);
- assertTrue(snapshotA.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
- assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED);
+ assertEquals(WINDOWING_MODE_FULLSCREEN, snapshotA.getWindowingMode());
+ assertEquals(WINDOWING_MODE_PINNED, snapshotB.getWindowingMode());
}
@Test
@@ -239,8 +239,8 @@
TaskSnapshot b = new TaskSnapshotBuilder()
.setSystemUiVisibility(lightBarFlags)
.build();
- assertTrue(a.getSystemUiVisibility() == 0);
- assertTrue(b.getSystemUiVisibility() == lightBarFlags);
+ assertEquals(0, a.getSystemUiVisibility());
+ assertEquals(lightBarFlags, b.getSystemUiVisibility());
mPersister.persistSnapshot(1, mTestUserId, a);
mPersister.persistSnapshot(2, mTestUserId, b);
mPersister.waitForQueueEmpty();
@@ -248,8 +248,8 @@
final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
assertNotNull(snapshotA);
assertNotNull(snapshotB);
- assertTrue(snapshotA.getSystemUiVisibility() == 0);
- assertTrue(snapshotB.getSystemUiVisibility() == lightBarFlags);
+ assertEquals(0, snapshotA.getSystemUiVisibility());
+ assertEquals(lightBarFlags, snapshotB.getSystemUiVisibility());
}
@Test
@@ -261,13 +261,13 @@
mPersister.removeObsoleteFiles(taskIds, new int[] { mTestUserId });
mPersister.waitForQueueEmpty();
final File[] existsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/1.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg") };
+ new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg") };
final File[] nonExistsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/2.proto"),
- new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
+ new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
assertTrueForFiles(existsFiles, File::exists, " must exist");
assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
}
@@ -281,24 +281,12 @@
mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
mPersister.waitForQueueEmpty();
final File[] existsFiles = new File[] {
- new File(sFilesDir.getPath() + "/snapshots/1.proto"),
- new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/2.proto"),
- new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
- new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
+ new File(FILES_DIR.getPath() + "/snapshots/1.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/1.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/1_reduced.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/2.proto"),
+ new File(FILES_DIR.getPath() + "/snapshots/2.jpg"),
+ new File(FILES_DIR.getPath() + "/snapshots/2_reduced.jpg")};
assertTrueForFiles(existsFiles, File::exists, " must exist");
}
-
- /**
- * Private predicate definition.
- *
- * This is needed because com.android.internal.util.Predicate is deprecated
- * and can only be used with classes fron android.test.runner. This cannot
- * use java.util.function.Predicate because that is not present on all API
- * versions that this test must run on.
- */
- private interface Predicate<T> {
- boolean apply(T t);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 33b137e..0f9b825 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -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.wm;
@@ -21,6 +21,8 @@
import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
import static android.graphics.GraphicBuffer.USAGE_SW_READ_RARELY;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -31,51 +33,37 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import java.io.File;
-import androidx.test.InstrumentationRegistry;
-
/**
* Base class for tests that use a {@link TaskSnapshotPersister}.
*/
class TaskSnapshotPersisterTestBase extends WindowTestsBase {
private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
+ static final File FILES_DIR = getInstrumentation().getTargetContext().getFilesDir();
TaskSnapshotPersister mPersister;
TaskSnapshotLoader mLoader;
int mTestUserId;
- static File sFilesDir;
- @BeforeClass
- public static void setUpUser() {
- sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
- }
-
- @Override
@Before
- public void setUp() throws Exception {
- super.setUp();
-
- final UserManager um = UserManager.get(InstrumentationRegistry.getContext());
+ public void setUp() {
+ final UserManager um = UserManager.get(getInstrumentation().getTargetContext());
mTestUserId = um.getUserHandle();
- mPersister = new TaskSnapshotPersister(userId -> sFilesDir);
+ mPersister = new TaskSnapshotPersister(userId -> FILES_DIR);
mLoader = new TaskSnapshotLoader(mPersister);
mPersister.start();
}
- @Override
@After
- public void tearDown() throws Exception {
+ public void tearDown() {
cleanDirectory();
-
- super.tearDown();
}
private void cleanDirectory() {
- final File[] files = new File(sFilesDir, "snapshots").listFiles();
+ final File[] files = new File(FILES_DIR, "snapshots").listFiles();
if (files == null) {
return;
}
@@ -99,7 +87,7 @@
/**
* Builds a TaskSnapshot.
*/
- class TaskSnapshotBuilder {
+ static class TaskSnapshotBuilder {
private float mScale = 1f;
private boolean mIsRealSnapshot = true;
@@ -107,32 +95,32 @@
private int mWindowingMode = WINDOWING_MODE_FULLSCREEN;
private int mSystemUiVisibility = 0;
- public TaskSnapshotBuilder setScale(float scale) {
+ TaskSnapshotBuilder setScale(float scale) {
mScale = scale;
return this;
}
- public TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) {
+ TaskSnapshotBuilder setIsRealSnapshot(boolean isRealSnapshot) {
mIsRealSnapshot = isRealSnapshot;
return this;
}
- public TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) {
+ TaskSnapshotBuilder setIsTranslucent(boolean isTranslucent) {
mIsTranslucent = isTranslucent;
return this;
}
- public TaskSnapshotBuilder setWindowingMode(int windowingMode) {
+ TaskSnapshotBuilder setWindowingMode(int windowingMode) {
mWindowingMode = windowingMode;
return this;
}
- public TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) {
+ TaskSnapshotBuilder setSystemUiVisibility(int systemUiVisibility) {
mSystemUiVisibility = systemUiVisibility;
return this;
}
- public TaskSnapshot build() {
+ TaskSnapshot build() {
final GraphicBuffer buffer = GraphicBuffer.create(100, 100, PixelFormat.RGBA_8888,
USAGE_HW_TEXTURE | USAGE_SW_READ_RARELY | USAGE_SW_READ_RARELY);
Canvas c = buffer.lockCanvas();
@@ -142,6 +130,5 @@
mScale < 1f /* reducedResolution */, mScale, mIsRealSnapshot, mWindowingMode,
mSystemUiVisibility, mIsTranslucent);
}
-
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index 91074b9..7c16191 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -39,21 +39,19 @@
import android.view.Surface;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.TaskSnapshotSurface.Window;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link TaskSnapshotSurface}.
*
- * runtest frameworks-services -c com.android.server.wm.TaskSnapshotSurfaceTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:TaskSnapshotSurfaceTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskSnapshotSurfaceTest extends WindowTestsBase {
private TaskSnapshotSurface mSurface;
@@ -65,7 +63,7 @@
final TaskSnapshot snapshot = new TaskSnapshot(buffer,
ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
- mSurface = new TaskSnapshotSurface(sWm, new Window(), new Surface(), snapshot, "Test",
+ mSurface = new TaskSnapshotSurface(mWm, new Window(), new Surface(), snapshot, "Test",
Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
ORIENTATION_PORTRAIT);
}
@@ -76,7 +74,7 @@
}
@Test
- public void fillEmptyBackground_fillHorizontally() throws Exception {
+ public void fillEmptyBackground_fillHorizontally() {
setupSurface(200, 100);
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(200);
@@ -86,7 +84,7 @@
}
@Test
- public void fillEmptyBackground_fillVertically() throws Exception {
+ public void fillEmptyBackground_fillVertically() {
setupSurface(100, 200);
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
@@ -96,7 +94,7 @@
}
@Test
- public void fillEmptyBackground_fillBoth() throws Exception {
+ public void fillEmptyBackground_fillBoth() {
setupSurface(200, 200);
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(200);
@@ -107,7 +105,7 @@
}
@Test
- public void fillEmptyBackground_dontFill_sameSize() throws Exception {
+ public void fillEmptyBackground_dontFill_sameSize() {
setupSurface(100, 100);
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
@@ -117,7 +115,7 @@
}
@Test
- public void fillEmptyBackground_dontFill_bitmapLarger() throws Exception {
+ public void fillEmptyBackground_dontFill_bitmapLarger() {
setupSurface(100, 100);
final Canvas mockCanvas = mock(Canvas.class);
when(mockCanvas.getWidth()).thenReturn(100);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 0e9a63c..f01e9f0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -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.wm;
@@ -27,17 +27,17 @@
import android.platform.test.annotations.Presubmit;
+import androidx.test.filters.SmallTest;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import androidx.test.filters.SmallTest;
-
/**
* Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
+ * atest FrameworksServicesTests:TaskStackContainersTests
*/
@SmallTest
@Presubmit
@@ -45,11 +45,8 @@
private TaskStack mPinnedStack;
- @Override
@Before
public void setUp() throws Exception {
- super.setUp();
-
mPinnedStack = createStackControllerOnStackOnDisplay(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
// Stack should contain visible app window to be considered visible.
@@ -61,12 +58,9 @@
assertTrue(mPinnedStack.isVisible());
}
- @Override
@After
public void tearDown() throws Exception {
mPinnedStack.removeImmediately();
-
- super.tearDown();
}
@Test
@@ -121,14 +115,14 @@
final Task task = createTaskInStack(stack, 0 /* userId */);
// Add another display at top.
- sWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+ mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
false /* includingParents */);
// Move the task of {@code mDisplayContent} to top.
stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
- final int indexOfDisplayWithPinnedStack = sWm.mRoot.mChildren.indexOf(mDisplayContent);
+ final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent);
assertEquals("The testing DisplayContent should be moved to top with task",
- sWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
+ mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index cb5c1cd..7ac3318 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -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.wm;
@@ -25,24 +25,21 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link TaskStack} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.TaskStackTests
+ * atest FrameworksServicesTests:TaskStackTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskStackTests extends WindowTestsBase {
@Test
- public void testStackPositionChildAt() throws Exception {
+ public void testStackPositionChildAt() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
final Task task2 = createTaskInStack(stack, 1 /* userId */);
@@ -59,7 +56,7 @@
}
@Test
- public void testClosingAppDifferentStackOrientation() throws Exception {
+ public void testClosingAppDifferentStackOrientation() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken1 =
@@ -79,7 +76,7 @@
}
@Test
- public void testMoveTaskToBackDifferentStackOrientation() throws Exception {
+ public void testMoveTaskToBackDifferentStackOrientation() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task1 = createTaskInStack(stack, 0 /* userId */);
WindowTestUtils.TestAppWindowToken appWindowToken1 =
@@ -99,7 +96,7 @@
}
@Test
- public void testStackRemoveImmediately() throws Exception {
+ public void testStackRemoveImmediately() {
final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
assertEquals(stack, task.mStack);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index edd7664..1af79e4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -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.wm;
@@ -24,24 +24,21 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link TaskWindowContainerController}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.TaskWindowContainerControllerTests
+ * atest FrameworksServicesTests:TaskWindowContainerControllerTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskWindowContainerControllerTests extends WindowTestsBase {
@Test
- public void testRemoveContainer() throws Exception {
+ public void testRemoveContainer() {
final WindowTestUtils.TestTaskWindowContainerController taskController =
new WindowTestUtils.TestTaskWindowContainerController(this);
final WindowTestUtils.TestAppWindowContainerController appController =
@@ -54,7 +51,7 @@
}
@Test
- public void testRemoveContainer_deferRemoval() throws Exception {
+ public void testRemoveContainer_deferRemoval() {
final WindowTestUtils.TestTaskWindowContainerController taskController =
new WindowTestUtils.TestTaskWindowContainerController(this);
final WindowTestUtils.TestAppWindowContainerController appController =
@@ -79,7 +76,7 @@
}
@Test
- public void testReparent() throws Exception {
+ public void testReparent() {
final StackWindowController stackController1 =
createStackControllerOnDisplay(mDisplayContent);
final WindowTestUtils.TestTaskWindowContainerController taskController =
@@ -116,7 +113,7 @@
}
@Test
- public void testReparent_BetweenDisplays() throws Exception {
+ public void testReparent_BetweenDisplays() {
// Create first stack on primary display.
final StackWindowController stack1Controller =
createStackControllerOnDisplay(mDisplayContent);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
index 353aa7d..e8d0a06 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestIWindow.java
@@ -11,13 +11,11 @@
* 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.wm;
-import com.android.internal.os.IResultReceiver;
-
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -27,87 +25,71 @@
import android.view.DragEvent;
import android.view.IWindow;
+import com.android.internal.os.IResultReceiver;
+
public class TestIWindow extends IWindow.Stub {
@Override
public void executeCommand(String command, String parameters,
- ParcelFileDescriptor descriptor)
- throws RemoteException {
-
+ ParcelFileDescriptor descriptor) throws RemoteException {
}
@Override
public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfig,
Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId,
- DisplayCutout.ParcelableWrapper displayCutout)
- throws RemoteException {
-
+ DisplayCutout.ParcelableWrapper displayCutout) throws RemoteException {
}
@Override
public void moved(int newX, int newY) throws RemoteException {
-
}
@Override
public void dispatchAppVisibility(boolean visible) throws RemoteException {
-
}
@Override
public void dispatchGetNewSurface() throws RemoteException {
-
}
@Override
- public void windowFocusChanged(boolean hasFocus, boolean inTouchMode)
- throws RemoteException {
-
+ public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) throws RemoteException {
}
@Override
public void closeSystemDialogs(String reason) throws RemoteException {
-
}
@Override
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync)
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)
throws RemoteException {
-
}
@Override
public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras,
boolean sync) throws RemoteException {
-
}
@Override
public void dispatchDragEvent(DragEvent event) throws RemoteException {
-
}
@Override
public void updatePointerIcon(float x, float y) throws RemoteException {
-
}
@Override
public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue,
int localChanges) throws RemoteException {
-
}
@Override
public void dispatchWindowShown() throws RemoteException {
-
}
@Override
public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId)
throws RemoteException {
-
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 19abd9e..0165e7d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -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.wm;
@@ -46,8 +46,6 @@
import java.util.function.Supplier;
class TestWindowManagerPolicy implements WindowManagerPolicy {
- private static final String TAG = "TestWindowManagerPolicy";
-
private final Supplier<WindowManagerService> mWmSupplier;
int rotationToReport = 0;
@@ -55,21 +53,18 @@
private Runnable mRunnableWhenAddingSplashScreen;
- public TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
-
+ TestWindowManagerPolicy(Supplier<WindowManagerService> wmSupplier) {
mWmSupplier = wmSupplier;
}
@Override
public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
throws RemoteException {
-
}
@Override
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
-
}
public void setDefaultDisplay(DisplayContentInfo displayContentInfo) {
@@ -93,7 +88,6 @@
@Override
public void adjustConfigurationLw(Configuration config, int keyboardPresence,
int navigationPresence) {
-
}
@Override
@@ -179,7 +173,6 @@
@Override
public void removeWindowLw(WindowState win) {
-
}
@Override
@@ -189,7 +182,6 @@
@Override
public void selectRotationAnimationLw(int[] anim) {
-
}
@Override
@@ -220,14 +212,12 @@
}
@Override
- public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event,
- int policyFlags) {
+ public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
return 0;
}
@Override
- public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event,
- int policyFlags) {
+ public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
return null;
}
@@ -238,12 +228,11 @@
@Override
public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
-
}
@Override
- public void applyPostLayoutPolicyLw(WindowState win,
- WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget) {
+ public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
+ WindowState attached, WindowState imeTarget) {
}
@Override
@@ -257,49 +246,40 @@
}
@Override
- public int focusChangedLw(WindowState lastFocus,
- WindowState newFocus) {
+ public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
return 0;
}
@Override
public void startedWakingUp() {
-
}
@Override
public void finishedWakingUp() {
-
}
@Override
public void startedGoingToSleep(int why) {
-
}
@Override
public void finishedGoingToSleep(int why) {
-
}
@Override
public void screenTurningOn(ScreenOnListener screenOnListener) {
-
}
@Override
public void screenTurnedOn() {
-
}
@Override
public void screenTurningOff(ScreenOffListener screenOffListener) {
-
}
@Override
public void screenTurnedOff() {
-
}
@Override
@@ -314,22 +294,18 @@
@Override
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-
}
@Override
public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered) {
-
}
@Override
public void enableKeyguard(boolean enabled) {
-
}
@Override
public void exitKeyguardSecurely(OnKeyguardExitResult callback) {
-
}
@Override
@@ -382,53 +358,44 @@
}
public void setSafeMode(boolean safeMode) {
-
}
@Override
public void systemReady() {
-
}
@Override
public void systemBooted() {
-
}
@Override
public void showBootMessage(CharSequence msg, boolean always) {
-
}
@Override
public void hideBootMessages() {
-
}
@Override
public void userActivity() {
-
}
@Override
public void enableScreenAfterBoot() {
-
}
@Override
- public boolean performHapticFeedbackLw(WindowState win, int effectId,
- boolean always, String reason) {
+ public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always,
+ String reason) {
return false;
}
@Override
public void keepScreenOnStartedLw() {
-
}
@Override
public void keepScreenOnStoppedLw() {
-
}
@Override
@@ -443,37 +410,30 @@
@Override
public void lockNow(Bundle options) {
-
}
@Override
public void showRecentApps() {
-
}
@Override
public void showGlobalActions() {
-
}
@Override
public void setCurrentUserLw(int newUserId) {
-
}
@Override
public void setSwitchingUser(boolean switching) {
-
}
@Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
-
}
@Override
public void dump(String prefix, PrintWriter writer, String[] args) {
-
}
@Override
@@ -483,13 +443,11 @@
@Override
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
-
}
@Override
public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
DisplayCutout cutout, Rect outInsets) {
-
}
@Override
@@ -506,7 +464,6 @@
@Override
public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
DisplayCutout cutout, Rect outInsets) {
-
}
@Override
@@ -517,7 +474,6 @@
@Override
public void onConfigurationChanged(DisplayContentInfo displayContentInfo) {
-
}
@Override
@@ -528,12 +484,10 @@
@Override
public void setPipVisibilityLw(boolean visible) {
-
}
@Override
public void setRecentsVisibilityLw(boolean visible) {
-
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 54456fb..9e22c0a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -11,52 +11,50 @@
* 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.wm;
import static junit.framework.Assert.assertTrue;
+import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Test class for {@link AppTransition}.
*
- * runtest frameworks-services -c com.android.server.wm.UnknownAppVisibilityControllerTest
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:UnknownAppVisibilityControllerTest
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
@Before
public void setUp() throws Exception {
- super.setUp();
mDisplayContent.mUnknownAppVisibilityController.clear();
}
@Test
- public void testFlow() throws Exception {
+ public void testFlow() {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
// Make sure our handler processed the message.
- Thread.sleep(100);
+ SystemClock.sleep(100);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@Test
- public void testMultiple() throws Exception {
+ public void testMultiple() {
final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token1);
@@ -67,12 +65,12 @@
mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
// Make sure our handler processed the message.
- Thread.sleep(100);
+ SystemClock.sleep(100);
assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@Test
- public void testClear() throws Exception {
+ public void testClear() {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
mDisplayContent.mUnknownAppVisibilityController.clear();;
@@ -80,7 +78,7 @@
}
@Test
- public void testAppRemoved() throws Exception {
+ public void testAppRemoved() {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(token);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
index e3280ca..25e73e3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -13,33 +29,30 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link WallpaperController} class.
*
* Build/Install/Run:
- * atest com.android.server.wm.WallpaperControllerTests
+ * atest FrameworksServicesTests:WallpaperControllerTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class WallpaperControllerTests extends WindowTestsBase {
@Test
public void testWallpaperScreenshot() {
WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class);
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
// No wallpaper
final DisplayContent dc = createNewDisplay();
- Bitmap wallpaperBitmap = sWm.mRoot.mWallpaperController.screenshotWallpaperLocked();
+ Bitmap wallpaperBitmap = mWm.mRoot.mWallpaperController.screenshotWallpaperLocked();
assertNull(wallpaperBitmap);
// No wallpaper WSA Surface
- WindowToken wallpaperWindowToken = new WallpaperWindowToken(sWm, mock(IBinder.class),
+ WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
true, dc, true /* ownerCanManageAppTokens */);
WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
wallpaperWindowToken, "wallpaperWindow");
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index e7cc285..4369c96 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -36,26 +36,24 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
/**
* Test class to for {@link android.app.WindowConfiguration}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.WindowConfigurationTests
+ * atest FrameworksServicesTests:WindowConfigurationTests
*/
-@SmallTest
@FlakyTest(bugId = 74078662)
+@SmallTest
@Presubmit
-@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowConfigurationTests extends WindowTestsBase {
private Rect mParentBounds;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
}
@@ -95,7 +93,7 @@
/** Tests {@link android.app.WindowConfiguration#compareTo(WindowConfiguration)}. */
@Test
- public void testConfigurationCompareTo() throws Exception {
+ public void testConfigurationCompareTo() {
final Configuration blankConfig = new Configuration();
final WindowConfiguration blankWinConfig = new WindowConfiguration();
@@ -135,7 +133,7 @@
}
@Test
- public void testSetActivityType() throws Exception {
+ public void testSetActivityType() {
final WindowConfiguration config = new WindowConfiguration();
config.setActivityType(ACTIVITY_TYPE_HOME);
assertEquals(ACTIVITY_TYPE_HOME, config.getActivityType());
@@ -147,12 +145,12 @@
/** Ensures the configuration app bounds at the root level match the app dimensions. */
@Test
- public void testAppBounds_RootConfigurationBounds() throws Exception {
+ public void testAppBounds_RootConfigurationBounds() {
final DisplayInfo info = mDisplayContent.getDisplayInfo();
info.appWidth = 1024;
info.appHeight = 768;
- final Rect appBounds = sWm.computeNewConfiguration(
+ final Rect appBounds = mWm.computeNewConfiguration(
mDisplayContent.getDisplayId()).windowConfiguration.getAppBounds();
// The bounds should always be positioned in the top left.
assertEquals(appBounds.left, 0);
@@ -165,7 +163,7 @@
/** Ensures that bounds are clipped to their parent. */
@Test
- public void testAppBounds_BoundsClipping() throws Exception {
+ public void testAppBounds_BoundsClipping() {
final Rect shiftedBounds = new Rect(mParentBounds);
shiftedBounds.offset(10, 10);
final Rect expectedBounds = new Rect(mParentBounds);
@@ -176,7 +174,7 @@
/** Ensures that empty bounds are not propagated to the configuration. */
@Test
- public void testAppBounds_EmptyBounds() throws Exception {
+ public void testAppBounds_EmptyBounds() {
final Rect emptyBounds = new Rect();
testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
null /*ExpectedBounds*/);
@@ -184,7 +182,7 @@
/** Ensures that bounds on freeform stacks are not clipped. */
@Test
- public void testAppBounds_FreeFormBounds() throws Exception {
+ public void testAppBounds_FreeFormBounds() {
final Rect freeFormBounds = new Rect(mParentBounds);
freeFormBounds.offset(10, 10);
testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
@@ -193,7 +191,7 @@
/** Ensures that fully contained bounds are not clipped. */
@Test
- public void testAppBounds_ContainedBounds() throws Exception {
+ public void testAppBounds_ContainedBounds() {
final Rect insetBounds = new Rect(mParentBounds);
insetBounds.inset(5, 5, 5, 5);
testStackBoundsConfiguration(
@@ -202,7 +200,7 @@
/** Ensures that full screen free form bounds are clipped */
@Test
- public void testAppBounds_FullScreenFreeFormBounds() throws Exception {
+ public void testAppBounds_FullScreenFreeFormBounds() {
final Rect fullScreenBounds = new Rect(0, 0, mDisplayInfo.logicalWidth,
mDisplayInfo.logicalHeight);
testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, fullScreenBounds,
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
index 6b1feb8..7592f1c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -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.wm;
@@ -28,7 +28,6 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
@@ -36,18 +35,17 @@
* Test class for {@link WindowContainerController}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.WindowContainerControllerTests
+ * atest FrameworksServicesTests:WindowContainerControllerTests
*/
+@FlakyTest(bugId = 74078662)
@SmallTest
@Presubmit
-@FlakyTest(bugId = 74078662)
-@org.junit.runner.RunWith(AndroidJUnit4.class)
public class WindowContainerControllerTests extends WindowTestsBase {
@Test
- public void testCreation() throws Exception {
- final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer(sWm);
+ public void testCreation() {
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+ final WindowContainer container = new WindowContainer(mWm);
container.setController(controller);
assertEquals(controller, container.getController());
@@ -55,9 +53,9 @@
}
@Test
- public void testSetContainer() throws Exception {
- final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer(sWm);
+ public void testSetContainer() {
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+ final WindowContainer container = new WindowContainer(mWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
@@ -65,7 +63,7 @@
// Assert we can't change the container to another one once set
boolean gotException = false;
try {
- controller.setContainer(new WindowContainer(sWm));
+ controller.setContainer(new WindowContainer(mWm));
} catch (IllegalArgumentException e) {
gotException = true;
}
@@ -77,9 +75,9 @@
}
@Test
- public void testRemoveContainer() throws Exception {
- final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer(sWm);
+ public void testRemoveContainer() {
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+ final WindowContainer container = new WindowContainer(mWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
@@ -89,9 +87,9 @@
}
@Test
- public void testOnOverrideConfigurationChanged() throws Exception {
- final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer(sWm);
+ public void testOnOverrideConfigurationChanged() {
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+ final WindowContainer container = new WindowContainer(mWm);
controller.setContainer(container);
assertEquals(controller.mContainer, container);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index dc763b9..e59afd6 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -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.wm;
@@ -46,10 +46,8 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.Comparator;
@@ -57,24 +55,23 @@
* Test class for {@link WindowContainer}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.WindowContainerTests
+ * atest FrameworksServicesTests:WindowContainerTests
*/
@SmallTest
@Presubmit
@FlakyTest(bugId = 74078662)
-@RunWith(AndroidJUnit4.class)
public class WindowContainerTests extends WindowTestsBase {
@Test
- public void testCreation() throws Exception {
- final TestWindowContainer w = new TestWindowContainerBuilder().setLayer(0).build();
+ public void testCreation() {
+ final TestWindowContainer w = new TestWindowContainerBuilder(mWm).setLayer(0).build();
assertNull("window must have no parent", w.getParentWindow());
assertEquals("window must have no children", 0, w.getChildrenCount());
}
@Test
- public void testAdd() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testAdd() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer layer1 = root.addChildWindow(builder.setLayer(1));
@@ -113,23 +110,24 @@
}
@Test
- public void testAddChildSetsSurfacePosition() throws Exception {
- MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer();
+ public void testAddChildSetsSurfacePosition() {
+ try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
- final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
- sWm.mTransactionFactory = () -> transaction;
+ final SurfaceControl.Transaction transaction = mock(SurfaceControl.Transaction.class);
+ mWm.mTransactionFactory = () -> transaction;
- WindowContainer child = new WindowContainer(sWm);
- child.setBounds(1, 1, 10, 10);
+ WindowContainer child = new WindowContainer(mWm);
+ child.setBounds(1, 1, 10, 10);
- verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
- top.addChild(child, 0);
- verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+ verify(transaction, never()).setPosition(any(), anyFloat(), anyFloat());
+ top.addChild(child, 0);
+ verify(transaction, times(1)).setPosition(any(), eq(1.f), eq(1.f));
+ }
}
@Test
- public void testAdd_AlreadyHasParent() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testAdd_AlreadyHasParent() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -153,8 +151,8 @@
}
@Test
- public void testHasChild() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testHasChild() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -183,8 +181,8 @@
}
@Test
- public void testRemoveImmediately() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testRemoveImmediately() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -218,9 +216,9 @@
}
@Test
- public void testRemoveImmediately_WithController() throws Exception {
- final WindowContainer container = new WindowContainer(sWm);
- final WindowContainerController controller = new WindowContainerController(null, sWm);
+ public void testRemoveImmediately_WithController() {
+ final WindowContainer container = new WindowContainer(mWm);
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
container.setController(controller);
assertEquals(controller, container.getController());
@@ -232,9 +230,9 @@
}
@Test
- public void testSetController() throws Exception {
- final WindowContainerController controller = new WindowContainerController(null, sWm);
- final WindowContainer container = new WindowContainer(sWm);
+ public void testSetController() {
+ final WindowContainerController controller = new WindowContainerController<>(null, mWm);
+ final WindowContainer container = new WindowContainer(mWm);
container.setController(controller);
assertEquals(controller, container.getController());
@@ -243,7 +241,7 @@
// Assert we can't change the controller to another one once set
boolean gotException = false;
try {
- container.setController(new WindowContainerController(null, sWm));
+ container.setController(new WindowContainerController<>(null, mWm));
} catch (IllegalArgumentException e) {
gotException = true;
}
@@ -256,8 +254,8 @@
}
@Test
- public void testAddChildByIndex() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testAddChildByIndex() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child = root.addChildWindow();
@@ -283,8 +281,8 @@
}
@Test
- public void testPositionChildAt() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPositionChildAt() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -307,8 +305,8 @@
}
@Test
- public void testPositionChildAtIncludeParents() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPositionChildAtIncludeParents() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -349,12 +347,11 @@
}
@Test
- public void testPositionChildAtInvalid() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPositionChildAtInvalid() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
- final TestWindowContainer child2 = root.addChildWindow();
boolean gotException = false;
try {
@@ -376,8 +373,8 @@
}
@Test
- public void testIsAnimating() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testIsAnimating() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow(builder.setIsAnimating(true));
@@ -402,8 +399,8 @@
}
@Test
- public void testIsVisible() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testIsVisible() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow(builder.setIsVisible(true));
@@ -422,7 +419,7 @@
@Test
public void testOverrideConfigurationAncestorNotification() {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer grandparent = builder.setLayer(0).build();
final TestWindowContainer parent = grandparent.addChildWindow();
@@ -433,8 +430,8 @@
}
@Test
- public void testRemoveChild() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testRemoveChild() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
final TestWindowContainer child2 = root.addChildWindow();
@@ -460,7 +457,7 @@
}
@Test
- public void testGetOrientation_childSpecified() throws Exception {
+ public void testGetOrientation_childSpecified() {
testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_LANDSCAPE,
SCREEN_ORIENTATION_LANDSCAPE);
testGetOrientation_childSpecifiedConfig(false, SCREEN_ORIENTATION_UNSET,
@@ -469,7 +466,7 @@
private void testGetOrientation_childSpecifiedConfig(boolean childVisible, int childOrientation,
int expectedOrientation) {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
root.setFillsParent(true);
@@ -486,16 +483,16 @@
}
@Test
- public void testGetOrientation_Unset() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testGetOrientation_Unset() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
// Unspecified well because we didn't specify anything...
assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, root.getOrientation());
}
@Test
- public void testGetOrientation_InvisibleParentUnsetVisibleChildren() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testGetOrientation_InvisibleParentUnsetVisibleChildren() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
builder.setIsVisible(false).setLayer(-1);
@@ -516,12 +513,11 @@
visibleUnset.setOrientation(SCREEN_ORIENTATION_UNSET);
assertEquals(SCREEN_ORIENTATION_UNSET, visibleUnset.getOrientation());
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, root.getOrientation());
-
}
@Test
- public void testGetOrientation_setBehind() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testGetOrientation_setBehind() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
builder.setIsVisible(true).setLayer(-1);
@@ -541,8 +537,8 @@
}
@Test
- public void testGetOrientation_fillsParent() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testGetOrientation_fillsParent() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).setIsVisible(true).build();
builder.setIsVisible(true).setLayer(-1);
@@ -577,8 +573,8 @@
}
@Test
- public void testCompareTo() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testCompareTo() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.setLayer(0).build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -588,8 +584,6 @@
final TestWindowContainer child2 = root.addChildWindow();
final TestWindowContainer child21 = child2.addChildWindow();
final TestWindowContainer child22 = child2.addChildWindow();
- final TestWindowContainer child23 = child2.addChildWindow();
- final TestWindowContainer child221 = child22.addChildWindow();
final TestWindowContainer child222 = child22.addChildWindow();
final TestWindowContainer child223 = child22.addChildWindow();
final TestWindowContainer child2221 = child222.addChildWindow();
@@ -620,8 +614,8 @@
}
@Test
- public void testPrefixOrderIndex() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPrefixOrderIndex() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -654,8 +648,8 @@
}
@Test
- public void testPrefixOrder_addEntireSubtree() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPrefixOrder_addEntireSubtree() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.build();
final TestWindowContainer subtree = builder.build();
final TestWindowContainer subtree2 = builder.build();
@@ -677,8 +671,8 @@
}
@Test
- public void testPrefixOrder_remove() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testPrefixOrder_remove() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.build();
final TestWindowContainer child1 = root.addChildWindow();
@@ -705,8 +699,8 @@
* is invoked with overridden bounds.
*/
@Test
- public void testOnParentResizePropagation() throws Exception {
- final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+ public void testOnParentResizePropagation() {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
final TestWindowContainer root = builder.build();
final TestWindowContainer child = root.addChildWindow();
@@ -731,7 +725,7 @@
}
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
- private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
+ private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
private boolean mIsAnimating;
private boolean mIsVisible;
@@ -745,7 +739,7 @@
* Compares 2 window layers and returns -1 if the first is lesser than the second in terms
* of z-order and 1 otherwise.
*/
- private final Comparator<TestWindowContainer> mWindowSubLayerComparator = (w1, w2) -> {
+ private static final Comparator<TestWindowContainer> SUBLAYER_COMPARATOR = (w1, w2) -> {
final int layer1 = w1.mLayer;
final int layer2 = w2.mLayer;
if (layer1 < layer2 || (layer1 == layer2 && layer2 < 0 )) {
@@ -753,12 +747,14 @@
// the negative one should go below others; the positive one should go above others.
return -1;
}
+ if (layer1 == layer2) return 0;
return 1;
};
- TestWindowContainer(int layer, boolean isAnimating, boolean isVisible,
- Integer orientation) {
- super(sWm);
+ TestWindowContainer(WindowManagerService wm, int layer, boolean isAnimating,
+ boolean isVisible, Integer orientation) {
+ super(wm);
+
mLayer = layer;
mIsAnimating = isAnimating;
mIsVisible = isVisible;
@@ -775,18 +771,18 @@
}
TestWindowContainer addChildWindow(TestWindowContainer child) {
- addChild(child, mWindowSubLayerComparator);
+ addChild(child, SUBLAYER_COMPARATOR);
return child;
}
TestWindowContainer addChildWindow(TestWindowContainerBuilder childBuilder) {
TestWindowContainer child = childBuilder.build();
- addChild(child, mWindowSubLayerComparator);
+ addChild(child, SUBLAYER_COMPARATOR);
return child;
}
TestWindowContainer addChildWindow() {
- return addChildWindow(new TestWindowContainerBuilder().setLayer(1));
+ return addChildWindow(new TestWindowContainerBuilder(mService).setLayer(1));
}
@Override
@@ -830,14 +826,19 @@
}
}
- private class TestWindowContainerBuilder {
+ private static class TestWindowContainerBuilder {
+ private final WindowManagerService mWm;
private int mLayer;
private boolean mIsAnimating;
private boolean mIsVisible;
private Integer mOrientation;
- public TestWindowContainerBuilder() {
- reset();
+ TestWindowContainerBuilder(WindowManagerService wm) {
+ mWm = wm;
+ mLayer = 0;
+ mIsAnimating = false;
+ mIsVisible = false;
+ mOrientation = null;
}
TestWindowContainerBuilder setLayer(int layer) {
@@ -860,27 +861,20 @@
return this;
}
- TestWindowContainerBuilder reset() {
- mLayer = 0;
- mIsAnimating = false;
- mIsVisible = false;
- mOrientation = null;
- return this;
- }
-
TestWindowContainer build() {
- return new TestWindowContainer(mLayer, mIsAnimating, mIsVisible, mOrientation);
+ return new TestWindowContainer(mWm, mLayer, mIsAnimating, mIsVisible, mOrientation);
}
}
- private class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer> {
- final SurfaceSession mSession = new SurfaceSession();
+ private static class MockSurfaceBuildingContainer extends WindowContainer<WindowContainer>
+ implements AutoCloseable {
+ private final SurfaceSession mSession = new SurfaceSession();
- MockSurfaceBuildingContainer() {
- super(sWm);
+ MockSurfaceBuildingContainer(WindowManagerService wm) {
+ super(wm);
}
- class MockSurfaceBuilder extends SurfaceControl.Builder {
+ static class MockSurfaceBuilder extends SurfaceControl.Builder {
MockSurfaceBuilder(SurfaceSession ss) {
super(ss);
}
@@ -895,5 +889,10 @@
SurfaceControl.Builder makeChildSurface(WindowContainer child) {
return new MockSurfaceBuilder(mSession);
}
+
+ @Override
+ public void close() {
+ mSession.kill();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
index ffc8622..2b8b934 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTraversalTests.java
@@ -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.wm;
@@ -28,23 +28,23 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.function.Consumer;
/**
* Tests for {@link WindowContainer#forAllWindows} and various implementations.
+ *
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:WindowContainerTraversalTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class WindowContainerTraversalTests extends WindowTestsBase {
@Test
- public void testDockedDividerPosition() throws Exception {
+ public void testDockedDividerPosition() {
final WindowState splitScreenWindow = createWindowOnStack(null,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
mDisplayContent, "splitScreenWindow");
@@ -52,7 +52,7 @@
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
- sWm.mInputMethodTarget = splitScreenWindow;
+ mWm.mInputMethodTarget = splitScreenWindow;
Consumer<WindowState> c = mock(Consumer.class);
mDisplayContent.forAllWindows(c, false);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 7cd1314..b0c8d8b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -11,14 +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.wm;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
-import static android.view.WindowManager.LayoutParams.FILL_PARENT;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static org.junit.Assert.assertEquals;
@@ -33,33 +33,32 @@
import android.view.WindowManager;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
*
- * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:WindowFrameTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class WindowFrameTests extends WindowTestsBase {
private WindowToken mWindowToken;
private final IWindow mIWindow = new TestIWindow();
private final Rect mEmptyRect = new Rect();
- class WindowStateWithTask extends WindowState {
+ static class WindowStateWithTask extends WindowState {
final Task mTask;
boolean mDockedResizingForTest = false;
- WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
- super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0,
+ WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
+ WindowManager.LayoutParams attrs, Task t) {
+ super(wm, null, iWindow, windowToken, null, 0, 0, attrs, 0, 0,
false /* ownerCanAddInternalSystemWindow */);
mTask = t;
}
@@ -73,14 +72,15 @@
boolean isDockedResizing() {
return mDockedResizingForTest;
}
- };
+ }
- class TaskWithBounds extends Task {
+ private static class TaskWithBounds extends Task {
final Rect mBounds;
final Rect mInsetBounds = new Rect();
boolean mFullscreenForTest = true;
- TaskWithBounds(Rect bounds) {
- super(0, mStubStack, 0, sWm, 0, false, new TaskDescription(), null);
+
+ TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) {
+ super(0, stack, 0, wm, 0, false, new TaskDescription(), null);
mBounds = bounds;
setBounds(bounds);
}
@@ -113,14 +113,12 @@
@Before
public void setUp() throws Exception {
- super.setUp();
-
// Just any non zero value.
- sWm.mSystemDecorLayer = 10000;
+ mWm.mSystemDecorLayer = 10000;
mWindowToken = WindowTestUtils.createTestAppWindowToken(
- sWm.getDefaultDisplayContentLocked());
- mStubStack = new TaskStack(sWm, 0, null);
+ mWm.getDefaultDisplayContentLocked());
+ mStubStack = new TaskStack(mWm, 0, null);
}
// Do not use this function directly in the tests below. Instead, use more explicit function
@@ -170,9 +168,10 @@
}
@Test
- public void testLayoutInFullscreenTaskInsets() throws Exception {
- Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ public void testLayoutInFullscreenTaskInsets() {
+ // fullscreen task doesn't use bounds for computeFrame
+ final Task task = new TaskWithBounds(mStubStack, mWm, null);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final int bottomContentInset = 100;
@@ -227,9 +226,10 @@
}
@Test
- public void testLayoutInFullscreenTaskNoInsets() throws Exception {
- Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ public void testLayoutInFullscreenTaskNoInsets() {
+ // fullscreen task doesn't use bounds for computeFrame
+ final Task task = new TaskWithBounds(mStubStack, mWm, null);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
// With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -307,7 +307,7 @@
@Test
public void testLayoutNonfullscreenTask() {
- final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo();
+ final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
final int logicalWidth = displayInfo.logicalWidth;
final int logicalHeight = displayInfo.logicalHeight;
@@ -316,9 +316,9 @@
final int taskRight = logicalWidth / 4 * 3;
final int taskBottom = logicalHeight / 4 * 3;
final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
- TaskWithBounds task = new TaskWithBounds(taskBounds);
+ final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
task.mFullscreenForTest = false;
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -367,7 +367,7 @@
@Test
public void testCalculatePolicyCrop() {
final WindowStateWithTask w = createWindow(
- new TaskWithBounds(null), FILL_PARENT, FILL_PARENT);
+ new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -423,7 +423,7 @@
@Test
public void testLayoutLetterboxedWindow() {
// First verify task behavior in multi-window mode.
- final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo();
+ final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
final int logicalWidth = displayInfo.logicalWidth;
final int logicalHeight = displayInfo.logicalHeight;
@@ -432,10 +432,10 @@
final int taskRight = logicalWidth / 4 * 3;
final int taskBottom = logicalHeight / 4 * 3;
final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
- TaskWithBounds task = new TaskWithBounds(taskBounds);
+ final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
task.mInsetBounds.set(taskLeft, taskTop, taskRight, taskBottom);
task.mFullscreenForTest = false;
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -467,8 +467,8 @@
@Test
public void testDisplayCutout() {
// Regular fullscreen task and window
- Task task = new TaskWithBounds(null);
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ final Task task = new TaskWithBounds(mStubStack, mWm, null);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -491,10 +491,11 @@
@Test
public void testDisplayCutout_tempInsetBounds() {
// Regular fullscreen task and window
- TaskWithBounds task = new TaskWithBounds(new Rect(0, -500, 1000, 1500));
+ final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm,
+ new Rect(0, -500, 1000, 1500));
task.mFullscreenForTest = false;
task.mInsetBounds.set(0, 0, 1000, 2000);
- WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
+ WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
final Rect pf = new Rect(0, -500, 1000, 1500);
@@ -519,7 +520,6 @@
attrs.width = width;
attrs.height = height;
- return new WindowStateWithTask(attrs, task);
+ return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task);
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 012c4be..4e75ec9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -19,6 +19,8 @@
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
import static android.view.Display.DEFAULT_DISPLAY;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static org.mockito.ArgumentMatchers.any;
@@ -51,8 +53,6 @@
import java.util.ArrayList;
import java.util.List;
-import androidx.test.InstrumentationRegistry;
-
/**
* A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
* to properly tear it down after.
@@ -89,7 +89,7 @@
}
private void setUp() {
- final Context context = InstrumentationRegistry.getTargetContext();
+ final Context context = getInstrumentation().getTargetContext();
removeServices();
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
index 570a853..343d359 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRuleTest.java
@@ -22,13 +22,14 @@
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
-@RunWith(AndroidJUnit4.class)
+/**
+ * Build/InstallRun:
+ * atest FrameworksServicesTests:WindowManagerServiceRuleTest
+ */
@Presubmit
@SmallTest
public class WindowManagerServiceRuleTest {
@@ -40,4 +41,4 @@
public void testWindowManagerSetUp() {
assertThat(mRule.getWindowManagerService(), notNullValue());
}
-}
\ No newline at end of file
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 3637baf..118ce89 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -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.wm;
@@ -58,32 +58,28 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
import com.android.server.wm.utils.WmDisplayCutout;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import java.util.Arrays;
import java.util.LinkedList;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
/**
* Tests for the {@link WindowState} class.
*
- * atest FrameworksServicesTests:com.android.server.wm.WindowStateTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:WindowStateTests
*/
-@SmallTest
@FlakyTest(bugId = 74078662)
-// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
public class WindowStateTests extends WindowTestsBase {
@Test
- public void testIsParentWindowHidden() throws Exception {
+ public void testIsParentWindowHidden() {
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -98,11 +94,10 @@
assertFalse(parentWindow.isParentWindowHidden());
assertFalse(child1.isParentWindowHidden());
assertFalse(child2.isParentWindowHidden());
-
}
@Test
- public void testIsChildWindow() throws Exception {
+ public void testIsChildWindow() {
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -115,7 +110,7 @@
}
@Test
- public void testHasChild() throws Exception {
+ public void testHasChild() {
final WindowState win1 = createWindow(null, TYPE_APPLICATION, "win1");
final WindowState win11 = createWindow(win1, FIRST_SUB_WINDOW, "win11");
final WindowState win12 = createWindow(win1, FIRST_SUB_WINDOW, "win12");
@@ -136,7 +131,7 @@
}
@Test
- public void testGetParentWindow() throws Exception {
+ public void testGetParentWindow() {
final WindowState parentWindow = createWindow(null, TYPE_APPLICATION, "parentWindow");
final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
@@ -157,7 +152,7 @@
}
@Test
- public void testGetTopParentWindow() throws Exception {
+ public void testGetTopParentWindow() {
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
@@ -183,7 +178,7 @@
}
@Test
- public void testCanBeImeTarget() throws Exception {
+ public void testCanBeImeTarget() {
final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
@@ -219,7 +214,7 @@
}
@Test
- public void testGetWindow() throws Exception {
+ public void testGetWindow() {
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
final WindowState mediaChild = createWindow(root, TYPE_APPLICATION_MEDIA, "mediaChild");
final WindowState mediaOverlayChild = createWindow(root,
@@ -231,7 +226,7 @@
final WindowState aboveSubPanelChild = createWindow(root,
TYPE_APPLICATION_ABOVE_SUB_PANEL, "aboveSubPanelChild");
- final LinkedList<WindowState> windows = new LinkedList();
+ final LinkedList<WindowState> windows = new LinkedList<>();
root.getWindow(w -> {
windows.addLast(w);
@@ -249,7 +244,7 @@
}
@Test
- public void testPrepareWindowToDisplayDuringRelayout() throws Exception {
+ public void testPrepareWindowToDisplayDuringRelayout() {
testPrepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
testPrepareWindowToDisplayDuringRelayout(true /*wasVisible*/);
@@ -262,14 +257,14 @@
final WindowState second = createWindow(null, TYPE_APPLICATION, appWindowToken, "second");
second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
assertTrue(appWindowToken.canTurnScreenOn());
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
assertFalse(appWindowToken.canTurnScreenOn());
// Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON
@@ -278,14 +273,14 @@
first.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
second.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
assertFalse(appWindowToken.canTurnScreenOn());
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
assertFalse(appWindowToken.canTurnScreenOn());
// Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
@@ -299,17 +294,17 @@
firstWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
secondWindow.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
- verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
}
@Test
- public void testCanAffectSystemUiFlags() throws Exception {
+ public void testCanAffectSystemUiFlags() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mToken.setHidden(false);
assertTrue(app.canAffectSystemUiFlags());
@@ -318,11 +313,10 @@
app.mToken.setHidden(false);
app.mAttrs.alpha = 0.0f;
assertFalse(app.canAffectSystemUiFlags());
-
}
@Test
- public void testCanAffectSystemUiFlags_disallow() throws Exception {
+ public void testCanAffectSystemUiFlags_disallow() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mToken.setHidden(false);
assertTrue(app.canAffectSystemUiFlags());
@@ -331,7 +325,7 @@
}
@Test
- public void testIsSelfOrAncestorWindowAnimating() throws Exception {
+ public void testIsSelfOrAncestorWindowAnimating() {
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
final WindowState child1 = createWindow(root, FIRST_SUB_WINDOW, "child1");
final WindowState child2 = createWindow(child1, FIRST_SUB_WINDOW, "child2");
@@ -344,7 +338,7 @@
}
@Test
- public void testLayoutSeqResetOnReparent() throws Exception {
+ public void testLayoutSeqResetOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
app.mLayoutSeq = 1;
mDisplayContent.mLayoutSeq = 1;
@@ -355,7 +349,7 @@
}
@Test
- public void testDisplayIdUpdatedOnReparent() throws Exception {
+ public void testDisplayIdUpdatedOnReparent() {
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
// fake a different display
app.mInputWindowHandle.displayId = mDisplayContent.getDisplayId() + 1;
@@ -418,11 +412,11 @@
}
private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
- reset(mPowerManagerWrapper);
+ reset(sPowerManagerWrapper);
final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
- verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
+ verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index e155be4..9e12f02 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -11,11 +11,26 @@
* 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.wm;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -26,24 +41,9 @@
import android.view.IApplicationToken;
import android.view.IWindow;
import android.view.Surface;
-import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
-import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
-import static com.android.server.wm.WindowContainer.POSITION_TOP;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyFloat;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import org.mockito.invocation.InvocationOnMock;
/**
@@ -277,35 +277,33 @@
*/
public static class TestTaskWindowContainerController extends TaskWindowContainerController {
+ static final TaskWindowContainerListener NOP_LISTENER = new TaskWindowContainerListener() {
+ @Override
+ public void registerConfigurationChangeListener(
+ ConfigurationContainerListener listener) {
+ }
+
+ @Override
+ public void unregisterConfigurationChangeListener(
+ ConfigurationContainerListener listener) {
+ }
+
+ @Override
+ public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
+ }
+
+ @Override
+ public void requestResize(Rect bounds, int resizeMode) {
+ }
+ };
+
TestTaskWindowContainerController(WindowTestsBase testsBase) {
this(testsBase.createStackControllerOnDisplay(testsBase.mDisplayContent));
}
TestTaskWindowContainerController(StackWindowController stackController) {
- super(sNextTaskId++, new TaskWindowContainerListener() {
- @Override
- public void registerConfigurationChangeListener(
- ConfigurationContainerListener listener) {
-
- }
-
- @Override
- public void unregisterConfigurationChangeListener(
- ConfigurationContainerListener listener) {
-
- }
-
- @Override
- public void onSnapshotChanged(ActivityManager.TaskSnapshot snapshot) {
-
- }
-
- @Override
- public void requestResize(Rect bounds, int resizeMode) {
-
- }
- }, stackController, 0 /* userId */, null /* bounds */, RESIZE_MODE_UNRESIZEABLE,
- false /* supportsPictureInPicture */, true /* toTop*/,
+ super(sNextTaskId++, NOP_LISTENER, stackController, 0 /* userId */, null /* bounds */,
+ RESIZE_MODE_UNRESIZEABLE, false /* supportsPictureInPicture */, true /* toTop*/,
true /* showForAllUsers */, new ActivityManager.TaskDescription(),
stackController.mService);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 73bb1c9..945cbb9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -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.wm;
@@ -35,6 +35,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static org.mockito.Mockito.mock;
import android.content.Context;
@@ -52,13 +54,12 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Rule;
import java.util.HashSet;
import java.util.LinkedList;
-import androidx.test.InstrumentationRegistry;
-
/**
* Common base class for window manager unit test classes.
*
@@ -66,7 +67,8 @@
*/
class WindowTestsBase {
private static final String TAG = WindowTestsBase.class.getSimpleName();
- WindowManagerService sWm = null; // TODO(roosa): rename to mWm in follow-up CL
+
+ WindowManagerService mWm;
private final IWindow mIWindow = new TestIWindow();
private Session mMockSession;
// The default display is removed in {@link #setUp} and then we iterate over all displays to
@@ -97,32 +99,36 @@
@Rule
public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
- static WindowState.PowerManagerWrapper mPowerManagerWrapper; // TODO(roosa): make non-static.
+ static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static.
+
+ @BeforeClass
+ public static void setUpOnceBase() {
+ AttributeCache.init(getInstrumentation().getTargetContext());
+ sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
+ }
@Before
- public void setUp() throws Exception {
+ public void setUpBase() {
// If @Before throws an exception, the error isn't logged. This will make sure any failures
// in the set up are clear. This can be removed when b/37850063 is fixed.
try {
mMockSession = mock(Session.class);
- mPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
- final Context context = InstrumentationRegistry.getTargetContext();
- AttributeCache.init(context);
+ final Context context = getInstrumentation().getTargetContext();
- sWm = mWmRule.getWindowManagerService();
+ mWm = mWmRule.getWindowManagerService();
beforeCreateDisplay();
- mWallpaperController = new WallpaperController(sWm);
+ mWallpaperController = new WallpaperController(mWm);
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
- sWm.mDisplayEnabled = true;
- sWm.mDisplayReady = true;
+ mWm.mDisplayEnabled = true;
+ mWm.mDisplayReady = true;
// Set-up some common windows.
- mCommonWindows = new HashSet();
- synchronized (sWm.mGlobalLock) {
+ mCommonWindows = new HashSet<>();
+ synchronized (mWm.mGlobalLock) {
mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
mDisplayContent.mInputMethodWindow = mImeWindow;
@@ -154,7 +160,7 @@
}
@After
- public void tearDown() throws Exception {
+ public void tearDownBase() {
// If @After throws an exception, the error isn't logged. This will make sure any failures
// in the tear down are clear. This can be removed when b/37850063 is fixed.
try {
@@ -164,8 +170,8 @@
final LinkedList<WindowState> nonCommonWindows = new LinkedList<>();
- synchronized (sWm.mGlobalLock) {
- sWm.mRoot.forAllWindows(w -> {
+ synchronized (mWm.mGlobalLock) {
+ mWm.mRoot.forAllWindows(w -> {
if (!mCommonWindows.contains(w)) {
nonCommonWindows.addLast(w);
}
@@ -175,18 +181,18 @@
nonCommonWindows.pollLast().removeImmediately();
}
- for (int i = sWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
- final DisplayContent displayContent = sWm.mRoot.mChildren.get(i);
+ for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent displayContent = mWm.mRoot.mChildren.get(i);
if (!displayContent.isDefaultDisplay) {
displayContent.removeImmediately();
}
}
// Remove app transition & window freeze timeout callbacks to prevent unnecessary
// actions after test.
- sWm.getDefaultDisplayContentLocked().mAppTransition
+ mWm.getDefaultDisplayContentLocked().mAppTransition
.removeAppTransitionTimeoutCallbacks();
- sWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
- sWm.mInputMethodTarget = null;
+ mWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
+ mWm.mInputMethodTarget = null;
}
// Wait until everything is really cleaned up.
@@ -198,7 +204,7 @@
}
private WindowState createCommonWindow(WindowState parent, int type, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final WindowState win = createWindow(parent, type, name);
mCommonWindows.add(win);
// Prevent common windows from been IMe targets
@@ -216,7 +222,7 @@
private WindowToken createWindowToken(
DisplayContent dc, int windowingMode, int activityType, int type) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) {
return WindowTestUtils.createTestWindowToken(type, dc);
}
@@ -241,7 +247,7 @@
}
WindowState createWindow(WindowState parent, int type, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
return (parent == null)
? createWindow(parent, type, mDisplayContent, name)
: createWindow(parent, type, parent.mToken, name);
@@ -250,14 +256,14 @@
WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType,
int type, DisplayContent dc, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final WindowToken token = createWindowToken(dc, windowingMode, activityType, type);
return createWindow(parent, type, token, name);
}
}
WindowState createAppWindow(Task task, int type, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
task.addChild(token, 0);
return createWindow(null, type, token, name);
@@ -265,7 +271,7 @@
}
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final WindowToken token = createWindowToken(
dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name);
@@ -274,7 +280,7 @@
WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name,
boolean ownerCanAddInternalSystemWindow) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final WindowToken token = createWindowToken(
dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type);
return createWindow(parent, type, token, name, 0 /* ownerId */,
@@ -283,7 +289,7 @@
}
WindowState createWindow(WindowState parent, int type, WindowToken token, String name) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
return createWindow(parent, type, token, name, 0 /* ownerId */,
false /* ownerCanAddInternalSystemWindow */);
}
@@ -292,7 +298,7 @@
WindowState createWindow(WindowState parent, int type, WindowToken token, String name,
int ownerId, boolean ownerCanAddInternalSystemWindow) {
return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow,
- sWm, mMockSession, mIWindow);
+ mWm, mMockSession, mIWindow);
}
static WindowState createWindow(WindowState parent, int type, WindowToken token,
@@ -305,7 +311,7 @@
final WindowState w = new WindowState(service, session, iWindow, token, parent,
OP_NONE,
0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow,
- mPowerManagerWrapper);
+ sPowerManagerWrapper);
// TODO: Probably better to make this call in the WindowState ctor to avoid errors with
// adding it to the token...
token.addWindow(w);
@@ -315,13 +321,13 @@
/** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
TaskStack createTaskStackOnDisplay(DisplayContent dc) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
return createStackControllerOnDisplay(dc).mContainer;
}
}
StackWindowController createStackControllerOnDisplay(DisplayContent dc) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
return createStackControllerOnStackOnDisplay(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
}
@@ -329,13 +335,13 @@
StackWindowController createStackControllerOnStackOnDisplay(
int windowingMode, int activityType, DisplayContent dc) {
- synchronized (sWm.mGlobalLock) {
+ synchronized (mWm.mGlobalLock) {
final Configuration overrideConfig = new Configuration();
overrideConfig.windowConfiguration.setWindowingMode(windowingMode);
overrideConfig.windowConfiguration.setActivityType(activityType);
final int stackId = ++sNextStackId;
final StackWindowController controller = new StackWindowController(stackId, null,
- dc.getDisplayId(), true /* onTop */, new Rect(), sWm);
+ dc.getDisplayId(), true /* onTop */, new Rect(), mWm);
controller.onOverrideConfigurationChanged(overrideConfig);
return controller;
}
@@ -343,7 +349,7 @@
/** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
Task createTaskInStack(TaskStack stack, int userId) {
- return WindowTestUtils.createTaskInStack(sWm, stack, userId);
+ return WindowTestUtils.createTaskInStack(mWm, stack, userId);
}
/** Creates a {@link DisplayContent} and adds it to the system. */
@@ -351,8 +357,8 @@
final int displayId = sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- synchronized (sWm.mGlobalLock) {
- return new DisplayContent(display, sWm, mWallpaperController,
+ synchronized (mWm.mGlobalLock) {
+ return new DisplayContent(display, mWm, mWallpaperController,
mock(DisplayWindowController.class));
}
}
@@ -375,20 +381,19 @@
final int displayId = sNextDisplayId++;
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
- final DisplayWindowController dcw = new DisplayWindowController(display, sWm);
- synchronized (sWm.mGlobalLock) {
+ final DisplayWindowController dcw = new DisplayWindowController(display, mWm);
+ synchronized (mWm.mGlobalLock) {
// Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
// We skip those steps here.
- return sWm.mRoot.createDisplayContent(display, dcw);
+ return mWm.mRoot.createDisplayContent(display, dcw);
}
}
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
WindowToken token) {
- synchronized (sWm.mGlobalLock) {
- return new WindowTestUtils.TestWindowState(sWm, mMockSession, mIWindow, attrs, token);
+ synchronized (mWm.mGlobalLock) {
+ return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token);
}
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 3732486..3048f1a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -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.wm;
@@ -30,25 +30,22 @@
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* Tests for the {@link WindowToken} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.WindowTokenTests
+ * atest FrameworksServicesTests:WindowTokenTests
*/
-@SmallTest
@FlakyTest(bugId = 74078662)
+@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class WindowTokenTests extends WindowTestsBase {
@Test
- public void testAddWindow() throws Exception {
+ public void testAddWindow() {
final WindowTestUtils.TestWindowToken token =
WindowTestUtils.createTestWindowToken(0, mDisplayContent);
@@ -78,7 +75,7 @@
}
@Test
- public void testChildRemoval() throws Exception {
+ public void testChildRemoval() {
final DisplayContent dc = mDisplayContent;
final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc);
@@ -102,7 +99,7 @@
* Tokens should only be removed from the system when all their windows are gone.
*/
@Test
- public void testTokenRemovalProcess() throws Exception {
+ public void testTokenRemovalProcess() {
final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(
TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */);
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 3a8c4ae..32e4e02 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -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.wm;
@@ -38,27 +38,30 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
import org.junit.After;
import org.junit.Test;
import java.util.HashMap;
import java.util.LinkedList;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-
/**
- * Tests for the {@link WindowLayersController} class.
+ * Tests for the {@link DisplayContent#assignChildLayers(SurfaceControl.Transaction)} method.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ * atest FrameworksServicesTests:ZOrderingTests
*/
-@SmallTest
@FlakyTest(bugId = 74078662)
+@SmallTest
@Presubmit
public class ZOrderingTests extends WindowTestsBase {
- private class LayerRecordingTransaction extends SurfaceControl.Transaction {
+ private static class LayerRecordingTransaction extends SurfaceControl.Transaction {
+ // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
+ // such that we can keep track of the parents of Surfaces as they are constructed.
+ private final HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
@@ -85,17 +88,28 @@
private SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
+
+ void addParentFor(SurfaceControl child, SurfaceControl parent) {
+ mParentFor.put(child, parent);
+ }
+
+ SurfaceControl getParentFor(SurfaceControl child) {
+ return mParentFor.get(child);
+ }
+
+ @Override
+ public void close() {
+
+ }
}
- // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
- // such that we can keep track of the parents of Surfaces as they are constructed.
- private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
+ private static class HierarchyRecorder extends SurfaceControl.Builder {
+ private LayerRecordingTransaction mTransaction;
+ private SurfaceControl mPendingParent;
- private class HierarchyRecorder extends SurfaceControl.Builder {
- SurfaceControl mPendingParent;
-
- HierarchyRecorder(SurfaceSession s) {
+ HierarchyRecorder(SurfaceSession s, LayerRecordingTransaction transaction) {
super(s);
+ mTransaction = transaction;
}
@Override
@@ -106,16 +120,26 @@
@Override
public SurfaceControl build() {
- SurfaceControl sc = super.build();
- mParentFor.put(sc, mPendingParent);
+ final SurfaceControl sc = super.build();
+ mTransaction.addParentFor(sc, mPendingParent);
+ mTransaction = null;
mPendingParent = null;
return sc;
}
}
- private class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+ private static class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
+ private LayerRecordingTransaction mTransaction;
+
+ HierarchyRecordingBuilderFactory(LayerRecordingTransaction transaction) {
+ mTransaction = transaction;
+ }
+
+ @Override
public SurfaceControl.Builder make(SurfaceSession s) {
- return new HierarchyRecorder(s);
+ final LayerRecordingTransaction transaction = mTransaction;
+ mTransaction = null;
+ return new HierarchyRecorder(s, transaction);
}
}
@@ -127,18 +151,17 @@
// which is after construction of the DisplayContent, meaning the HierarchyRecorder
// would miss construction of the top-level layers.
mTransaction = new LayerRecordingTransaction();
- sWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory();
- sWm.mTransactionFactory = () -> mTransaction;
+ mWm.mSurfaceBuilderFactory = new HierarchyRecordingBuilderFactory(mTransaction);
+ mWm.mTransactionFactory = () -> mTransaction;
}
@After
- public void after() {
+ public void tearDown() {
mTransaction.close();
- mParentFor.keySet().forEach(SurfaceControl::destroy);
- mParentFor.clear();
}
- LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
+ private static LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t,
+ SurfaceControl sc) {
LinkedList<SurfaceControl> p = new LinkedList<>();
SurfaceControl current = sc;
do {
@@ -148,23 +171,22 @@
if (rs != null) {
current = rs;
} else {
- current = mParentFor.get(current);
+ current = t.getParentFor(current);
}
} while (current != null);
return p;
}
- void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
+ private static void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
SurfaceControl right) {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
- SurfaceControl commonAncestor = null;
SurfaceControl leftTop = leftParentChain.peekLast();
SurfaceControl rightTop = rightParentChain.peekLast();
while (leftTop != null && rightTop != null && leftTop == rightTop) {
- commonAncestor = leftParentChain.removeLast();
+ leftParentChain.removeLast();
rightParentChain.removeLast();
leftTop = leftParentChain.peekLast();
rightTop = rightParentChain.peekLast();
@@ -189,7 +211,7 @@
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
- sWm.mInputMethodTarget = null;
+ mWm.mInputMethodTarget = null;
mDisplayContent.assignChildLayers(mTransaction);
// The Ime has an higher base layer than app windows and lower base layer than system
@@ -207,7 +229,7 @@
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
- sWm.mInputMethodTarget = imeAppTarget;
+ mWm.mInputMethodTarget = imeAppTarget;
mDisplayContent.assignChildLayers(mTransaction);
@@ -233,7 +255,7 @@
TYPE_APPLICATION_MEDIA_OVERLAY, imeAppTarget.mToken,
"imeAppTargetChildBelowWindow");
- sWm.mInputMethodTarget = imeAppTarget;
+ mWm.mInputMethodTarget = imeAppTarget;
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows except for child windows that are z-ordered above it
@@ -255,7 +277,7 @@
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
- sWm.mInputMethodTarget = imeAppTarget;
+ mWm.mInputMethodTarget = imeAppTarget;
mDisplayContent.assignChildLayers(mTransaction);
// Ime should be above all app windows except for non-fullscreen app window above it and
@@ -278,7 +300,7 @@
mDisplayContent, "imeSystemOverlayTarget",
true /* ownerCanAddInternalSystemWindow */);
- sWm.mInputMethodTarget = imeSystemOverlayTarget;
+ mWm.mInputMethodTarget = imeSystemOverlayTarget;
mDisplayContent.assignChildLayers(mTransaction);
// The IME target base layer is higher than all window except for the nav bar window, so the
@@ -301,7 +323,7 @@
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
- sWm.mInputMethodTarget = mStatusBarWindow;
+ mWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
assertWindowHigher(mImeWindow, mChildAppWindowAbove);
@@ -322,8 +344,8 @@
final WindowState dockedStackWindow = createWindowOnStack(null,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION,
mDisplayContent, "dockedStackWindow");
- final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+ final WindowState assistantStackWindow = createWindowOnStack(null,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
final WindowState homeActivityWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_HOME, TYPE_BASE_APPLICATION,
@@ -368,7 +390,8 @@
final WindowState anyWindow = createWindow("anyWindow");
final WindowState child = createWindow(anyWindow, TYPE_APPLICATION_MEDIA, mDisplayContent,
"TypeApplicationMediaChild");
- final WindowState mediaOverlayChild = createWindow(anyWindow, TYPE_APPLICATION_MEDIA_OVERLAY,
+ final WindowState mediaOverlayChild = createWindow(anyWindow,
+ TYPE_APPLICATION_MEDIA_OVERLAY,
mDisplayContent, "TypeApplicationMediaOverlayChild");
mDisplayContent.assignChildLayers(mTransaction);
@@ -388,8 +411,8 @@
final WindowState splitScreenSecondaryWindow = createWindowOnStack(null,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD,
TYPE_BASE_APPLICATION, mDisplayContent, "splitScreenSecondaryWindow");
- final WindowState assistantStackWindow = createWindowOnStack(null, WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
+ final WindowState assistantStackWindow = createWindowOnStack(null,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, TYPE_BASE_APPLICATION,
mDisplayContent, "assistantStackWindow");
mDisplayContent.assignChildLayers(mTransaction);
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 73a34b6..ff84803 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -41,7 +41,8 @@
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityRequestedOrientationChange" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskChangeCallbacks" />
<activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityTaskDescriptionChange" />
- <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+ <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
+ android:showWhenLocked="true" />
</application>
<instrumentation
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
similarity index 81%
rename from services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
rename to services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 01b7c4f..0445ea0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -29,21 +31,21 @@
import android.content.Context;
import android.platform.test.annotations.Presubmit;
+import android.testing.DexmakerShareClassLoaderRule;
import android.util.proto.ProtoOutputStream;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.Preconditions;
-import com.android.server.wm.WindowManagerTraceProto;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import java.io.File;
import java.io.FileInputStream;
@@ -55,41 +57,44 @@
* Test class for {@link WindowTracing}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
+ * atest FrameworksServicesTests:WindowTracingTest
*/
-@SmallTest
@FlakyTest(bugId = 74078662)
-// TODO(b/116597907): Re-enable this test in postsubmit after the bug is fixed.
-// @Presubmit
-@RunWith(AndroidJUnit4.class)
-public class WindowTracingTest extends WindowTestsBase {
+@SmallTest
+@Presubmit
+public class WindowTracingTest {
- private static final byte[] MAGIC_HEADER = new byte[] {
- 0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
+ private static final byte[] MAGIC_HEADER = new byte[]{
+ 0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
};
- private Context mTestContext;
- private WindowTracing mWindowTracing;
+ @Rule
+ public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+ new DexmakerShareClassLoaderRule();
+
+ @Mock
private WindowManagerService mWmMock;
+ private WindowTracing mWindowTracing;
private File mFile;
- @Override
@Before
public void setUp() throws Exception {
- super.setUp();
+ MockitoAnnotations.initMocks(this);
- mWmMock = mock(WindowManagerService.class);
-
- mTestContext = InstrumentationRegistry.getContext();
-
- mFile = mTestContext.getFileStreamPath("tracing_test.dat");
+ final Context testContext = getInstrumentation().getContext();
+ mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
mWindowTracing = new WindowTracing(mFile);
}
+ @After
+ public void tearDown() throws Exception {
+ mFile.delete();
+ }
+
@Test
- public void isEnabled_returnsFalseByDefault() throws Exception {
+ public void isEnabled_returnsFalseByDefault() {
assertFalse(mWindowTracing.isEnabled());
}
@@ -107,7 +112,7 @@
}
@Test
- public void trace_discared_whenNotTracing() throws Exception {
+ public void trace_discared_whenNotTracing() {
mWindowTracing.traceStateLocked("where", mWmMock);
verifyZeroInteractions(mWmMock);
}
@@ -132,12 +137,12 @@
}
}
- @Test
@Ignore("Figure out why this test is crashing when setting up mWmMock.")
+ @Test
public void tracing_endsUpInFile() throws Exception {
mWindowTracing.startTrace(mock(PrintWriter.class));
- doAnswer((inv) -> {
+ doAnswer(inv -> {
inv.<ProtoOutputStream>getArgument(0).write(
WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
return null;
@@ -157,22 +162,14 @@
}
}
- @Override
- @After
- public void tearDown() throws Exception {
- super.tearDown();
-
- mFile.delete();
- }
-
/** Return true if {@code needle} appears anywhere in {@code haystack[0..length]} */
- boolean containsBytes(byte[] haystack, int haystackLenght, byte[] needle) {
- Preconditions.checkArgument(haystackLenght > 0);
+ private static boolean containsBytes(byte[] haystack, int haystackLength, byte[] needle) {
+ Preconditions.checkArgument(haystackLength > 0);
Preconditions.checkArgument(needle.length > 0);
- outer: for (int i = 0; i <= haystackLenght - needle.length; i++) {
+ outer: for (int i = 0; i <= haystackLength - needle.length; i++) {
for (int j = 0; j < needle.length; j++) {
- if (haystack[i+j] != needle[j]) {
+ if (haystack[i + j] != needle[j]) {
continue outer;
}
}
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index cac9f2b..9c64cf6 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -32,7 +32,20 @@
public static final int IWLAN = 5;
/** @hide */
- private AccessNetworkType() {};
+ private AccessNetworkType() {}
+
+ /** @hide */
+ public static String toString(int type) {
+ switch (type) {
+ case UNKNOWN: return "UNKNOWN";
+ case GERAN: return "GERAN";
+ case UTRAN: return "UTRAN";
+ case EUTRAN: return "EUTRAN";
+ case CDMA2000: return "CDMA2000";
+ case IWLAN: return "IWLAN";
+ default: return Integer.toString(type);
+ }
+ }
}
/**
@@ -47,7 +60,16 @@
public static final int WLAN = 2;
/** @hide */
- private TransportType() {};
+ private TransportType() {}
+
+ /** @hide */
+ public static String toString(int type) {
+ switch (type) {
+ case WWAN: return "WWAN";
+ case WLAN: return "WLAN";
+ default: return Integer.toString(type);
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 05c1fd5..d6856b3 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -31,27 +31,8 @@
private static final String LOG_TAG = "CellSignalStrengthLte";
private static final boolean DBG = false;
- /**
- * Indicates the unknown or undetectable RSSI value in ASU.
- *
- * Reference: TS 27.007 8.5 - Signal quality +CSQ
- */
- private static final int SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN = 99;
- /**
- * Indicates the maximum valid RSSI value in ASU.
- *
- * Reference: TS 27.007 8.5 - Signal quality +CSQ
- */
- private static final int SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE = 31;
- /**
- * Indicates the minimum valid RSSI value in ASU.
- *
- * Reference: TS 27.007 8.5 - Signal quality +CSQ
- */
- private static final int SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE = 0;
-
@UnsupportedAppUsage
- private int mRssi;
+ private int mSignalStrength;
@UnsupportedAppUsage
private int mRsrp;
@UnsupportedAppUsage
@@ -70,9 +51,9 @@
}
/** @hide */
- public CellSignalStrengthLte(int rssi, int rsrp, int rsrq, int rssnr, int cqi,
+ public CellSignalStrengthLte(int signalStrength, int rsrp, int rsrq, int rssnr, int cqi,
int timingAdvance) {
- mRssi = convertRssiAsuToDBm(rssi);
+ mSignalStrength = signalStrength;
mRsrp = rsrp;
mRsrq = rsrq;
mRssnr = rssnr;
@@ -87,7 +68,7 @@
/** @hide */
protected void copyFrom(CellSignalStrengthLte s) {
- mRssi = s.mRssi;
+ mSignalStrength = s.mSignalStrength;
mRsrp = s.mRsrp;
mRsrq = s.mRsrq;
mRssnr = s.mRssnr;
@@ -104,7 +85,7 @@
/** @hide */
@Override
public void setDefaultValues() {
- mRssi = CellInfo.UNAVAILABLE;
+ mSignalStrength = CellInfo.UNAVAILABLE;
mRsrp = CellInfo.UNAVAILABLE;
mRsrq = CellInfo.UNAVAILABLE;
mRssnr = CellInfo.UNAVAILABLE;
@@ -161,19 +142,6 @@
}
/**
- * Get Received Signal Strength Indication (RSSI) in dBm
- *
- * The value range is [-113, -51] inclusively or {@link CellInfo#UNAVAILABLE} if unavailable.
- *
- * Reference: TS 27.007 8.5 Signal quality +CSQ
- *
- * @return the RSSI if available or {@link CellInfo#UNAVAILABLE} if unavailable.
- */
- public int getRssi() {
- return mRssi;
- }
-
- /**
* Get reference signal signal-to-noise ratio
*
* @return the RSSNR if available or
@@ -242,7 +210,7 @@
@Override
public int hashCode() {
- return Objects.hash(mRssi, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
+ return Objects.hash(mSignalStrength, mRsrp, mRsrq, mRssnr, mCqi, mTimingAdvance);
}
@Override
@@ -259,7 +227,7 @@
return false;
}
- return mRssi == s.mRssi
+ return mSignalStrength == s.mSignalStrength
&& mRsrp == s.mRsrp
&& mRsrq == s.mRsrq
&& mRssnr == s.mRssnr
@@ -273,7 +241,7 @@
@Override
public String toString() {
return "CellSignalStrengthLte:"
- + " rssi(dBm)=" + mRssi
+ + " ss=" + mSignalStrength
+ " rsrp=" + mRsrp
+ " rsrq=" + mRsrq
+ " rssnr=" + mRssnr
@@ -285,7 +253,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
if (DBG) log("writeToParcel(Parcel, int): " + toString());
- dest.writeInt(mRssi);
+ dest.writeInt(mSignalStrength);
// Need to multiply rsrp and rsrq by -1
// to ensure consistency when reading values written here
// unless the values are invalid
@@ -301,7 +269,7 @@
* where the token is already been processed.
*/
private CellSignalStrengthLte(Parcel in) {
- mRssi = convertRssiAsuToDBm(in.readInt());
+ mSignalStrength = in.readInt();
// rsrp and rsrq are written into the parcel as positive values.
// Need to convert into negative values unless the values are invalid
mRsrp = in.readInt();
@@ -341,17 +309,4 @@
private static void log(String s) {
Rlog.w(LOG_TAG, s);
}
-
- private static int convertRssiAsuToDBm(int rssiAsu) {
- if (rssiAsu != SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN
- && (rssiAsu < SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MIN_VALUE
- || rssiAsu > SIGNAL_STRENGTH_LTE_RSSI_VALID_ASU_MAX_VALUE)) {
- Rlog.e(LOG_TAG, "convertRssiAsuToDBm: invalid RSSI in ASU=" + rssiAsu);
- return CellInfo.UNAVAILABLE;
- }
- if (rssiAsu == SIGNAL_STRENGTH_LTE_RSSI_ASU_UNKNOWN) {
- return CellInfo.UNAVAILABLE;
- }
- return -113 + (2 * rssiAsu);
- }
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index aabefe3..2e9bffe 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1184,6 +1184,16 @@
}
/**
+ * @param apnType APN type
+ * @return APN type in string format
+ * @hide
+ */
+ public static String getApnTypeString(int apnType) {
+ String apnTypeString = APN_TYPE_INT_MAP.get(apnType);
+ return apnTypeString == null ? "Unknown" : apnTypeString;
+ }
+
+ /**
* @param types comma delimited list of APN types.
* @return bitmask of APN types.
* @hide
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
index 04266c5..b9222a8 100644
--- a/tests/net/java/android/net/MacAddressTest.java
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -17,8 +17,8 @@
package android.net;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest;
@@ -252,6 +252,39 @@
}
}
+ @Test
+ public void testMatches() {
+ // match 4 bytes prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:00:00"),
+ MacAddress.fromString("ff:ff:ff:ff:00:00")));
+
+ // match bytes 0,1,2 and 5
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:00:00:11"),
+ MacAddress.fromString("ff:ff:ff:00:00:ff")));
+
+ // match 34 bit prefix
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:c0:00"),
+ MacAddress.fromString("ff:ff:ff:ff:c0:00")));
+
+ // fail to match 36 bit prefix
+ assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:40:00"),
+ MacAddress.fromString("ff:ff:ff:ff:f0:00")));
+
+ // match all 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("aa:bb:cc:dd:ee:11"),
+ MacAddress.fromString("ff:ff:ff:ff:ff:ff")));
+
+ // match none of 6 bytes
+ assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
+ MacAddress.fromString("00:00:00:00:00:00"),
+ MacAddress.fromString("00:00:00:00:00:00")));
+ }
+
static byte[] toByteArray(int... in) {
byte[] out = new byte[in.length];
for (int i = 0; i < in.length; i++) {
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 0a517ab..0bc5221 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -306,8 +306,29 @@
break;
}
- if (entry->overlayable) {
- printer->Print(" OVERLAYABLE");
+ for (size_t i = 0; i < entry->overlayable_declarations.size(); i++) {
+ printer->Print((i == 0) ? " " : "|");
+ printer->Print("OVERLAYABLE");
+
+ if (entry->overlayable_declarations[i].policy) {
+ switch (entry->overlayable_declarations[i].policy.value()) {
+ case Overlayable::Policy::kProduct:
+ printer->Print("_PRODUCT");
+ break;
+ case Overlayable::Policy::kProductServices:
+ printer->Print("_PRODUCT_SERVICES");
+ break;
+ case Overlayable::Policy::kSystem:
+ printer->Print("_SYSTEM");
+ break;
+ case Overlayable::Policy::kVendor:
+ printer->Print("_VENDOR");
+ break;
+ case Overlayable::Policy::kPublic:
+ printer->Print("_PUBLIC");
+ break;
+ }
+ }
}
printer->Println();
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9a3f14c..4f25e09 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -99,7 +99,7 @@
ResourceId id;
Visibility::Level visibility_level = Visibility::Level::kUndefined;
bool allow_new = false;
- bool overlayable = false;
+ std::vector<Overlayable> overlayable_declarations;
std::string comment;
std::unique_ptr<Value> value;
@@ -133,11 +133,8 @@
}
}
- if (res->overlayable) {
- Overlayable overlayable;
- overlayable.source = res->source;
- overlayable.comment = res->comment;
- if (!table->SetOverlayable(res->name, overlayable, diag)) {
+ for (auto& overlayable : res->overlayable_declarations) {
+ if (!table->AddOverlayable(res->name, overlayable, diag)) {
return false;
}
}
@@ -673,7 +670,7 @@
if (can_be_bag) {
const auto bag_iter = elToBagMap.find(resource_type);
if (bag_iter != elToBagMap.end()) {
- // Ensure we have a name (unless this is a <public-group>).
+ // Ensure we have a name (unless this is a <public-group> or <overlayable>).
if (resource_type != "public-group" && resource_type != "overlayable") {
if (!maybe_name) {
diag_->Error(DiagMessage(out_resource->source)
@@ -1062,74 +1059,137 @@
bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (out_resource->config != ConfigDescription::DefaultConfig()) {
diag_->Warn(DiagMessage(out_resource->source)
- << "ignoring configuration '" << out_resource->config << "' for <overlayable> tag");
+ << "ignoring configuration '" << out_resource->config
+ << "' for <overlayable> tag");
}
- if (Maybe<StringPiece> maybe_policy = xml::FindNonEmptyAttribute(parser, "policy")) {
- const StringPiece& policy = maybe_policy.value();
- if (policy != "system") {
- diag_->Error(DiagMessage(out_resource->source)
- << "<overlayable> has invalid policy '" << policy << "'");
- return false;
- }
- }
+ std::string comment;
+ std::vector<Overlayable::Policy> policies;
bool error = false;
- const size_t depth = parser->depth();
- while (xml::XmlPullParser::NextChildNode(parser, depth)) {
- if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
- // Skip text/comments.
+ const size_t start_depth = parser->depth();
+ while (xml::XmlPullParser::IsGoodEvent(parser->Next())) {
+ xml::XmlPullParser::Event event = parser->event();
+ if (event == xml::XmlPullParser::Event::kEndElement && parser->depth() == start_depth) {
+ // Break the loop when exiting the overyabale element
+ break;
+ } else if (event == xml::XmlPullParser::Event::kEndElement
+ && parser->depth() == start_depth + 1) {
+ // Clear the current policies when exiting the policy element
+ policies.clear();
+ continue;
+ } else if (event == xml::XmlPullParser::Event::kComment) {
+ // Get the comment of individual item elements
+ comment = parser->comment();
+ continue;
+ } else if (event != xml::XmlPullParser::Event::kStartElement) {
+ // Skip to the next element
continue;
}
const Source item_source = source_.WithLine(parser->line_number());
- const std::string& element_namespace = parser->element_namespace();
const std::string& element_name = parser->element_name();
+ const std::string& element_namespace = parser->element_namespace();
+
if (element_namespace.empty() && element_name == "item") {
- Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
- if (!maybe_name) {
- diag_->Error(DiagMessage(item_source)
- << "<item> within an <overlayable> tag must have a 'name' attribute");
+ if (!ParseOverlayableItem(parser, policies, comment, out_resource)) {
error = true;
- continue;
}
-
- Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
- if (!maybe_type) {
- diag_->Error(DiagMessage(item_source)
- << "<item> within an <overlayable> tag must have a 'type' attribute");
+ } else if (element_namespace.empty() && element_name == "policy") {
+ if (!policies.empty()) {
+ // If the policy list is not empty, then we are currently inside a policy element
+ diag_->Error(DiagMessage(item_source) << "<policy> blocks cannot be recursively nested");
error = true;
- continue;
+ break;
+ } else if (Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
+ // Parse the polices separated by vertical bar characters to allow for specifying multiple
+ // policies at once
+ for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
+ StringPiece trimmed_part = util::TrimWhitespace(part);
+ if (trimmed_part == "public") {
+ policies.push_back(Overlayable::Policy::kPublic);
+ } else if (trimmed_part == "product") {
+ policies.push_back(Overlayable::Policy::kProduct);
+ } else if (trimmed_part == "product_services") {
+ policies.push_back(Overlayable::Policy::kProductServices);
+ } else if (trimmed_part == "system") {
+ policies.push_back(Overlayable::Policy::kSystem);
+ } else if (trimmed_part == "vendor") {
+ policies.push_back(Overlayable::Policy::kVendor);
+ } else {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "<policy> has unsupported type '" << trimmed_part << "'");
+ error = true;
+ continue;
+ }
+ }
}
-
- const ResourceType* type = ParseResourceType(maybe_type.value());
- if (type == nullptr) {
- diag_->Error(DiagMessage(out_resource->source)
- << "invalid resource type '" << maybe_type.value()
- << "' in <item> within an <overlayable>");
- error = true;
- continue;
- }
-
- ParsedResource child_resource;
- child_resource.name.type = *type;
- child_resource.name.entry = maybe_name.value().to_string();
- child_resource.source = item_source;
- child_resource.overlayable = true;
- if (options_.visibility) {
- child_resource.visibility_level = options_.visibility.value();
- }
- out_resource->child_resources.push_back(std::move(child_resource));
-
- xml::XmlPullParser::SkipCurrentElement(parser);
} else if (!ShouldIgnoreElement(element_namespace, element_name)) {
- diag_->Error(DiagMessage(item_source) << ":" << element_name << ">");
+ diag_->Error(DiagMessage(item_source) << "invalid element <" << element_name << "> in "
+ << " <overlayable>");
error = true;
+ break;
}
}
+
return !error;
}
+bool ResourceParser::ParseOverlayableItem(xml::XmlPullParser* parser,
+ const std::vector<Overlayable::Policy>& policies,
+ const std::string& comment,
+ ParsedResource* out_resource) {
+ const Source item_source = source_.WithLine(parser->line_number());
+
+ Maybe<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
+ if (!maybe_name) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'name' attribute");
+ return false;
+ }
+
+ Maybe<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type");
+ if (!maybe_type) {
+ diag_->Error(DiagMessage(item_source)
+ << "<item> within an <overlayable> tag must have a 'type' attribute");
+ return false;
+ }
+
+ const ResourceType* type = ParseResourceType(maybe_type.value());
+ if (type == nullptr) {
+ diag_->Error(DiagMessage(out_resource->source)
+ << "invalid resource type '" << maybe_type.value()
+ << "' in <item> within an <overlayable>");
+ return false;
+ }
+
+ ParsedResource child_resource;
+ child_resource.name.type = *type;
+ child_resource.name.entry = maybe_name.value().to_string();
+ child_resource.source = item_source;
+
+ if (policies.empty()) {
+ Overlayable overlayable;
+ overlayable.source = item_source;
+ overlayable.comment = comment;
+ child_resource.overlayable_declarations.push_back(overlayable);
+ } else {
+ for (Overlayable::Policy policy : policies) {
+ Overlayable overlayable;
+ overlayable.policy = policy;
+ overlayable.source = item_source;
+ overlayable.comment = comment;
+ child_resource.overlayable_declarations.push_back(overlayable);
+ }
+ }
+
+ if (options_.visibility) {
+ child_resource.visibility_level = options_.visibility.value();
+ }
+ out_resource->child_resources.push_back(std::move(child_resource));
+ return true;
+}
+
bool ResourceParser::ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource) {
if (ParseSymbolImpl(parser, out_resource)) {
out_resource->visibility_level = Visibility::Level::kUndefined;
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 06bb0c9..ebacd6f 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -96,6 +96,10 @@
bool ParseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseSymbol(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseOverlayable(xml::XmlPullParser* parser, ParsedResource* out_resource);
+ bool ParseOverlayableItem(xml::XmlPullParser* parser,
+ const std::vector<Overlayable::Policy>& policies,
+ const std::string& comment,
+ ParsedResource* out_resource);
bool ParseAddResource(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 0dff664..c6f29ac 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -891,56 +891,162 @@
ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
}
-TEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) {
- std::string input = R"(
- <overlayable policy="illegal_policy">
- <item type="string" name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="attr" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="bad_type" name="foo" />
- </overlayable>)";
- EXPECT_FALSE(TestParse(input));
-
- input = R"(<overlayable policy="system" />)";
+TEST_F(ResourceParserTest, ParseOverlayable) {
+ std::string input = R"(<overlayable />)";
EXPECT_TRUE(TestParse(input));
- input = R"(<overlayable />)";
- EXPECT_TRUE(TestParse(input));
-
- input = R"(
- <overlayable policy="system">
- <item type="string" name="foo" />
- <item type="dimen" name="foo" />
- </overlayable>)";
- ASSERT_TRUE(TestParse(input));
-
input = R"(
<overlayable>
- <item type="string" name="bar" />
+ <item type="string" name="foo" />
+ <item type="drawable" name="bar" />
</overlayable>)";
ASSERT_TRUE(TestParse(input));
- Maybe<ResourceTable::SearchResult> search_result =
- table_.FindResource(test::ParseNameOrDie("string/bar"));
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
- EXPECT_TRUE(search_result.value().entry->overlayable);
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+ search_result = table_.FindResource(test::ParseNameOrDie("drawable/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+}
+
+TEST_F(ResourceParserTest, ParseOverlayablePolicy) {
+ std::string input = R"(<overlayable />)";
+ EXPECT_TRUE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <item type="string" name="foo" />
+ <policy type="product">
+ <item type="string" name="bar" />
+ </policy>
+ <policy type="product_services">
+ <item type="string" name="baz" />
+ </policy>
+ <policy type="system">
+ <item type="string" name="fiz" />
+ </policy>
+ <policy type="vendor">
+ <item type="string" name="fuz" />
+ </policy>
+ <policy type="public">
+ <item type="string" name="faz" />
+ </policy>
+ </overlayable>)";
+ ASSERT_TRUE(TestParse(input));
+
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProductServices));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kSystem));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/fuz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kVendor));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/faz"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kPublic));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="illegal_policy">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="product">
+ <item name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="vendor">
+ <item type="string" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product_services">
+ <item type="string" name="foo" />
+ </policy>
+ <policy type="product|system">
+ <item type="string" name="bar" />
+ </policy>
+ </overlayable>)";
+ ASSERT_TRUE(TestParse(input));
+
+ auto search_result = table_.FindResource(test::ParseNameOrDie("string/foo"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kVendor));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+
+ search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kSystem));
}
TEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
@@ -950,6 +1056,85 @@
<item type="string" name="foo" />
</overlayable>)";
EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable>
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable">
+ <policy type="product">
+ <item type="string" name="foo" />
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable>
+ <policy type="product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>
+
+ <overlayable>
+ <policy type="product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, PolicyAndNonPolicyOverlayableError) {
+ std::string input = R"(
+ <overlayable policy="product">
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable policy="">
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+
+ input = R"(
+ <overlayable policy="">
+ <item type="string" name="foo" />
+ </overlayable>
+ <overlayable policy="product">
+ <item type="string" name="foo" />
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, DuplicateOverlayableMultiplePolicyError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>
+ <overlayable>
+ <policy type="product_services|vendor">
+ <item type="string" name="foo" />
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
+}
+
+TEST_F(ResourceParserTest, NestPolicyInOverlayableError) {
+ std::string input = R"(
+ <overlayable>
+ <policy type="vendor|product">
+ <policy type="product_services">
+ <item type="string" name="foo" />
+ </policy>
+ </policy>
+ </overlayable>)";
+ EXPECT_FALSE(TestParse(input));
}
TEST_F(ResourceParserTest, ParseIdItem) {
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 056a27b..bc8a4d1 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -625,17 +625,17 @@
return true;
}
-bool ResourceTable::SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag) {
- return SetOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
+ return AddOverlayableImpl(name, overlayable, ResourceNameValidator, diag);
}
-bool ResourceTable::SetOverlayableMangled(const ResourceNameRef& name,
+bool ResourceTable::AddOverlayableMangled(const ResourceNameRef& name,
const Overlayable& overlayable, IDiagnostics* diag) {
- return SetOverlayableImpl(name, overlayable, SkipNameValidator, diag);
+ return AddOverlayableImpl(name, overlayable, SkipNameValidator, diag);
}
-bool ResourceTable::SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+bool ResourceTable::AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
NameValidator name_validator, IDiagnostics* diag) {
CHECK(diag != nullptr);
@@ -646,13 +646,28 @@
ResourceTablePackage* package = FindOrCreatePackage(name.package);
ResourceTableType* type = package->FindOrCreateType(name.type);
ResourceEntry* entry = type->FindOrCreateEntry(name.entry);
- if (entry->overlayable) {
- diag->Error(DiagMessage(overlayable.source)
- << "duplicate overlayable declaration for resource '" << name << "'");
- diag->Error(DiagMessage(entry->overlayable.value().source) << "previous declaration here");
- return false;
+
+ for (auto& overlayable_declaration : entry->overlayable_declarations) {
+ // An overlayable resource cannot be declared twice with the same policy
+ if (overlayable.policy == overlayable_declaration.policy) {
+ diag->Error(DiagMessage(overlayable.source)
+ << "duplicate overlayable declaration for resource '" << name << "'");
+ diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+ return false;
+ }
+
+ // An overlayable resource cannot be declared once with a policy and without a policy because
+ // the policy becomes unused
+ if (!overlayable.policy || !overlayable_declaration.policy) {
+ diag->Error(DiagMessage(overlayable.source)
+ << "overlayable resource '" << name << "'"
+ << " declared once with a policy and once with no policy");
+ diag->Error(DiagMessage(overlayable_declaration.source) << "previous declaration here");
+ return false;
+ }
}
- entry->overlayable = overlayable;
+
+ entry->overlayable_declarations.push_back(overlayable);
return true;
}
@@ -688,7 +703,7 @@
new_entry->id = entry->id;
new_entry->visibility = entry->visibility;
new_entry->allow_new = entry->allow_new;
- new_entry->overlayable = entry->overlayable;
+ new_entry->overlayable_declarations = entry->overlayable_declarations;
for (const auto& config_value : entry->values) {
ResourceConfigValue* new_value =
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 1917d7e..3dd0a769 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -57,8 +57,27 @@
std::string comment;
};
-// The policy dictating whether an entry is overlayable at runtime by RROs.
+// Represents a declaration that a resource is overayable at runtime.
struct Overlayable {
+ // Represents the types overlays that are allowed to overlay the resource.
+ enum class Policy {
+ // The resource can be overlaid by any overlay.
+ kPublic,
+
+ // The resource can be overlaid by any overlay on the system partition.
+ kSystem,
+
+ // The resource can be overlaid by any overlay on the vendor partition.
+ kVendor,
+
+ // The resource can be overlaid by any overlay on the product partition.
+ kProduct,
+
+ // The resource can be overlaid by any overlay on the product services partition.
+ kProductServices,
+ };
+
+ Maybe<Policy> policy;
Source source;
std::string comment;
};
@@ -96,7 +115,8 @@
Maybe<AllowNew> allow_new;
- Maybe<Overlayable> overlayable;
+ // The declarations of this resource as overlayable for RROs
+ std::vector<Overlayable> overlayable_declarations;
// The resource's values for each configuration.
std::vector<std::unique_ptr<ResourceConfigValue>> values;
@@ -226,9 +246,9 @@
bool SetVisibilityWithIdMangled(const ResourceNameRef& name, const Visibility& visibility,
const ResourceId& res_id, IDiagnostics* diag);
- bool SetOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayable(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag);
- bool SetOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayableMangled(const ResourceNameRef& name, const Overlayable& overlayable,
IDiagnostics* diag);
bool SetAllowNew(const ResourceNameRef& name, const AllowNew& allow_new, IDiagnostics* diag);
@@ -303,7 +323,7 @@
bool SetAllowNewImpl(const ResourceNameRef& name, const AllowNew& allow_new,
NameValidator name_validator, IDiagnostics* diag);
- bool SetOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
+ bool AddOverlayableImpl(const ResourceNameRef& name, const Overlayable& overlayable,
NameValidator name_validator, IDiagnostics* diag);
bool SetSymbolStateImpl(const ResourceNameRef& name, const ResourceId& res_id,
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 05c6f15..7c28f07 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -242,21 +242,69 @@
ASSERT_THAT(result.value().entry->allow_new.value().comment, StrEq("second"));
}
-TEST(ResourceTableTest, SetOverlayable) {
+TEST(ResourceTableTest, AddOverlayable) {
ResourceTable table;
const ResourceName name = test::ParseNameOrDie("android:string/foo");
Overlayable overlayable;
-
+ overlayable.policy = Overlayable::Policy::kProduct;
overlayable.comment = "first";
- ASSERT_TRUE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
Maybe<ResourceTable::SearchResult> result = table.FindResource(name);
ASSERT_TRUE(result);
- ASSERT_TRUE(result.value().entry->overlayable);
- ASSERT_THAT(result.value().entry->overlayable.value().comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
- overlayable.comment = "second";
- ASSERT_FALSE(table.SetOverlayable(name, overlayable, test::GetDiagnostics()));
+ Overlayable overlayable2;
+ overlayable2.comment = "second";
+ overlayable2.policy = Overlayable::Policy::kProductServices;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+ result = table.FindResource(name);
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].comment, StrEq("first"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].comment, StrEq("second"));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST(ResourceTableTest, AddDuplicateOverlayableFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ Overlayable overlayable;
+ overlayable.policy = Overlayable::Policy::kProduct;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+ Overlayable overlayable2;
+ overlayable2.policy = Overlayable::Policy::kProduct;
+ ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneFirstFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ ASSERT_TRUE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
+
+ Overlayable overlayable2;
+ overlayable2.policy = Overlayable::Policy::kProduct;
+ ASSERT_FALSE(table.AddOverlayable(name, overlayable2, test::GetDiagnostics()));
+}
+
+TEST(ResourceTableTest, AddOverlayablePolicyAndNoneLastFail) {
+ ResourceTable table;
+ const ResourceName name = test::ParseNameOrDie("android:string/foo");
+
+ Overlayable overlayable;
+ overlayable.policy = Overlayable::Policy::kProduct;
+ ASSERT_TRUE(table.AddOverlayable(name, overlayable, test::GetDiagnostics()));
+
+ ASSERT_FALSE(table.AddOverlayable(name, {}, test::GetDiagnostics()));
}
TEST(ResourceTableTest, AllowDuplictaeResourcesNames) {
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index d7a3771..bf9fe49 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -133,13 +133,25 @@
string comment = 2;
}
-// Whether a resource is overlayable by runtime resource overlays (RRO).
+// Represents a declaration that a resource is overayable at runtime.
message Overlayable {
+ enum Policy {
+ NONE = 0;
+ PUBLIC = 1;
+ SYSTEM = 2;
+ VENDOR = 3;
+ PRODUCT = 4;
+ PRODUCT_SERVICES = 5;
+ }
+
// Where this declaration was defined in source.
Source source = 1;
// Any comment associated with the declaration.
string comment = 2;
+
+ // The policy of the overlayable declaration
+ Policy policy = 3;
}
// An entry ID in the range [0x0000, 0xffff].
@@ -169,7 +181,7 @@
AllowNew allow_new = 4;
// Whether this resource can be overlaid by a runtime resource overlay (RRO).
- Overlayable overlayable = 5;
+ repeated Overlayable overlayable = 5;
// The set of values defined for this entry, each corresponding to a different
// configuration/variant.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 3a39a6b..ed70fb3 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -398,7 +398,7 @@
if (type_spec_flags & ResTable_typeSpec::SPEC_OVERLAYABLE) {
Overlayable overlayable;
overlayable.source = source_.WithLine(0);
- if (!table_->SetOverlayableMangled(name, overlayable, diag_)) {
+ if (!table_->AddOverlayableMangled(name, overlayable, diag_)) {
return false;
}
}
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 8641a7c..8a86f63a 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -446,7 +446,7 @@
config_masks[entry->id.value()] |= util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
}
- if (entry->overlayable) {
+ if (!entry->overlayable_declarations.empty()) {
config_masks[entry->id.value()] |=
util::HostToDevice32(ResTable_typeSpec::SPEC_OVERLAYABLE);
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index af19b98..cd1414c 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -634,7 +634,7 @@
.AddSimple("com.app.test:integer/overlayable", ResourceId(0x7f020000))
.Build();
- ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
+ ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.test:integer/overlayable"),
Overlayable{}, test::GetDiagnostics()));
ResTable res_table;
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index d1b2fdb..f612914 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -437,15 +437,37 @@
entry->allow_new = std::move(allow_new);
}
- if (pb_entry.has_overlayable()) {
- const pb::Overlayable& pb_overlayable = pb_entry.overlayable();
-
+ for (const pb::Overlayable& pb_overlayable : pb_entry.overlayable()) {
Overlayable overlayable;
+ switch (pb_overlayable.policy()) {
+ case pb::Overlayable::NONE:
+ overlayable.policy = {};
+ break;
+ case pb::Overlayable::PUBLIC:
+ overlayable.policy = Overlayable::Policy::kPublic;
+ break;
+ case pb::Overlayable::PRODUCT:
+ overlayable.policy = Overlayable::Policy::kProduct;
+ break;
+ case pb::Overlayable::PRODUCT_SERVICES:
+ overlayable.policy = Overlayable::Policy::kProductServices;
+ break;
+ case pb::Overlayable::SYSTEM:
+ overlayable.policy = Overlayable::Policy::kSystem;
+ break;
+ case pb::Overlayable::VENDOR:
+ overlayable.policy = Overlayable::Policy::kVendor;
+ break;
+ default:
+ *out_error = "unknown overlayable policy";
+ return false;
+ }
+
if (pb_overlayable.has_source()) {
DeserializeSourceFromPb(pb_overlayable.source(), src_pool, &overlayable.source);
}
overlayable.comment = pb_overlayable.comment();
- entry->overlayable = std::move(overlayable);
+ entry->overlayable_declarations.push_back(overlayable);
}
ResourceId resid(pb_package.package_id().id(), pb_type.type_id().id(),
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 7e35ea7..f1e96d6 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -310,11 +310,31 @@
pb_allow_new->set_comment(entry->allow_new.value().comment);
}
- if (entry->overlayable) {
- pb::Overlayable* pb_overlayable = pb_entry->mutable_overlayable();
- SerializeSourceToPb(entry->overlayable.value().source, &source_pool,
+ for (const Overlayable& overlayable : entry->overlayable_declarations) {
+ pb::Overlayable* pb_overlayable = pb_entry->add_overlayable();
+ if (overlayable.policy) {
+ switch (overlayable.policy.value()) {
+ case Overlayable::Policy::kPublic:
+ pb_overlayable->set_policy(pb::Overlayable::PUBLIC);
+ break;
+ case Overlayable::Policy::kProduct:
+ pb_overlayable->set_policy(pb::Overlayable::PRODUCT);
+ break;
+ case Overlayable::Policy::kProductServices:
+ pb_overlayable->set_policy(pb::Overlayable::PRODUCT_SERVICES);
+ break;
+ case Overlayable::Policy::kSystem:
+ pb_overlayable->set_policy(pb::Overlayable::SYSTEM);
+ break;
+ case Overlayable::Policy::kVendor:
+ pb_overlayable->set_policy(pb::Overlayable::VENDOR);
+ break;
+ }
+ }
+
+ SerializeSourceToPb(overlayable.source, &source_pool,
pb_overlayable->mutable_source());
- pb_overlayable->set_comment(entry->overlayable.value().comment);
+ pb_overlayable->set_comment(overlayable.comment);
}
for (const std::unique_ptr<ResourceConfigValue>& config_value : entry->values) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 3c4d41a..95dbbeb 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -93,7 +93,7 @@
util::make_unique<Reference>(expected_ref), context->GetDiagnostics()));
// Make an overlayable resource.
- ASSERT_TRUE(table->SetOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
+ ASSERT_TRUE(table->AddOverlayable(test::ParseNameOrDie("com.app.a:integer/overlayable"),
Overlayable{}, test::GetDiagnostics()));
pb::ResourceTable pb_table;
@@ -106,7 +106,7 @@
ResourceTable new_table;
std::string error;
- ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error)) << error;
EXPECT_THAT(error, IsEmpty());
Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
@@ -160,7 +160,8 @@
new_table.FindResource(test::ParseNameOrDie("com.app.a:integer/overlayable"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
- EXPECT_TRUE(search_result.value().entry->overlayable);
+ EXPECT_THAT(search_result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(search_result.value().entry->overlayable_declarations[0].policy);
}
TEST(ProtoSerializeTest, SerializeAndDeserializeXml) {
@@ -464,4 +465,59 @@
"night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23");
}
+TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kSystem)
+ .AddOverlayable("com.app.a:bool/foo", Overlayable::Policy::kProduct)
+ .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kProductServices)
+ .AddOverlayable("com.app.a:bool/bar", Overlayable::Policy::kVendor)
+ .AddOverlayable("com.app.a:bool/baz", Overlayable::Policy::kPublic)
+ .AddOverlayable("com.app.a:bool/biz", {})
+ .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true"))
+ .Build();
+
+ pb::ResourceTable pb_table;
+ SerializeTableToPb(*table, &pb_table, context->GetDiagnostics());
+
+ MockFileCollection files;
+ ResourceTable new_table;
+ std::string error;
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
+ EXPECT_THAT(error, IsEmpty());
+
+ Maybe<ResourceTable::SearchResult> result =
+ new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kSystem));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProduct));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/bar"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProductServices));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kVendor));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kPublic));
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz"));
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(1));
+ EXPECT_FALSE(result.value().entry->overlayable_declarations[0].policy);
+
+ result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/fiz"));
+ ASSERT_TRUE(result);
+ EXPECT_THAT(result.value().entry->overlayable_declarations.size(), Eq(0));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index afb8ae0..d777e22 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -101,7 +101,7 @@
return true;
}
-static bool MergeEntry(IAaptContext* context, const Source& src, bool overlay,
+static bool MergeEntry(IAaptContext* context, const Source& src,
ResourceEntry* dst_entry, ResourceEntry* src_entry,
bool strict_visibility) {
if (strict_visibility
@@ -134,17 +134,35 @@
dst_entry->allow_new = std::move(src_entry->allow_new);
}
- if (src_entry->overlayable) {
- if (dst_entry->overlayable && !overlay) {
- context->GetDiagnostics()->Error(DiagMessage(src_entry->overlayable.value().source)
- << "duplicate overlayable declaration for resource '"
- << src_entry->name << "'");
- context->GetDiagnostics()->Error(DiagMessage(dst_entry->overlayable.value().source)
- << "previous declaration here");
- return false;
+ for (auto& src_overlayable : src_entry->overlayable_declarations) {
+ for (auto& dst_overlayable : dst_entry->overlayable_declarations) {
+ // An overlayable resource cannot be declared twice with the same policy
+ if (src_overlayable.policy == dst_overlayable.policy) {
+ context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+ << "duplicate overlayable declaration for resource '"
+ << src_entry->name << "'");
+ context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+ << "previous declaration here");
+ return false;
+ }
+
+ // An overlayable resource cannot be declared once with a policy and without a policy because
+ // the policy becomes unused
+ if (!src_overlayable.policy || !dst_overlayable.policy) {
+ context->GetDiagnostics()->Error(DiagMessage(src_overlayable.source)
+ << "overlayable resource '" << src_entry->name
+ << "' declared once with a policy and once with no "
+ << "policy");
+ context->GetDiagnostics()->Error(DiagMessage(dst_overlayable.source)
+ << "previous declaration here");
+ return false;
+ }
}
- dst_entry->overlayable = std::move(src_entry->overlayable);
}
+
+ dst_entry->overlayable_declarations.insert(dst_entry->overlayable_declarations.end(),
+ src_entry->overlayable_declarations.begin(),
+ src_entry->overlayable_declarations.end());
return true;
}
@@ -244,7 +262,7 @@
continue;
}
- if (!MergeEntry(context_, src, overlay, dst_entry, src_entry.get(), options_.strict_visibility)) {
+ if (!MergeEntry(context_, src, dst_entry, src_entry.get(), options_.strict_visibility)) {
error = true;
continue;
}
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 79a734b..d6579d3 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -436,4 +436,97 @@
Eq(make_value(Reference(test::ParseNameOrDie("com.app.a:style/OverlayParent")))));
}
+TEST_F(TableMergerTest, AddOverlayable) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProductServices)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_TRUE(merger.Merge({}, table_b.get(), false /*overlay*/));
+
+ const ResourceName name = test::ParseNameOrDie("com.app.a:bool/foo");
+ Maybe<ResourceTable::SearchResult> result = final_table.FindResource(name);
+ ASSERT_TRUE(result);
+ ASSERT_THAT(result.value().entry->overlayable_declarations.size(), Eq(2));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[0].policy,
+ Eq(Overlayable::Policy::kProduct));
+ ASSERT_THAT(result.value().entry->overlayable_declarations[1].policy,
+ Eq(Overlayable::Policy::kProductServices));
+}
+
+TEST_F(TableMergerTest, AddDuplicateOverlayableFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneFirstFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", {})
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
+TEST_F(TableMergerTest, AddOverlayablePolicyAndNoneLastFail) {
+ std::unique_ptr<ResourceTable> table_a =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", Overlayable::Policy::kProduct)
+ .Build();
+
+ std::unique_ptr<ResourceTable> table_b =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.a", 0x7f)
+ .AddOverlayable("bool/foo", {})
+ .Build();
+
+ ResourceTable final_table;
+ TableMergerOptions options;
+ options.auto_add_overlay = true;
+ TableMerger merger(context_.get(), &final_table, options);
+ ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
+ ASSERT_FALSE(merger.Merge({}, table_b.get(), false /*overlay*/));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index f33ae31..03b59e0 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -135,6 +135,15 @@
return *this;
}
+ResourceTableBuilder& ResourceTableBuilder::AddOverlayable(const StringPiece& name,
+ const Maybe<Overlayable::Policy> p) {
+ ResourceName res_name = ParseNameOrDie(name);
+ Overlayable overlayable;
+ overlayable.policy = p;
+ CHECK(table_->AddOverlayable(res_name, overlayable, GetDiagnostics()));
+ return *this;
+}
+
StringPool* ResourceTableBuilder::string_pool() {
return &table_->string_pool;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 9159599..d68c24d 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -73,6 +73,8 @@
const ResourceId& id, std::unique_ptr<Value> value);
ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
Visibility::Level level, bool allow_new = false);
+ ResourceTableBuilder& AddOverlayable(const android::StringPiece& name,
+ Maybe<Overlayable::Policy> policy);
StringPool* string_pool();
std::unique_ptr<ResourceTable> Build();
diff --git a/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
new file mode 100644
index 0000000..f472a02
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.INetworkRequestUserSelectionCallback;
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for network request match callback.
+ *
+ * @hide
+ */
+oneway interface INetworkRequestMatchCallback
+{
+ void onUserSelectionCallbackRegistration(in INetworkRequestUserSelectionCallback userSelectionCallback);
+
+ void onMatch(in List<WifiConfiguration> wificonfigurations);
+
+ void onUserSelectionConnectSuccess(in WifiConfiguration wificonfiguration);
+
+ void onUserSelectionConnectFailure(in WifiConfiguration wificonfiguration);
+}
diff --git a/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
new file mode 100644
index 0000000..524cefb
--- /dev/null
+++ b/wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Interface for providing user selection in response to
+ * network request match callback.
+ * @hide
+ */
+oneway interface INetworkRequestUserSelectionCallback
+{
+ void select(in WifiConfiguration wificonfiguration);
+
+ void reject();
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 12f50c8..1fd68ec 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -25,6 +25,7 @@
import android.net.DhcpInfo;
import android.net.Network;
+import android.net.wifi.INetworkRequestMatchCallback;
import android.net.wifi.ISoftApCallback;
import android.net.wifi.ITrafficStateCallback;
import android.net.wifi.PasspointManagementObjectDefinition;
@@ -185,5 +186,9 @@
void registerTrafficStateCallback(in IBinder binder, in ITrafficStateCallback callback, int callbackIdentifier);
void unregisterTrafficStateCallback(int callbackIdentifier);
+
+ void registerNetworkRequestMatchCallback(in IBinder binder, in INetworkRequestMatchCallback callback, int callbackIdentifier);
+
+ void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0330614..0574716 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -47,7 +47,11 @@
/**
* A class representing a configured Wi-Fi network, including the
* security configuration.
+ *
+ * @deprecated Use {@link WifiNetworkConfigBuilder} to create {@link NetworkSpecifier} and
+ * {@link WifiNetworkSuggestion}. This will become a system use only object in the future.
*/
+@Deprecated
public class WifiConfiguration implements Parcelable {
private static final String TAG = "WifiConfiguration";
/**
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9adbe67..9ce5486 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -25,19 +25,17 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -52,7 +50,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import com.android.server.net.NetworkPinner;
import dalvik.system.CloseGuard;
@@ -1035,7 +1032,17 @@
* </ul>
* @return a list of network configurations in the form of a list
* of {@link WifiConfiguration} objects.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return an empty list.
*/
+ @Deprecated
public List<WifiConfiguration> getConfiguredNetworks() {
try {
ParceledListSlice<WifiConfiguration> parceledList =
@@ -1135,7 +1142,17 @@
* @return the ID of the newly created network description. This is used in
* other operations to specified the network to be acted upon.
* Returns {@code -1} on failure.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int addNetwork(WifiConfiguration config) {
if (config == null) {
return -1;
@@ -1160,7 +1177,17 @@
* Returns {@code -1} on failure, including when the {@code networkId}
* field of the {@code WifiConfiguration} does not refer to an
* existing network.
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return {@code -1}.
*/
+ @Deprecated
public int updateNetwork(WifiConfiguration config) {
if (config == null || config.networkId < 0) {
return -1;
@@ -1185,6 +1212,302 @@
}
/**
+ * Interface for indicating user selection from the list of networks presented in the
+ * {@link NetworkRequestMatchCallback#onMatch(List)}.
+ *
+ * The platform will implement this callback and pass it along with the
+ * {@link NetworkRequestMatchCallback#onUserSelectionCallbackRegistration(
+ * NetworkRequestUserSelectionCallback)}. The UI component handling
+ * {@link NetworkRequestMatchCallback} will invoke {@link #select(WifiConfiguration)} or
+ * {@link #reject()} to return the user's selection back to the platform via this callback.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestUserSelectionCallback {
+ /**
+ * User selected this network to connect to.
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void select(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * User rejected the app's request.
+ */
+ void reject();
+ }
+
+ /**
+ * Interface for network request callback. Should be implemented by applications and passed when
+ * calling {@link #registerNetworkRequestMatchCallback(NetworkRequestMatchCallback, Handler)}.
+ *
+ * This is meant to be implemented by a UI component to present the user with a list of networks
+ * matching the app's request. The user is allowed to pick one of these networks to connect to
+ * or reject the request by the app.
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkRequestMatchCallback {
+ /**
+ * Invoked to register a callback to be invoked to convey user selection. The callback
+ * object paased in this method is to be invoked by the UI component after the service sends
+ * a list of matching scan networks using {@link #onMatch(List)} and user picks a network
+ * from that list.
+ *
+ * @param userSelectionCallback Callback object to send back the user selection.
+ */
+ void onUserSelectionCallbackRegistration(
+ @NonNull NetworkRequestUserSelectionCallback userSelectionCallback);
+
+ /**
+ * Invoked when a network request initiated by an app matches some networks in scan results.
+ * This may be invoked multiple times for a single network request as the platform finds new
+ * networks in scan results.
+ *
+ * @param wifiConfigurations List of {@link WifiConfiguration} objects corresponding to the
+ * networks matching the request.
+ */
+ void onMatch(@NonNull List<WifiConfiguration> wifiConfigurations);
+
+ /**
+ * Invoked on a successful connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network that the
+ * user selected.
+ */
+ void onUserSelectionConnectSuccess(@NonNull WifiConfiguration wifiConfiguration);
+
+ /**
+ * Invoked on failure to establish connection with the network that the user selected
+ * via {@link NetworkRequestUserSelectionCallback}.
+ *
+ * @param wifiConfiguration WifiConfiguration object corresponding to the network
+ * user selected.
+ */
+ void onUserSelectionConnectFailure(@NonNull WifiConfiguration wifiConfiguration);
+ }
+
+ /**
+ * Callback proxy for NetworkRequestUserSelectionCallback objects.
+ * @hide
+ */
+ private class NetworkRequestUserSelectionCallbackProxy implements
+ NetworkRequestUserSelectionCallback {
+ private final INetworkRequestUserSelectionCallback mCallback;
+
+ NetworkRequestUserSelectionCallbackProxy(
+ INetworkRequestUserSelectionCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void select(@NonNull WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: select "
+ + "wificonfiguration: " + wifiConfiguration);
+ }
+ try {
+ mCallback.select(wifiConfiguration);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onSelected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void reject() {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestUserSelectionCallbackProxy: reject");
+ }
+ try {
+ mCallback.reject();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to invoke onRejected", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Callback proxy for NetworkRequestMatchCallback objects.
+ * @hide
+ */
+ private class NetworkRequestMatchCallbackProxy extends INetworkRequestMatchCallback.Stub {
+ private final Handler mHandler;
+ private final NetworkRequestMatchCallback mCallback;
+
+ NetworkRequestMatchCallbackProxy(Looper looper, NetworkRequestMatchCallback callback) {
+ mHandler = new Handler(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void onUserSelectionCallbackRegistration(
+ INetworkRequestUserSelectionCallback userSelectionCallback) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: "
+ + "onUserSelectionCallbackRegistration callback: " + userSelectionCallback);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionCallbackRegistration(
+ new NetworkRequestUserSelectionCallbackProxy(userSelectionCallback));
+ });
+ }
+
+ @Override
+ public void onMatch(List<WifiConfiguration> wifiConfigurations) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onMatch wificonfigurations: "
+ + wifiConfigurations);
+ }
+ mHandler.post(() -> {
+ mCallback.onMatch(wifiConfigurations);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectSuccess(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectSuccess "
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectSuccess(wifiConfiguration);
+ });
+ }
+
+ @Override
+ public void onUserSelectionConnectFailure(WifiConfiguration wifiConfiguration) {
+ if (mVerboseLoggingEnabled) {
+ Log.v(TAG, "NetworkRequestMatchCallbackProxy: onUserSelectionConnectFailure"
+ + " wificonfiguration: " + wifiConfiguration);
+ }
+ mHandler.post(() -> {
+ mCallback.onUserSelectionConnectFailure(wifiConfiguration);
+ });
+ }
+ }
+
+ /**
+ * Registers a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * Caller can unregister a previously registered callback using
+ * {@link #unregisterNetworkRequestMatchCallback(NetworkRequestMatchCallback)}
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @param handler The Handler on whose thread to execute the callbacks of the {@code callback}
+ * object. If null, then the application's main thread will be used.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void registerNetworkRequestMatchCallback(@NonNull NetworkRequestMatchCallback callback,
+ @Nullable Handler handler) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "registerNetworkRequestMatchCallback: callback=" + callback
+ + ", handler=" + handler);
+
+ Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
+ Binder binder = new Binder();
+ try {
+ mService.registerNetworkRequestMatchCallback(
+ binder, new NetworkRequestMatchCallbackProxy(looper, callback),
+ callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters a callback for NetworkRequest matches. See {@link NetworkRequestMatchCallback}.
+ * <p>
+ * Applications should have the
+ * {@link android.Manifest.permission#NETWORK_SETTINGS} permission. Callers
+ * without the permission will trigger a {@link java.lang.SecurityException}.
+ * <p>
+ *
+ * @param callback Callback for network match events
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void unregisterNetworkRequestMatchCallback(
+ @NonNull NetworkRequestMatchCallback callback) {
+ if (callback == null) throw new IllegalArgumentException("callback cannot be null");
+ Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
+
+ try {
+ mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Provide a list of network suggestions to the device. See {@link WifiNetworkSuggestion}
+ * for a detailed explanation of the parameters.
+ *<p>
+ * When the device decides to connect to one of the provided network suggestions, platform fires
+ * the associated {@code pendingIntent} if
+ * {@link WifiNetworkSuggestion#isAppInteractionRequired} is {@code true} and the
+ * provided {@code pendingIntent} is non-null.
+ *<p>
+ * Registration of a non-null pending intent {@code pendingIntent} requires
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission.
+ *<p>
+ * NOTE:
+ * <li> These networks are just a suggestion to the platform. The platform will ultimately
+ * decide on which network the device connects to. </li>
+ * <li> When an app is uninstalled, all its suggested networks are discarded. If the device is
+ * currently connected to a suggested network which is being removed then the device will
+ * disconnect from that network.</li>
+ * <li> No in-place modification of existing suggestions are allowed. Apps are expected to
+ * remove suggestions using {@link #removeNetworkSuggestions(List)} and then add the modified
+ * suggestion back using this API.</li>
+ *
+ * @param networkSuggestions List of network suggestions provided by the app.
+ * @param pendingIntent Pending intent to be fired post connection for networks. These will be
+ * fired only when connecting to a network which has the
+ * {@link WifiNetworkSuggestion#isAppInteractionRequired} flag set.
+ * Pending intent must hold a foreground service, else will be rejected.
+ * (i.e {@link PendingIntent#isForegroundService()} should return true)
+ * @return true on success, false if any of the suggestions match (See
+ * {@link WifiNetworkSuggestion#equals(Object)} any previously provided suggestions by the app.
+ * @throws {@link SecurityException} if the caller is missing required permissions.
+ */
+ public boolean addNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+ @Nullable PendingIntent pendingIntent) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+
+ /**
+ * Remove a subset of or all of networks from previously provided suggestions by the app to the
+ * device.
+ * See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
+ * See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
+ *
+ * @param networkSuggestions List of network suggestions to be removed. Pass an empty list
+ * to remove all the previous suggestions provided by the app.
+ * @return true on success, false if any of the suggestions do not match any suggestions
+ * previously provided by the app. Any matching suggestions are removed from the device and
+ * will not be considered for any further connection attempts.
+ */
+ public boolean removeNetworkSuggestions(
+ @NonNull List<WifiNetworkSuggestion> networkSuggestions) {
+ // TODO(b/115504887): Implementation
+ return false;
+ }
+
+ /**
* Add or update a Passpoint configuration. The configuration provides a credential
* for connecting to Passpoint networks that are operated by the Passpoint
* service provider specified in the configuration.
@@ -1299,7 +1622,17 @@
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean removeNetwork(int netId) {
try {
return mService.removeNetwork(netId, mContext.getOpPackageName());
@@ -1314,10 +1647,8 @@
* network is initiated. This may result in the asynchronous delivery
* of state change events.
* <p>
- * <b>Note:</b> If an application's target SDK version is
- * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
- * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
- * instead be sent through another network, such as cellular data,
+ * <b>Note:</b> Network communication may not use Wi-Fi even if Wi-Fi is connected;
+ * traffic may instead be sent through another network, such as cellular data,
* Bluetooth tethering, or Ethernet. For example, traffic will never use a
* Wi-Fi network that does not provide Internet access (e.g. a wireless
* printer), if another network that does offer Internet access (e.g.
@@ -1335,29 +1666,24 @@
* @param attemptConnect The way to select a particular network to connect to is specify
* {@code true} for this parameter.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
boolean success;
try {
success = mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
return success;
}
@@ -1372,7 +1698,17 @@
* @param netId the ID of the network as returned by {@link #addNetwork} or {@link
* #getConfiguredNetworks}.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disableNetwork(int netId) {
try {
return mService.disableNetwork(netId, mContext.getOpPackageName());
@@ -1385,7 +1721,17 @@
* Disassociate from the currently active access point. This may result
* in the asynchronous delivery of state change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean disconnect() {
try {
mService.disconnect(mContext.getOpPackageName());
@@ -1400,7 +1746,17 @@
* disconnected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reconnect() {
try {
mService.reconnect(mContext.getOpPackageName());
@@ -1415,7 +1771,17 @@
* connected. This may result in the asynchronous delivery of state
* change events.
* @return {@code true} if the operation succeeded
+ *
+ * @deprecated
+ * a) See {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for new
+ * mechanism to trigger connection to a Wi-Fi network.
+ * b) See {@link #addNetworkSuggestions(List, PendingIntent)},
+ * {@link #removeNetworkSuggestions(List)} for new API to add Wi-Fi networks for consideration
+ * when auto-connecting to wifi.
+ * <b>Compatibility Note:</b> For applications targeting
+ * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always return false.
*/
+ @Deprecated
public boolean reassociate() {
try {
mService.reassociate(mContext.getOpPackageName());
@@ -1821,7 +2187,12 @@
* @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
* either already in the requested state, or in progress toward the requested state.
* @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
+ *
+ * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
+ * enable/disable Wi-Fi regardless of application's target SDK. This API will have no effect
+ * and will always return false.
*/
+ @Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
new file mode 100644
index 0000000..55fde4ca
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkAgent;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used by wifi's {@link android.net.NetworkAgent}.
+ * @hide
+ */
+public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * Security credentials for the currently connected network.
+ */
+ private final WifiConfiguration mWifiConfiguration;
+
+ /**
+ * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
+ *
+ * Will only be filled when the device connects to a wifi network as a result of a
+ * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
+ * auto-connected to a wifi network.
+ */
+ private final int mOriginalRequestorUid;
+
+ public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
+ int originalRequestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ mWifiConfiguration = wifiConfiguration;
+ mOriginalRequestorUid = originalRequestorUid;
+ }
+
+ /**
+ * @hide
+ */
+ public static final Creator<WifiNetworkAgentSpecifier> CREATOR =
+ new Creator<WifiNetworkAgentSpecifier>() {
+ @Override
+ public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int originalRequestorUid = in.readInt();
+ return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
+ }
+
+ @Override
+ public WifiNetworkAgentSpecifier[] newArray(int size) {
+ return new WifiNetworkAgentSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mWifiConfiguration, flags);
+ dest.writeInt(mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(@Nullable NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkSpecifier) {
+ return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other);
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be "
+ + "compared");
+ }
+ return false;
+ }
+
+ /**
+ * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
+ * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
+ */
+ public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
+ // None of these should be null by construction.
+ // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}.
+ // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}.
+ checkNotNull(ns);
+ checkNotNull(ns.ssidPatternMatcher);
+ checkNotNull(ns.bssidPatternMatcher);
+ checkNotNull(ns.wifiConfiguration.allowedKeyManagement);
+ checkNotNull(this.mWifiConfiguration.SSID);
+ checkNotNull(this.mWifiConfiguration.BSSID);
+ checkNotNull(this.mWifiConfiguration.allowedKeyManagement);
+
+ final String ssidWithQuotes = this.mWifiConfiguration.SSID;
+ checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
+ final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
+ if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) {
+ return false;
+ }
+ final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID);
+ final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first;
+ final MacAddress matchMask = ns.bssidPatternMatcher.second;
+ if (!bssid.matches(matchBaseAddress, matchMask)) {
+ return false;
+ }
+ if (!ns.wifiConfiguration.allowedKeyManagement.equals(
+ this.mWifiConfiguration.allowedKeyManagement)) {
+ return false;
+ }
+ if (ns.requestorUid != this.mOriginalRequestorUid) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mWifiConfiguration.SSID,
+ mWifiConfiguration.BSSID,
+ mWifiConfiguration.allowedKeyManagement,
+ mOriginalRequestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkAgentSpecifier)) {
+ return false;
+ }
+ WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj;
+ return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
+ && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
+ && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
+ lhs.mWifiConfiguration.allowedKeyManagement)
+ && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
+ sb.append(", WifiConfiguration=").append(
+ mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
+ .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
+ .append("]");
+ return sb.toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
+ + "for requests.");
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
new file mode 100644
index 0000000..ae4f405
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.net.MacAddress;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * WifiNetworkConfigBuilder to use for creating Wi-Fi network configuration.
+ * <li>See {@link #buildNetworkSpecifier()} for creating a network specifier to use in
+ * {@link NetworkRequest}.</li>
+ * <li>See {@link #buildNetworkSuggestion()} for creating a network suggestion to use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.</li>
+ */
+public class WifiNetworkConfigBuilder {
+ private static final String MATCH_ALL_SSID_PATTERN_PATH = ".*";
+ private static final String MATCH_EMPTY_SSID_PATTERN_PATH = "";
+ private static final Pair<MacAddress, MacAddress> MATCH_NO_BSSID_PATTERN =
+ new Pair(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS);
+ private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
+ new Pair(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ private static final MacAddress MATCH_EXACT_BSSID_PATTERN_MASK =
+ MacAddress.BROADCAST_ADDRESS;
+ private static final int UNASSIGNED_PRIORITY = -1;
+
+ /**
+ * SSID pattern match specified by the app.
+ */
+ private @Nullable PatternMatcher mSsidPatternMatcher;
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher;
+ /**
+ * Pre-shared key for use with WPA-PSK networks.
+ */
+ private @Nullable String mPskPassphrase;
+ /**
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the EAP.
+ */
+ private @Nullable WifiEnterpriseConfig mEnterpriseConfig;
+ /**
+ * This is a network that does not broadcast its SSID, so an
+ * SSID-specific probe request must be used for scans.
+ */
+ private boolean mIsHiddenSSID;
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsAppInteractionRequired;
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ */
+ private boolean mIsUserInteractionRequired;
+ /**
+ * Whether this network is metered or not.
+ */
+ private boolean mIsMetered;
+ /**
+ * Priority of this network among other network suggestions provided by the app.
+ * The lower the number, the higher the priority (i.e value of 0 = highest priority).
+ */
+ private int mPriority;
+
+ public WifiNetworkConfigBuilder() {
+ mSsidPatternMatcher = null;
+ mBssidPatternMatcher = null;
+ mPskPassphrase = null;
+ mEnterpriseConfig = null;
+ mIsHiddenSSID = false;
+ mIsAppInteractionRequired = false;
+ mIsUserInteractionRequired = false;
+ mIsMetered = false;
+ mPriority = UNASSIGNED_PRIORITY;
+ }
+
+ /**
+ * Set the unicode SSID match pattern to use for filtering networks from scan results.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssidPattern Instance of {@link PatternMatcher} containing the UTF-8 encoded
+ * string pattern to use for matching the network's SSID.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setSsidPattern(@NonNull PatternMatcher ssidPattern) {
+ checkNotNull(ssidPattern);
+ mSsidPatternMatcher = ssidPattern;
+ return this;
+ }
+
+ /**
+ * Set the unicode SSID for the network.
+ * <p>
+ * <li>For network requests ({@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, sets the SSID to use for filtering networks from scan
+ * results. Will only match networks whose SSID is identical to the UTF-8 encoding of the
+ * specified value.</li>
+ * <li>For network suggestions ({@link WifiNetworkSuggestion}), built using
+ * {@link #buildNetworkSuggestion()}, sets the SSID for the network.</li>
+ * <li>Overrides any previous value set using {@link #setSsid(String)} or
+ * {@link #setSsidPattern(PatternMatcher)}.</li>
+ *
+ * @param ssid The SSID of the network. It must be valid Unicode.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the SSID is not valid unicode.
+ */
+ public WifiNetworkConfigBuilder setSsid(@NonNull String ssid) {
+ checkNotNull(ssid);
+ final CharsetEncoder unicodeEncoder = StandardCharsets.UTF_8.newEncoder();
+ if (!unicodeEncoder.canEncode(ssid)) {
+ throw new IllegalArgumentException("SSID is not a valid unicode string");
+ }
+ mSsidPatternMatcher = new PatternMatcher(ssid, PatternMatcher.PATTERN_LITERAL);
+ return this;
+ }
+
+ /**
+ * Set the BSSID match pattern to use for filtering networks from scan results.
+ * Will match all networks with BSSID which satisfies the following:
+ * {@code BSSID & mask == baseAddress}.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param baseAddress Base address for BSSID pattern.
+ * @param mask Mask for BSSID pattern.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssidPattern(
+ @NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
+ checkNotNull(baseAddress, mask);
+ mBssidPatternMatcher = Pair.create(baseAddress, mask);
+ return this;
+ }
+
+ /**
+ * Set the BSSID to use for filtering networks from scan results. Will only match network whose
+ * BSSID is identical to the specified value.
+ * <p>
+ * <li>Only allowed for creating network specifier, i.e {@link #buildNetworkSpecifier()}. </li>
+ * <li>Overrides any previous value set using {@link #setBssid(MacAddress)} or
+ * {@link #setBssidPattern(MacAddress, MacAddress)}.</li>
+ *
+ * @param bssid BSSID of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setBssid(@NonNull MacAddress bssid) {
+ checkNotNull(bssid);
+ mBssidPatternMatcher = Pair.create(bssid, MATCH_EXACT_BSSID_PATTERN_MASK);
+ return this;
+ }
+
+ /**
+ * Set the ASCII PSK passphrase for this network. Needed for authenticating to
+ * WPA_PSK networks.
+ *
+ * @param pskPassphrase PSK passphrase of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+ */
+ public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) {
+ checkNotNull(pskPassphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(pskPassphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ mPskPassphrase = pskPassphrase;
+ return this;
+ }
+
+ /**
+ * Set the associated enterprise configuration for this network. Needed for authenticating to
+ * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description.
+ *
+ * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setEnterpriseConfig(
+ @NonNull WifiEnterpriseConfig enterpriseConfig) {
+ checkNotNull(enterpriseConfig);
+ mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ return this;
+ }
+
+ /**
+ * Specifies whether this represents a hidden network.
+ * <p>
+ * <li>For network requests (see {@link NetworkSpecifier}), built using
+ * {@link #buildNetworkSpecifier}, setting this disallows the usage of
+ * {@link #setSsidPattern(PatternMatcher)} since hidden networks need to be explicitly
+ * probed for.</li>
+ * <li>If not set, defaults to false (i.e not a hidden network).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsHiddenSsid() {
+ mIsHiddenSSID = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the app needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} will be sent after
+ * successfully connecting to the network.
+ * Use this for captive portal type networks where the app needs to authenticate the user
+ * before the device can access the network.
+ * This setting will be ignored if the {@code PendingIntent} used to add this network
+ * suggestion is null.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no app interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsAppInteractionRequired() {
+ mIsAppInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specifies whether the user needs to log in to a captive portal to obtain Internet access.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e no user interaction required).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsUserInteractionRequired() {
+ mIsUserInteractionRequired = true;
+ return this;
+ }
+
+ /**
+ * Specify the priority of this network among other network suggestions provided by the same app
+ * (priorities have no impact on suggestions by different apps). The lower the number, the
+ * higher the priority (i.e value of 0 = highest priority).
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to -1 (i.e unassigned priority).</li>
+ *
+ * @param priority Integer number representing the priority among suggestions by the app.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the priority value is negative.
+ */
+ public WifiNetworkConfigBuilder setPriority(int priority) {
+ if (priority < 0) {
+ throw new IllegalArgumentException("Invalid priority value " + priority);
+ }
+ mPriority = priority;
+ return this;
+ }
+
+ /**
+ * Specifies whether this network is metered.
+ * <p>
+ * <li>Only allowed for creating network suggestion, i.e {@link #buildNetworkSuggestion()}.</li>
+ * <li>If not set, defaults to false (i.e not metered).</li>
+ *
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsMetered() {
+ mIsMetered = true;
+ return this;
+ }
+
+ /**
+ * Set defaults for the various low level credential type fields in the newly created
+ * WifiConfiguration object.
+ *
+ * See {@link com.android.server.wifi.WifiConfigManager#setDefaultsInWifiConfiguration(
+ * WifiConfiguration)}.
+ *
+ * @param configuration provided WifiConfiguration object.
+ */
+ private static void setDefaultsInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ configuration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
+ configuration.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ configuration.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+ }
+
+ private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ if (!TextUtils.isEmpty(mPskPassphrase)) {
+ // WPA_PSK network.
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ } else if (mEnterpriseConfig != null) {
+ // WPA_EAP network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+ } else {
+ // Open network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ }
+ }
+
+ /**
+ * Helper method to build WifiConfiguration object from the builder.
+ * @return Instance of {@link WifiConfiguration}.
+ */
+ private WifiConfiguration buildWifiConfiguration() {
+ final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ setDefaultsInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.SSID needs quotes around unicode SSID.
+ if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
+ wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
+ }
+ setKeyMgmtInWifiConfiguration(wifiConfiguration);
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ if (mPskPassphrase != null) {
+ wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\"";
+ }
+ wifiConfiguration.enterpriseConfig = mEnterpriseConfig;
+ wifiConfiguration.hiddenSSID = mIsHiddenSSID;
+ wifiConfiguration.priority = mPriority;
+ wifiConfiguration.meteredOverride =
+ mIsMetered ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NONE;
+ return wifiConfiguration;
+ }
+
+ private boolean hasSetAnyPattern() {
+ return mSsidPatternMatcher != null || mBssidPatternMatcher != null;
+ }
+
+ private void setMatchAnyPatternIfUnset() {
+ if (mSsidPatternMatcher == null) {
+ mSsidPatternMatcher = new PatternMatcher(MATCH_ALL_SSID_PATTERN_PATH,
+ PatternMatcher.PATTERN_SIMPLE_GLOB);
+ }
+ if (mBssidPatternMatcher == null) {
+ mBssidPatternMatcher = MATCH_ALL_BSSID_PATTERN;
+ }
+ }
+
+ private boolean hasSetMatchNonePattern() {
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_PREFIX
+ && mSsidPatternMatcher.getPath().equals(MATCH_EMPTY_SSID_PATTERN_PATH)) {
+ return true;
+ }
+ if (mBssidPatternMatcher.equals(MATCH_NO_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean hasSetMatchAllPattern() {
+ if ((mSsidPatternMatcher.match(MATCH_EMPTY_SSID_PATTERN_PATH))
+ && mBssidPatternMatcher.equals(MATCH_ALL_BSSID_PATTERN)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Create a specifier object used to request a Wi-Fi network. The generated
+ * {@link NetworkSpecifier} should be used in
+ * {@link NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} when building
+ * the {@link NetworkRequest}.
+ *<p>
+ * Note: Apps can set a combination of network match params:
+ * <li> SSID Pattern using {@link #setSsidPattern(PatternMatcher)} OR Specific SSID using
+ * {@link #setSsid(String)}. </li>
+ * AND/OR
+ * <li> BSSID Pattern using {@link #setBssidPattern(MacAddress, MacAddress)} OR Specific BSSID
+ * using {@link #setBssid(MacAddress)} </li>
+ * to trigger connection to a network that matches the set params.
+ * The system will find the set of networks matching the request and present the user
+ * with a system dialog which will allow the user to select a specific Wi-Fi network to connect
+ * to or to deny the request.
+ *</p>
+ *
+ * For example:
+ * To connect to an open network with a SSID prefix of "test" and a BSSID OUI of "10:03:23":
+ * {@code
+ * final NetworkSpecifier specifier =
+ * new WifiNetworkConfigBuilder()
+ * .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
+ * .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
+ * MacAddress.fromString("ff:ff:ff:00:00:00"))
+ * .buildNetworkSpecifier()
+ * final NetworkRequest request =
+ * new NetworkRequest.Builder()
+ * .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ * .setNetworkSpecifier(specifier)
+ * .build();
+ * final ConnectivityManager connectivityManager =
+ * context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ * final NetworkCallback networkCallback = new NetworkCallback() {
+ * ...
+ * @Override
+ * void onAvailable(...) {}
+ * // etc.
+ * };
+ * connectivityManager.requestNetwork(request, networkCallback);
+ * }
+ *
+ * @return Instance of {@link NetworkSpecifier}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public NetworkSpecifier buildNetworkSpecifier() {
+ if (!hasSetAnyPattern()) {
+ throw new IllegalStateException("one of setSsidPattern/setSsid/setBssidPattern/setBssid"
+ + " should be invoked for specifier");
+ }
+ setMatchAnyPatternIfUnset();
+ if (hasSetMatchNonePattern()) {
+ throw new IllegalStateException("cannot set match-none pattern for specifier");
+ }
+ if (hasSetMatchAllPattern()) {
+ throw new IllegalStateException("cannot set match-all pattern for specifier");
+ }
+ if (mIsHiddenSSID && mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL) {
+ throw new IllegalStateException("setSsid should also be invoked when "
+ + "setIsHiddenSsid is invoked for network specifier");
+ }
+ if (mIsAppInteractionRequired || mIsUserInteractionRequired
+ || mPriority != -1 || mIsMetered) {
+ throw new IllegalStateException("none of setIsAppInteractionRequired/"
+ + "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for "
+ + "specifier");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + " be invoked for network specifier");
+ }
+
+ return new WifiNetworkSpecifier(
+ mSsidPatternMatcher,
+ mBssidPatternMatcher,
+ buildWifiConfiguration(),
+ Process.myUid());
+ }
+
+ /**
+ * Create a network suggestion object use in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ * See {@link WifiNetworkSuggestion}.
+ *
+ * @return Instance of {@link WifiNetworkSuggestion}.
+ * @throws IllegalStateException on invalid params set.
+ */
+ public WifiNetworkSuggestion buildNetworkSuggestion() {
+ if (mSsidPatternMatcher == null) {
+ throw new IllegalStateException("setSsid should be invoked for suggestion");
+ }
+ if (mSsidPatternMatcher.getType() != PatternMatcher.PATTERN_LITERAL
+ || mBssidPatternMatcher != null) {
+ throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are"
+ + " allowed for suggestion");
+ }
+ if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
+ throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
+ + "be invoked for suggestion");
+ }
+
+ return new WifiNetworkSuggestion(
+ buildWifiConfiguration(),
+ mIsAppInteractionRequired,
+ mIsUserInteractionRequired,
+ Process.myUid());
+
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
new file mode 100644
index 0000000..4348399
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+import android.util.Pair;
+
+import java.util.Objects;
+
+/**
+ * Network specifier object used to request a Wi-Fi network. Apps should use the
+ * {@link WifiNetworkConfigBuilder} class to create an instance.
+ * @hide
+ */
+public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ /**
+ * SSID pattern match specified by the app.
+ */
+ public final PatternMatcher ssidPatternMatcher;
+
+ /**
+ * BSSID pattern match specified by the app.
+ * Pair of <BaseAddress, Mask>.
+ */
+ public final Pair<MacAddress, MacAddress> bssidPatternMatcher;
+
+ /**
+ * Security credentials for the network.
+ * <p>
+ * Note: {@link WifiConfiguration#SSID} & {@link WifiConfiguration#BSSID} fields from
+ * WifiConfiguration are not used. Instead we use the {@link #ssidPatternMatcher} &
+ * {@link #bssidPatternMatcher} fields embedded directly
+ * within {@link WifiNetworkSpecifier}.
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * The UID of the process initializing this network specifier. Validated by receiver using
+ * checkUidIfNecessary() and is used by satisfiedBy() to determine whether the specifier
+ * matches the offered network.
+ */
+ public final int requestorUid;
+
+ public WifiNetworkSpecifier(@NonNull PatternMatcher ssidPatternMatcher,
+ @NonNull Pair<MacAddress, MacAddress> bssidPatternMatcher,
+ @NonNull WifiConfiguration wifiConfiguration,
+ int requestorUid) {
+ checkNotNull(ssidPatternMatcher);
+ checkNotNull(bssidPatternMatcher);
+ checkNotNull(wifiConfiguration);
+
+ this.ssidPatternMatcher = ssidPatternMatcher;
+ this.bssidPatternMatcher = bssidPatternMatcher;
+ this.wifiConfiguration = wifiConfiguration;
+ this.requestorUid = requestorUid;
+ }
+
+ public static final Creator<WifiNetworkSpecifier> CREATOR =
+ new Creator<WifiNetworkSpecifier>() {
+ @Override
+ public WifiNetworkSpecifier createFromParcel(Parcel in) {
+ PatternMatcher ssidPatternMatcher = in.readParcelable(/* classLoader */null);
+ MacAddress baseAddress = in.readParcelable(null);
+ MacAddress mask = in.readParcelable(null);
+ Pair<MacAddress, MacAddress> bssidPatternMatcher =
+ Pair.create(baseAddress, mask);
+ WifiConfiguration wifiConfiguration = in.readParcelable(null);
+ int requestorUid = in.readInt();
+ return new WifiNetworkSpecifier(ssidPatternMatcher, bssidPatternMatcher,
+ wifiConfiguration, requestorUid);
+ }
+
+ @Override
+ public WifiNetworkSpecifier[] newArray(int size) {
+ return new WifiNetworkSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(ssidPatternMatcher, flags);
+ dest.writeParcelable(bssidPatternMatcher.first, flags);
+ dest.writeParcelable(bssidPatternMatcher.second, flags);
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeInt(requestorUid);
+ }
+
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ if (this == other) {
+ return true;
+ }
+ // Any generic requests should be satisifed by a specific wifi network.
+ if (other == null || other instanceof MatchAllNetworkSpecifier) {
+ return true;
+ }
+ if (other instanceof WifiNetworkAgentSpecifier) {
+ return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
+ }
+ // Specific requests are checked for equality although testing for equality of 2 patterns do
+ // not make much sense!
+ return equals(other);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ ssidPatternMatcher.getPath(),
+ ssidPatternMatcher.getType(),
+ bssidPatternMatcher,
+ wifiConfiguration.allowedKeyManagement,
+ requestorUid);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSpecifier)) {
+ return false;
+ }
+ WifiNetworkSpecifier lhs = (WifiNetworkSpecifier) obj;
+ return Objects.equals(this.ssidPatternMatcher.getPath(),
+ lhs.ssidPatternMatcher.getPath())
+ && Objects.equals(this.ssidPatternMatcher.getType(),
+ lhs.ssidPatternMatcher.getType())
+ && Objects.equals(this.bssidPatternMatcher,
+ lhs.bssidPatternMatcher)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && requestorUid == lhs.requestorUid;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("WifiNetworkSpecifierWifiNetworkSpecifier [")
+ .append(", SSID Match pattern=").append(ssidPatternMatcher)
+ .append(", BSSID Match pattern=").append(bssidPatternMatcher)
+ .append(", WifiConfiguration=").append(
+ wifiConfiguration == null ? null : wifiConfiguration.configKey())
+ .append(", requestorUid=").append(requestorUid)
+ .append("]")
+ .toString();
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ if (this.requestorUid != requestorUid) {
+ throw new SecurityException("mismatched UIDs");
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
new file mode 100644
index 0000000..04b9cb5
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.PendingIntent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Network Suggestion object is used to provide a Wi-Fi network for consideration when
+ * auto-connecting to networks. Apps cannot directly create this object, they must use
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} to obtain an instance
+ * of this object.
+ *<p>
+ * Apps can provide a list of such networks to the platform using
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)}.
+ */
+public final class WifiNetworkSuggestion implements Parcelable {
+ /**
+ * Network configuration for the provided network.
+ * @hide
+ */
+ public final WifiConfiguration wifiConfiguration;
+
+ /**
+ * Whether app needs to log in to captive portal to obtain Internet access.
+ * This will dictate if the associated pending intent in
+ * {@link WifiManager#addNetworkSuggestions(List, PendingIntent)} needs to be sent after
+ * successfully connecting to the network.
+ * @hide
+ */
+ public final boolean isAppInteractionRequired;
+
+ /**
+ * Whether user needs to log in to captive portal to obtain Internet access.
+ * @hide
+ */
+ public final boolean isUserInteractionRequired;
+
+ /**
+ * The UID of the process initializing this network suggestion.
+ * @hide
+ */
+ public final int suggestorUid;
+
+ /** @hide */
+ public WifiNetworkSuggestion(WifiConfiguration wifiConfiguration,
+ boolean isAppInteractionRequired,
+ boolean isUserInteractionRequired,
+ int suggestorUid) {
+ checkNotNull(wifiConfiguration);
+
+ this.wifiConfiguration = wifiConfiguration;
+ this.isAppInteractionRequired = isAppInteractionRequired;
+ this.isUserInteractionRequired = isUserInteractionRequired;
+ this.suggestorUid = suggestorUid;
+ }
+
+ public static final Creator<WifiNetworkSuggestion> CREATOR =
+ new Creator<WifiNetworkSuggestion>() {
+ @Override
+ public WifiNetworkSuggestion createFromParcel(Parcel in) {
+ return new WifiNetworkSuggestion(
+ in.readParcelable(null), // wifiConfiguration
+ in.readBoolean(), // isAppInteractionRequired
+ in.readBoolean(), // isUserInteractionRequired
+ in.readInt() // suggestorUid
+ );
+ }
+
+ @Override
+ public WifiNetworkSuggestion[] newArray(int size) {
+ return new WifiNetworkSuggestion[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(wifiConfiguration, flags);
+ dest.writeBoolean(isAppInteractionRequired);
+ dest.writeBoolean(isUserInteractionRequired);
+ dest.writeInt(suggestorUid);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.allowedKeyManagement,
+ suggestorUid);
+ }
+
+ /**
+ * Equals for network suggestions.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof WifiNetworkSuggestion)) {
+ return false;
+ }
+ WifiNetworkSuggestion lhs = (WifiNetworkSuggestion) obj;
+ return Objects.equals(this.wifiConfiguration.SSID, lhs.wifiConfiguration.SSID)
+ && Objects.equals(this.wifiConfiguration.allowedKeyManagement,
+ lhs.wifiConfiguration.allowedKeyManagement)
+ && suggestorUid == lhs.suggestorUid;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [")
+ .append(", WifiConfiguration=").append(wifiConfiguration)
+ .append(", isAppInteractionRequired=").append(isAppInteractionRequired)
+ .append(", isUserInteractionRequired=").append(isUserInteractionRequired)
+ .append(", suggestorUid=").append(suggestorUid)
+ .append("]");
+ return sb.toString();
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 045291b..529548f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -594,17 +594,17 @@
/** SSID of the network */
public String ssid;
/** Bitmask of the FLAG_XXX */
- public byte flags;
+ public byte flags = 0;
/** Bitmask of the ATUH_XXX */
- public byte authBitField;
+ public byte authBitField = 0;
+ /** frequencies on which the particular network needs to be scanned for */
+ public int[] frequencies = {};
/**
* default constructor for PnoNetwork
*/
public PnoNetwork(String ssid) {
this.ssid = ssid;
- flags = 0;
- authBitField = 0;
}
}
@@ -651,6 +651,7 @@
dest.writeString(networkList[i].ssid);
dest.writeByte(networkList[i].flags);
dest.writeByte(networkList[i].authBitField);
+ dest.writeIntArray(networkList[i].frequencies);
}
} else {
dest.writeInt(0);
@@ -677,6 +678,7 @@
PnoNetwork network = new PnoNetwork(ssid);
network.flags = in.readByte();
network.authBitField = in.readByte();
+ network.frequencies = in.createIntArray();
settings.networkList[i] = network;
}
return settings;
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index e40b657a..ea41bb3 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -43,6 +43,8 @@
import android.net.wifi.WifiManager.LocalOnlyHotspotObserver;
import android.net.wifi.WifiManager.LocalOnlyHotspotReservation;
import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription;
+import android.net.wifi.WifiManager.NetworkRequestMatchCallback;
+import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback;
import android.net.wifi.WifiManager.SoftApCallback;
import android.net.wifi.WifiManager.TrafficStateCallback;
import android.os.Handler;
@@ -59,6 +61,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+
/**
* Unit tests for {@link android.net.wifi.WifiManager}.
*/
@@ -67,16 +71,19 @@
private static final int ERROR_NOT_SET = -1;
private static final int ERROR_TEST_REASON = 5;
+ private static final int TEST_UID = 14553;
private static final String TEST_PACKAGE_NAME = "TestPackage";
private static final String TEST_COUNTRY_CODE = "US";
@Mock Context mContext;
- @Mock IWifiManager mWifiService;
+ @Mock
+ android.net.wifi.IWifiManager mWifiService;
@Mock ApplicationInfo mApplicationInfo;
@Mock WifiConfiguration mApConfig;
@Mock IBinder mAppBinder;
@Mock SoftApCallback mSoftApCallback;
@Mock TrafficStateCallback mTrafficStateCallback;
+ @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback;
private Handler mHandler;
private TestLooper mLooper;
@@ -1163,4 +1170,84 @@
assertEquals(1, altLooper.dispatchAll());
verify(mTrafficStateCallback).onStateChanged(TrafficStateCallback.DATA_ACTIVITY_INOUT);
}
+
+ /**
+ * Verify the call to registerNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void registerNetworkRequestMatchCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+
+ assertEquals(0, mLooper.dispatchAll());
+ callbackCaptor.getValue().onMatch(new ArrayList<WifiConfiguration>());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onMatch(anyList());
+
+ callbackCaptor.getValue().onUserSelectionConnectSuccess(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectSuccess(
+ any(WifiConfiguration.class));
+
+ callbackCaptor.getValue().onUserSelectionConnectFailure(new WifiConfiguration());
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionConnectFailure(
+ any(WifiConfiguration.class));
+ }
+
+ /**
+ * Verify the call to unregisterNetworkRequestMatchCallback goes to WifiServiceImpl.
+ */
+ @Test
+ public void unregisterNetworkRequestMatchCallbackCallGoesToWifiServiceImpl() throws Exception {
+ ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, mHandler);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), any(INetworkRequestMatchCallback.class),
+ callbackIdentifier.capture());
+
+ mWifiManager.unregisterNetworkRequestMatchCallback(mNetworkRequestMatchCallback);
+ verify(mWifiService).unregisterNetworkRequestMatchCallback(
+ eq((int) callbackIdentifier.getValue()));
+ }
+
+ /**
+ * Verify the call to NetworkRequestUserSelectionCallback goes to
+ * WifiServiceImpl.
+ */
+ @Test
+ public void networkRequestUserSelectionCallbackCallGoesToWifiServiceImpl()
+ throws Exception {
+ when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
+ ArgumentCaptor<INetworkRequestMatchCallback.Stub> callbackCaptor =
+ ArgumentCaptor.forClass(INetworkRequestMatchCallback.Stub.class);
+ mWifiManager.registerNetworkRequestMatchCallback(mNetworkRequestMatchCallback, null);
+ verify(mWifiService).registerNetworkRequestMatchCallback(
+ any(IBinder.class), callbackCaptor.capture(), anyInt());
+
+ INetworkRequestUserSelectionCallback iUserSelectionCallback =
+ mock(INetworkRequestUserSelectionCallback.class);
+ ArgumentCaptor<NetworkRequestUserSelectionCallback> userSelectionCallbackCaptor =
+ ArgumentCaptor.forClass(NetworkRequestUserSelectionCallback.class);
+ callbackCaptor.getValue().onUserSelectionCallbackRegistration(
+ iUserSelectionCallback);
+ assertEquals(1, mLooper.dispatchAll());
+ verify(mNetworkRequestMatchCallback).onUserSelectionCallbackRegistration(
+ userSelectionCallbackCaptor.capture());
+
+ WifiConfiguration selected = new WifiConfiguration();
+ userSelectionCallbackCaptor.getValue().select(selected);
+ verify(iUserSelectionCallback).select(selected);
+
+ userSelectionCallbackCaptor.getValue().reject();
+ verify(iUserSelectionCallback).reject();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
new file mode 100644
index 0000000..1b0007c
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkAgentSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkAgentSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final int TEST_UID_1 = 8;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_SSID_PATTERN = "Test";
+ private static final String TEST_SSID_1 = "456test";
+ private static final String TEST_BSSID = "12:12:12:aa:0b:c0";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID_1 = "aa:cc:12:aa:0b:c0";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierParcel() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkAgentSpecifier parcelSpecifier =
+ WifiNetworkAgentSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate that the NetworkAgentSpecifier cannot be used in a {@link NetworkRequest} by apps.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierNotUsedInNetworkRequest() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ specifier.assertValidFromUid(TEST_UID);
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 equals specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierEqualsSame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotEqualsWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different SSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.SSID = TEST_SSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier equals between instances of {@link WifiNetworkAgentSpecifier}.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with different BSSID.
+ * c) Ensure that the specifier 2 does not equal specifier 1.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifyWhenBssidDifferent() {
+ WifiConfiguration wifiConfiguration1 = createDefaultWifiConfiguration();
+ WifiNetworkAgentSpecifier specifier1 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration(wifiConfiguration1);
+ wifiConfiguration2.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier specifier2 =
+ new WifiNetworkAgentSpecifier(
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.equals(specifier1));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching.
+ * a) Create a network agent specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkAgentSpecifierSatisifiesNullAndAllMatch() {
+ WifiNetworkAgentSpecifier specifier = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkAgentSpecifier matching with itself.
+ * a) Create network agent specifier 1 for WPA_PSK network
+ * b) Create network agent specifier 2 with the same params as specifier 1.
+ * c) Ensure that invoking {@link NetworkSpecifier#satisfiedBy(NetworkSpecifier)} on 2
+ * {@link WifiNetworkAgentSpecifier} throws an exception.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkAgentSpecifierDoesNotSatisifySame() {
+ WifiNetworkAgentSpecifier specifier1 = createDefaultNetworkAgentSpecifier();
+ WifiNetworkAgentSpecifier specifier2 = createDefaultNetworkAgentSpecifier();
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID & BSSID pattern.
+ * c) Ensure that the agent specifier is satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierSatisfiesNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertTrue(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertTrue(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.SSID = "\"" + TEST_SSID_1 + "\"";
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS);
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching BSSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with non-matching SSID and BSSID pattern.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithSsidAndBssidPattern() {
+ WifiConfiguration wifiConfigurationNetworkAgent = createDefaultWifiConfiguration();
+ wifiConfigurationNetworkAgent.BSSID = TEST_BSSID_1;
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier =
+ new WifiNetworkAgentSpecifier(
+ wifiConfigurationNetworkAgent,
+ TEST_UID);
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different key mgmt.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentKeyMgmt() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ /**
+ * Validate {@link WifiNetworkAgentSpecifier} with {@link WifiNetworkSpecifier} matching.
+ * a) Create network agent specifier for WPA_PSK network
+ * b) Create network specifier with matching SSID and BSSID pattern, but different UID.
+ * c) Ensure that the agent specifier is not satisfied by specifier.
+ */
+ @Test
+ public void
+ testWifiNetworkAgentSpecifierDoesNotSatisfyNetworkSpecifierWithDifferentUid() {
+ WifiNetworkAgentSpecifier wifiNetworkAgentSpecifier = createDefaultNetworkAgentSpecifier();
+
+ PatternMatcher ssidPattern =
+ new PatternMatcher(TEST_SSID_PATTERN, PatternMatcher.PATTERN_PREFIX);
+ Pair<MacAddress, MacAddress> bssidPattern =
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK));
+ WifiConfiguration wificonfigurationNetworkSpecifier = new WifiConfiguration();
+ wificonfigurationNetworkSpecifier.allowedKeyManagement
+ .set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier(
+ ssidPattern,
+ bssidPattern,
+ wificonfigurationNetworkSpecifier,
+ TEST_UID_1);
+
+ assertFalse(wifiNetworkSpecifier.satisfiedBy(wifiNetworkAgentSpecifier));
+ assertFalse(wifiNetworkAgentSpecifier.satisfiedBy(wifiNetworkSpecifier));
+ }
+
+ private WifiConfiguration createDefaultWifiConfiguration() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.SSID = "\"" + TEST_SSID + "\"";
+ wifiConfiguration.BSSID = TEST_BSSID;
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ return wifiConfiguration;
+ }
+
+ private WifiNetworkAgentSpecifier createDefaultNetworkAgentSpecifier() {
+ return new WifiNetworkAgentSpecifier(createDefaultWifiConfiguration(), TEST_UID);
+ }
+
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
new file mode 100644
index 0000000..8980ddb
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.NetworkSpecifier;
+import android.os.PatternMatcher;
+import android.os.Process;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkConfigBuilder}.
+ */
+@SmallTest
+public class WifiNetworkConfigBuilderTest {
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_BSSID = "12:12:12:12:12:12";
+ private static final String TEST_PRESHARED_KEY = "Test123";
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for open network with SSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForOpenNetworkWithSsidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(Process.myUid(), wifiNetworkSpecifier.requestorUid);
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_PREFIX, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_PSK network with BSSID
+ * pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() {
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(".*", wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_SIMPLE_GLOB, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.fromString(TEST_BSSID_OUI_MASK),
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ wifiNetworkSpecifier.wifiConfiguration.preSharedKey);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSpecifier object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} for WPA_EAP network with
+ * SSID and BSSID pattern.
+ */
+ @Test
+ public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+
+ NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .setEnterpriseConfig(enterpriseConfig)
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+
+ assertTrue(specifier instanceof WifiNetworkSpecifier);
+ WifiNetworkSpecifier wifiNetworkSpecifier = (WifiNetworkSpecifier) specifier;
+
+ assertEquals(TEST_SSID, wifiNetworkSpecifier.ssidPatternMatcher.getPath());
+ assertEquals(PATTERN_LITERAL, wifiNetworkSpecifier.ssidPatternMatcher.getType());
+ assertEquals(MacAddress.fromString(TEST_BSSID),
+ wifiNetworkSpecifier.bssidPatternMatcher.first);
+ assertEquals(MacAddress.BROADCAST_ADDRESS,
+ wifiNetworkSpecifier.bssidPatternMatcher.second);
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_EAP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.IEEE8021X));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedProtocols
+ .get(WifiConfiguration.Protocol.RSN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedAuthAlgorithms
+ .get(WifiConfiguration.AuthAlgorithm.OPEN));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedPairwiseCiphers
+ .get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.TKIP));
+ assertTrue(wifiNetworkSpecifier.wifiConfiguration.hiddenSSID);
+ assertEquals(enterpriseConfig.getEapMethod(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getEapMethod());
+ assertEquals(enterpriseConfig.getPhase2Method(),
+ wifiNetworkSpecifier.wifiConfiguration.enterpriseConfig.getPhase2Method());
+ }
+
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setSsid(String)} throws an exception
+ * when the string is not Unicode.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetSsidWithNonUnicodeString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid("\ud800")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception
+ * when the string is not ASCII encodable.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetPskPassphraseWithNonAsciiString() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase("salvē")
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when neither SSID nor BSSID patterns were set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithNoSsidAndBssidPattern() {
+ new WifiNetworkConfigBuilder().buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern1() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_SIMPLE_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern2() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(".*", PatternMatcher.PATTERN_ADVANCED_GLOB))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllSsidPattern3() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_PREFIX))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-all BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchAllBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none SSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher("", PatternMatcher.PATTERN_LITERAL))
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when match-none BSSID pattern is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMatchNoneBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.BROADCAST_ADDRESS, MacAddress.BROADCAST_ADDRESS)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBssidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setEnterpriseConfig(new WifiEnterpriseConfig())
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when SSID pattern is set for hidden network.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PatternMatcher.PATTERN_PREFIX))
+ .setIsHiddenSsid()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsAppInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredAppInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsAppInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsUserInteractionRequired()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithRequiredUserInteraction() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsUserInteractionRequired()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setPriority(int)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithSetPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setPriority(4)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setIsMetered()} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithMetered() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setIsMetered()
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for Open network which requires
+ * app interaction.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setIsAppInteractionRequired()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.NONE));
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_EAP network which requires
+ * app interaction and has a priority of zero set.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsAppInteractionRequired()
+ .setPriority(0)
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.isAppInteractionRequired);
+ assertFalse(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(0, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for WPA_PSK network which requires
+ * user interaction and is metered.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setIsUserInteractionRequired()
+ .setIsMetered()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertFalse(suggestion.isAppInteractionRequired);
+ assertTrue(suggestion.isUserInteractionRequired);
+ assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+ suggestion.wifiConfiguration.meteredOverride);
+ assertEquals(-1, suggestion.wifiConfiguration.priority);
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithSsidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssid(MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssidPattern() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssidPattern(MacAddress.fromString(TEST_BSSID),
+ MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setBssidPattern(MacAddress, MacAddress)} is set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithBssid() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setBssid(MacAddress.fromString(TEST_BSSID))
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
+ * when {@link WifiNetworkConfigBuilder#setSsid(String)} is not set.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSuggestionBuilderWithNoSsid() {
+ new WifiNetworkConfigBuilder()
+ .buildNetworkSuggestion();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#setPriority(int)} throws an exception
+ * when the value is negative.
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testWifiNetworkSuggestionBuilderWithInvalidPriority() {
+ new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setPriority(-1)
+ .buildNetworkSuggestion();
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
new file mode 100644
index 0000000..856f0c7
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.net.MacAddress;
+import android.net.MatchAllNetworkSpecifier;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.support.test.filters.SmallTest;
+import android.util.Pair;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSpecifier}.
+ */
+@SmallTest
+public class WifiNetworkSpecifierTest {
+ private static final int TEST_UID = 5;
+ private static final String TEST_SSID = "Test123";
+ private static final String TEST_BSSID_OUI_BASE_ADDRESS = "12:12:12:00:00:00";
+ private static final String TEST_BSSID_OUI_MASK = "ff:ff:ff:00:00:00";
+ private static final String TEST_PRESHARED_KEY = "\"Test123\"";
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSpecifierParcel() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ Parcel parcelW = Parcel.obtain();
+ specifier.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSpecifier parcelSpecifier =
+ WifiNetworkSpecifier.CREATOR.createFromParcel(parcelR);
+
+ assertEquals(specifier, parcelSpecifier);
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create a network specifier for WPA_PSK network
+ * b) Ensure that the specifier matches {@code null} and {@link MatchAllNetworkSpecifier}
+ * specifiers.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesNullAndAllMatch() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+ WifiNetworkSpecifier specifier =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier.satisfiedBy(null));
+ assertTrue(specifier.satisfiedBy(new MatchAllNetworkSpecifier()));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with the same params as specifier 1.
+ * c) Ensure that the specifier 2 is satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierSatisfiesSame() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertTrue(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different key mgmt params.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenKeyMgmtDifferent() {
+ WifiConfiguration wifiConfiguration1 = new WifiConfiguration();
+ wifiConfiguration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration1.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration1,
+ TEST_UID);
+
+ WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
+ wifiConfiguration2.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration2,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different SSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenSsidDifferent() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher("", PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+
+ /**
+ * Validate NetworkSpecifier matching.
+ * a) Create network specifier 1 for WPA_PSK network
+ * b) Create network specifier 2 with different BSSID pattern.
+ * c) Ensure that the specifier 2 is not satisfied by specifier 1.
+ */
+ @Test
+ public void testWifiNetworkSpecifierDoesNotSatisfyWhenBssidDifferent() {
+ WifiConfiguration wifiConfiguration = new WifiConfiguration();
+ wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ wifiConfiguration.preSharedKey = TEST_PRESHARED_KEY;
+
+ WifiNetworkSpecifier specifier1 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
+ MacAddress.fromString(TEST_BSSID_OUI_MASK)),
+ wifiConfiguration,
+ TEST_UID);
+
+ WifiNetworkSpecifier specifier2 =
+ new WifiNetworkSpecifier(new PatternMatcher(TEST_SSID, PATTERN_LITERAL),
+ Pair.create(MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS),
+ wifiConfiguration,
+ TEST_UID);
+
+ assertFalse(specifier2.satisfiedBy(specifier1));
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
new file mode 100644
index 0000000..6bab60d
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.*;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiNetworkSuggestion}.
+ */
+@SmallTest
+public class WifiNetworkSuggestionTest {
+ private static final String TEST_SSID = "\"Test123\"";
+ private static final String TEST_SSID_1 = "\"Test1234\"";
+
+ /**
+ * Check that parcel marshalling/unmarshalling works
+ */
+ @Test
+ public void testWifiNetworkSuggestionParcel() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, true, 0);
+
+ Parcel parcelW = Parcel.obtain();
+ suggestion.writeToParcel(parcelW, 0);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+ WifiNetworkSuggestion parcelSuggestion =
+ WifiNetworkSuggestion.CREATOR.createFromParcel(parcelR);
+
+ // Two suggestion objects are considered equal if they point to the same network (i.e same
+ // SSID + keyMgmt + same UID). |isAppInteractionRequired| & |isUserInteractionRequired| are
+ // not considered for equality and hence needs to be checked for explicitly below.
+ assertEquals(suggestion, parcelSuggestion);
+ assertEquals(suggestion.isAppInteractionRequired,
+ parcelSuggestion.isAppInteractionRequired);
+ assertEquals(suggestion.isUserInteractionRequired,
+ parcelSuggestion.isUserInteractionRequired);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code true} for 2 network suggestions with the same
+ * SSID, key mgmt and UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsSame() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, true, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, true, 0);
+
+ assertEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * key mgmt and UID, but different SSID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenSsidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID_1;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and UID, but different key mgmt.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenKeyMgmtIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiConfiguration configuration1 = new WifiConfiguration();
+ configuration1.SSID = TEST_SSID;
+ configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration1, false, false, 0);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+
+ /**
+ * Check NetworkSuggestion equals returns {@code false} for 2 network suggestions with the same
+ * SSID and key mgmt, but different UID.
+ */
+ @Test
+ public void testWifiNetworkSuggestionEqualsFailsWhenUidIsDifferent() {
+ WifiConfiguration configuration = new WifiConfiguration();
+ configuration.SSID = TEST_SSID;
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+ WifiNetworkSuggestion suggestion =
+ new WifiNetworkSuggestion(configuration, false, false, 0);
+
+ WifiNetworkSuggestion suggestion1 =
+ new WifiNetworkSuggestion(configuration, false, false, 1);
+
+ assertNotEquals(suggestion, suggestion1);
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index 96d5a51..da42dcf 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -17,16 +17,20 @@
package android.net.wifi;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.validateMockitoUsage;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.net.wifi.WifiScanner.PnoSettings;
+import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
+import android.net.wifi.WifiScanner.ScanSettings;
import android.os.Handler;
import android.os.Parcel;
import android.os.test.TestLooper;
import android.support.test.filters.SmallTest;
-import android.net.wifi.WifiScanner.ScanSettings;
import com.android.internal.util.test.BidirectionalAsyncChannelServer;
@@ -36,6 +40,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
/**
* Unit tests for {@link android.net.wifi.WifiScanner}.
@@ -47,6 +53,19 @@
@Mock
private IWifiScanner mService;
+ private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
+ private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
+ private static final int TEST_PNOSETTINGS_MIN_2GHZ_RSSI = -70;
+ private static final int TEST_PNOSETTINGS_INITIAL_SCORE_MAX = 50;
+ private static final int TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS = 10;
+ private static final int TEST_PNOSETTINGS_SAME_NETWORK_BONUS = 11;
+ private static final int TEST_PNOSETTINGS_SECURE_BONUS = 12;
+ private static final int TEST_PNOSETTINGS_BAND_5GHZ_BONUS = 13;
+ private static final String TEST_SSID_1 = "TEST1";
+ private static final String TEST_SSID_2 = "TEST2";
+ private static final int[] TEST_FREQUENCIES_1 = {};
+ private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+
private WifiScanner mWifiScanner;
private TestLooper mLooper;
private Handler mHandler;
@@ -120,4 +139,68 @@
return ScanSettings.CREATOR.createFromParcel(parcel);
}
+ /**
+ * PnoSettings object can be serialized and deserialized, while keeping the
+ * values unchanged.
+ */
+ @Test
+ public void canSerializeAndDeserializePnoSettings() throws Exception {
+
+ PnoSettings pnoSettings = new PnoSettings();
+
+ PnoNetwork pnoNetwork1 = new PnoNetwork(TEST_SSID_1);
+ PnoNetwork pnoNetwork2 = new PnoNetwork(TEST_SSID_2);
+ pnoNetwork1.frequencies = TEST_FREQUENCIES_1;
+ pnoNetwork2.frequencies = TEST_FREQUENCIES_2;
+
+ pnoSettings.networkList = new PnoNetwork[]{pnoNetwork1, pnoNetwork2};
+ pnoSettings.isConnected = TEST_PNOSETTINGS_IS_CONNECTED;
+ pnoSettings.min5GHzRssi = TEST_PNOSETTINGS_MIN_5GHZ_RSSI;
+ pnoSettings.min24GHzRssi = TEST_PNOSETTINGS_MIN_2GHZ_RSSI;
+ pnoSettings.initialScoreMax = TEST_PNOSETTINGS_INITIAL_SCORE_MAX;
+ pnoSettings.currentConnectionBonus = TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS;
+ pnoSettings.sameNetworkBonus = TEST_PNOSETTINGS_SAME_NETWORK_BONUS;
+ pnoSettings.secureBonus = TEST_PNOSETTINGS_SECURE_BONUS;
+ pnoSettings.band5GHzBonus = TEST_PNOSETTINGS_BAND_5GHZ_BONUS;
+
+ Parcel parcel = Parcel.obtain();
+ pnoSettings.writeToParcel(parcel, 0);
+ // Rewind the pointer to the head of the parcel.
+ parcel.setDataPosition(0);
+ PnoSettings pnoSettingsDeserialized =
+ pnoSettings.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(pnoSettingsDeserialized);
+ assertEquals(TEST_PNOSETTINGS_IS_CONNECTED, pnoSettingsDeserialized.isConnected);
+ assertEquals(TEST_PNOSETTINGS_MIN_5GHZ_RSSI, pnoSettingsDeserialized.min5GHzRssi);
+ assertEquals(TEST_PNOSETTINGS_MIN_2GHZ_RSSI, pnoSettingsDeserialized.min24GHzRssi);
+ assertEquals(TEST_PNOSETTINGS_INITIAL_SCORE_MAX, pnoSettingsDeserialized.initialScoreMax);
+ assertEquals(TEST_PNOSETTINGS_CURRENT_CONNECTION_BONUS,
+ pnoSettingsDeserialized.currentConnectionBonus);
+ assertEquals(TEST_PNOSETTINGS_SAME_NETWORK_BONUS,
+ pnoSettingsDeserialized.sameNetworkBonus);
+ assertEquals(TEST_PNOSETTINGS_SECURE_BONUS, pnoSettingsDeserialized.secureBonus);
+ assertEquals(TEST_PNOSETTINGS_BAND_5GHZ_BONUS, pnoSettingsDeserialized.band5GHzBonus);
+
+ // Test parsing of PnoNetwork
+ assertEquals(pnoSettings.networkList.length, pnoSettingsDeserialized.networkList.length);
+ for (int i = 0; i < pnoSettings.networkList.length; i++) {
+ PnoNetwork expected = pnoSettings.networkList[i];
+ PnoNetwork actual = pnoSettingsDeserialized.networkList[i];
+ assertEquals(expected.ssid, actual.ssid);
+ assertEquals(expected.flags, actual.flags);
+ assertEquals(expected.authBitField, actual.authBitField);
+ assertTrue(Arrays.equals(expected.frequencies, actual.frequencies));
+ }
+ }
+
+ /**
+ * Make sure that frequencies is not null by default.
+ */
+ @Test
+ public void pnoNetworkFrequencyIsNotNull() throws Exception {
+ PnoNetwork pnoNetwork = new PnoNetwork(TEST_SSID_1);
+ assertNotNull(pnoNetwork.frequencies);
+ }
+
}