diff options
198 files changed, 5082 insertions, 2031 deletions
diff --git a/api/current.txt b/api/current.txt index ea6f190ca44c..99ea60f71926 100755 --- a/api/current.txt +++ b/api/current.txt @@ -29000,11 +29000,14 @@ package android.net.wifi { method public boolean is5GHzBandSupported(); method public boolean isDeviceToApRttSupported(); method public boolean isEnhancedPowerReportingSupported(); + method public boolean isOweSupported(); method public boolean isP2pSupported(); method public boolean isPreferredNetworkOffloadSupported(); method public deprecated boolean isScanAlwaysAvailable(); method public boolean isTdlsSupported(); method public boolean isWifiEnabled(); + method public boolean isWpa3SaeSupported(); + method public boolean isWpa3SuiteBSupported(); method public deprecated boolean pingSupplicant(); method public deprecated boolean reassociate(); method public deprecated boolean reconnect(); @@ -43326,6 +43329,7 @@ package android.telephony { public class PhoneStateListener { ctor public PhoneStateListener(); + ctor public PhoneStateListener(java.util.concurrent.Executor); method public void onCallForwardingIndicatorChanged(boolean); method public void onCallStateChanged(int, java.lang.String); method public void onCellInfoChanged(java.util.List<android.telephony.CellInfo>); diff --git a/api/system-current.txt b/api/system-current.txt index 2c2df81254cd..8eb55074e6af 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -137,6 +137,7 @@ package android { field public static final java.lang.String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE"; field public static final java.lang.String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT"; field public static final java.lang.String QUERY_TIME_ZONE_RULES = "android.permission.QUERY_TIME_ZONE_RULES"; + field public static final java.lang.String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; field public static final java.lang.String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS"; field public static final java.lang.String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE"; field public static final java.lang.String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS"; @@ -5461,6 +5462,7 @@ package android.telephony { method public static android.os.PersistableBundle getDefaultConfig(); method public void overrideConfig(int, android.os.PersistableBundle); method public void updateConfigForPhoneId(int, java.lang.String); + field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; field public static final java.lang.String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; } @@ -5535,8 +5537,10 @@ package android.telephony { public class PhoneStateListener { method public void onRadioPowerStateChanged(int); method public void onSrvccStateChanged(int); + method public void onVoiceActivationStateChanged(int); field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000 field public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000 + field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000 } public class ServiceState implements android.os.Parcelable { @@ -6600,6 +6604,22 @@ package android.telephony.ims { method public void receiveSessionModifyResponse(int, android.telecom.VideoProfile, android.telecom.VideoProfile); } + public class ProvisioningManager { + method public static android.telephony.ims.ProvisioningManager createForSubscriptionId(android.content.Context, int); + method public int getProvisioningIntValue(int); + method public java.lang.String getProvisioningStringValue(int); + method public void registerProvisioningChangedCallback(java.util.concurrent.Executor, android.telephony.ims.ProvisioningManager.Callback); + method public int setProvisioningIntValue(int, int); + method public int setProvisioningStringValue(int, java.lang.String); + method public void unregisterProvisioningChangedCallback(android.telephony.ims.ProvisioningManager.Callback); + } + + public static class ProvisioningManager.Callback { + ctor public ProvisioningManager.Callback(); + method public void onProvisioningIntChanged(int, int); + method public void onProvisioningStringChanged(int, java.lang.String); + } + } package android.telephony.ims.feature { diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index eb498f596141..a9819972cfc7 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -370,11 +370,9 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, // This skips the uid map if it's an empty config. if (it->second->getNumMetrics() > 0) { uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP); - if (it->second->hashStringInReport()) { - mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto); - } else { - mUidMap->appendUidMap(dumpTimeStampNs, key, nullptr, proto); - } + mUidMap->appendUidMap( + dumpTimeStampNs, key, it->second->hashStringInReport() ? &str_set : nullptr, + it->second->versionStringsInReport(), it->second->installerInReport(), proto); proto->end(uidMapToken); } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 27685fc108a0..7fa05be29b9d 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -787,21 +787,24 @@ status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) { } Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version, - const vector<String16>& app) { + const vector<String16>& version_string, + const vector<String16>& app, + const vector<String16>& installer) { ENFORCE_UID(AID_SYSTEM); VLOG("StatsService::informAllUidData was called"); - mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app); + mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, version_string, app, installer); VLOG("StatsService::informAllUidData succeeded"); return Status::ok(); } -Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) { +Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version, + const String16& version_string, const String16& installer) { ENFORCE_UID(AID_SYSTEM); VLOG("StatsService::informOnePackage was called"); - mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version); + mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version, version_string, installer); return Status::ok(); } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 4a5f05fef034..cd4d601a606f 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -73,8 +73,10 @@ public: virtual Status informAlarmForSubscriberTriggeringFired(); virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version, - const vector<String16>& app); - virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version); + const vector<String16>& version_string, + const vector<String16>& app, const vector<String16>& installer); + virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version, + const String16& version_string, const String16& installer); virtual Status informOnePackageRemoved(const String16& app, int32_t uid); virtual Status informDeviceShutdown(); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index dca47f77aa4b..e6efc4c68bd8 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -197,6 +197,9 @@ message Atom { NativeProcessMemoryState native_process_memory_state = 10036; CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037; OnDevicePowerMeasurement on_device_power_measurement = 10038; + DeviceCalculatedPowerUse device_calculated_power_use = 10039; + DeviceCalculatedPowerBlameUid device_calculated_power_blame_uid = 10040; + DeviceCalculatedPowerBlameOther device_calculated_power_blame_other = 10041; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -3238,3 +3241,63 @@ message CpuTimePerThreadFreq { // Time spent in frequency in milliseconds, since thread start. optional uint32 time_millis = 7; } + +/** + * Pulls on-device BatteryStats power use calculations for the overall device. + */ +message DeviceCalculatedPowerUse { + // Power used by the device in mAh, as computed by BatteryStats, since BatteryStats last reset + // (i.e. roughly since device was last significantly charged). + // Currently, this is BatteryStatsHelper.getComputedPower() (not getTotalPower()). + optional float computed_power_milli_amp_hours = 1; +} + +/** + * Pulls on-device BatteryStats power use calculations broken down by uid. + * This atom should be complemented by DeviceCalculatedPowerBlameOther, which contains the power use + * that is attributed to non-uid items. They must all be included to get the total power use. + */ +message DeviceCalculatedPowerBlameUid { + // Uid being blamed. Note: isolated uids have already been mapped to host uid. + optional int32 uid = 1 [(is_uid) = true]; + + // Power used by this uid in mAh, as computed by BatteryStats, since BatteryStats last reset + // (i.e. roughly since device was last significantly charged). + optional float power_milli_amp_hours = 2; +} + +/** + * Pulls on-device BatteryStats power use calculations that are not due to a uid, broken down by + * drain type. + * This atom should be complemented by DeviceCalculatedPowerBlameUid, which contains the blame that + * is attributed uids. They must all be included to get the total power use. + */ +message DeviceCalculatedPowerBlameOther { + // The type of item whose power use is being reported. + enum DrainType { + AMBIENT_DISPLAY = 0; + // reserved 1; reserved "APP"; // Logged instead in DeviceCalculatedPowerBlameUid. + BLUETOOTH = 2; + CAMERA = 3; + // Cell-standby + CELL = 4; + FLASHLIGHT = 5; + IDLE = 6; + MEMORY = 7; + // Amount that total computed drain exceeded the drain estimated using the + // battery level changes and capacity. + OVERCOUNTED = 8; + PHONE = 9; + SCREEN = 10; + // Amount that total computed drain was below the drain estimated using the + // battery level changes and capacity. + UNACCOUNTED = 11; + // reserved 12; reserved "USER"; // Entire drain for a user. This is NOT supported. + WIFI = 13; + } + optional DrainType drain_type = 1; + + // Power used by this item in mAh, as computed by BatteryStats, since BatteryStats last reset + // (i.e. roughly since device was last significantly charged). + optional float power_milli_amp_hours = 2; +}
\ No newline at end of file diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 8378ae15c1ef..0e131cb6c8c9 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -243,6 +243,20 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {2, 3, 4, 5, 6}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_THREAD_FREQ)}}, + // DeviceCalculatedPowerUse. + {android::util::DEVICE_CALCULATED_POWER_USE, + {{}, {}, 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_USE)}}, + // DeviceCalculatedPowerBlameUid. + {android::util::DEVICE_CALCULATED_POWER_BLAME_UID, + {{}, {}, // BatteryStats already merged isolated with host ids so it's unnecessary here. + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_UID)}}, + // DeviceCalculatedPowerBlameOther. + {android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER, + {{}, {}, + 1 * NS_PER_SEC, + new StatsCompanionServicePuller(android::util::DEVICE_CALCULATED_POWER_BLAME_OTHER)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 4244d5bed23b..ac34f4760a12 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -77,6 +77,8 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, mActivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, mNoReportMetricIds); mHashStringsInReport = config.hash_strings_in_metric_report(); + mVersionStringsInReport = config.version_strings_in_metric_report(); + mInstallerInReport = config.installer_in_metric_report(); if (config.allowed_log_source_size() == 0) { mConfigValid = false; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index a4672b68f2bc..a31efbd3c8a6 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -83,6 +83,14 @@ public: return mHashStringsInReport; }; + inline bool versionStringsInReport() const { + return mVersionStringsInReport; + }; + + inline bool installerInReport() const { + return mInstallerInReport; + }; + void refreshTtl(const int64_t currentTimestampNs) { if (mTtlNs > 0) { mTtlEndNs = currentTimestampNs + mTtlNs; @@ -126,6 +134,8 @@ private: bool mConfigValid = false; bool mHashStringsInReport = false; + bool mVersionStringsInReport = false; + bool mInstallerInReport = false; const int64_t mTtlNs; int64_t mTtlEndNs; diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index 37a00673959c..59f3f0448e0e 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -49,6 +49,10 @@ const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2; const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3; const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4; const int FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH = 5; +const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING = 6; +const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH = 7; +const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER = 8; +const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH = 9; const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1; const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2; const int FIELD_ID_SNAPSHOTS = 1; @@ -60,6 +64,10 @@ const int FIELD_ID_CHANGE_UID = 4; const int FIELD_ID_CHANGE_NEW_VERSION = 5; const int FIELD_ID_CHANGE_PREV_VERSION = 6; const int FIELD_ID_CHANGE_PACKAGE_HASH = 7; +const int FIELD_ID_CHANGE_NEW_VERSION_STRING = 8; +const int FIELD_ID_CHANGE_PREV_VERSION_STRING = 9; +const int FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH = 10; +const int FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH = 11; UidMap::UidMap() : mBytesUsed(0) {} @@ -104,7 +112,8 @@ int64_t UidMap::getAppVersion(int uid, const string& packageName) const { } void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid, - const vector<int64_t>& versionCode, const vector<String16>& packageName) { + const vector<int64_t>& versionCode, const vector<String16>& versionString, + const vector<String16>& packageName, const vector<String16>& installer) { vector<wp<PackageInfoListener>> broadcastList; { lock_guard<mutex> lock(mMutex); // Exclusively lock for updates. @@ -121,7 +130,9 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid, mMap.clear(); for (size_t j = 0; j < uid.size(); j++) { string package = string(String8(packageName[j]).string()); - mMap[std::make_pair(uid[j], package)] = AppData(versionCode[j]); + mMap[std::make_pair(uid[j], package)] = + AppData(versionCode[j], string(String8(versionString[j]).string()), + string(String8(installer[j]).string())); } for (const auto& kv : deletedApps) { @@ -150,23 +161,30 @@ void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid, } void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid, - const int64_t& versionCode) { + const int64_t& versionCode, const String16& versionString, + const String16& installer) { vector<wp<PackageInfoListener>> broadcastList; string appName = string(String8(app_16).string()); { lock_guard<mutex> lock(mMutex); int32_t prevVersion = 0; + string prevVersionString = ""; + string newVersionString = string(String8(versionString).string()); bool found = false; auto it = mMap.find(std::make_pair(uid, appName)); if (it != mMap.end()) { found = true; prevVersion = it->second.versionCode; + prevVersionString = it->second.versionString; it->second.versionCode = versionCode; + it->second.versionString = newVersionString; + it->second.installer = string(String8(installer).string()); it->second.deleted = false; } if (!found) { // Otherwise, we need to add an app at this uid. - mMap[std::make_pair(uid, appName)] = AppData(versionCode); + mMap[std::make_pair(uid, appName)] = + AppData(versionCode, newVersionString, string(String8(installer).string())); } else { // Only notify the listeners if this is an app upgrade. If this app is being installed // for the first time, then we don't notify the listeners. @@ -174,7 +192,8 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i // app after deletion. getListenerListCopyLocked(&broadcastList); } - mChanges.emplace_back(false, timestamp, appName, uid, versionCode, prevVersion); + mChanges.emplace_back(false, timestamp, appName, uid, versionCode, newVersionString, + prevVersion, prevVersionString); mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); @@ -226,10 +245,12 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i lock_guard<mutex> lock(mMutex); int64_t prevVersion = 0; + string prevVersionString = ""; auto key = std::make_pair(uid, app); auto it = mMap.find(key); if (it != mMap.end() && !it->second.deleted) { prevVersion = it->second.versionCode; + prevVersionString = it->second.versionString; it->second.deleted = true; mDeletedApps.push_back(key); } @@ -240,7 +261,7 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i mMap.erase(oldest); StatsdStats::getInstance().noteUidMapAppDeletionDropped(); } - mChanges.emplace_back(true, timestamp, app, uid, 0, prevVersion); + mChanges.emplace_back(true, timestamp, app, uid, 0, "", prevVersion, prevVersionString); mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); @@ -315,8 +336,9 @@ size_t UidMap::getBytesUsed() const { return mBytesUsed; } -void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, - std::set<string> *str_set, ProtoOutputStream* proto) { +void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set, + bool includeVersionStrings, bool includeInstaller, + ProtoOutputStream* proto) { lock_guard<mutex> lock(mMutex); // Lock for updates for (const ChangeRecord& record : mChanges) { @@ -330,8 +352,22 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, str_set->insert(record.package); proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PACKAGE_HASH, (long long)Hash64(record.package)); + if (includeVersionStrings) { + str_set->insert(record.versionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH, + (long long)Hash64(record.versionString)); + str_set->insert(record.prevVersionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH, + (long long)Hash64(record.prevVersionString)); + } } else { proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package); + if (includeVersionStrings) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_NEW_VERSION_STRING, + record.versionString); + proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PREV_VERSION_STRING, + record.prevVersionString); + } } proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid); @@ -354,8 +390,26 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, str_set->insert(kv.first.second); proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH, (long long)Hash64(kv.first.second)); + if (includeVersionStrings) { + str_set->insert(kv.second.versionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH, + (long long)Hash64(kv.second.versionString)); + } + if (includeInstaller) { + str_set->insert(kv.second.installer); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH, + (long long)Hash64(kv.second.installer)); + } } else { proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second); + if (includeVersionStrings) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING, + kv.second.versionString); + } + if (includeInstaller) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER, + kv.second.installer); + } } proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, @@ -391,8 +445,9 @@ void UidMap::printUidMap(int out) const { for (const auto& kv : mMap) { if (!kv.second.deleted) { - dprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode, - kv.first.first); + dprintf(out, "%s, v%" PRId64 ", %s, %s (%i)\n", kv.first.second.c_str(), + kv.second.versionCode, kv.second.versionString.c_str(), + kv.second.installer.c_str(), kv.first.first); } } } diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index 4598369f1222..75ff507ef09a 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -44,12 +44,16 @@ namespace statsd { struct AppData { int64_t versionCode; + string versionString; + string installer; bool deleted; // Empty constructor needed for unordered map. AppData() { } - AppData(const int64_t v) : versionCode(v), deleted(false){}; + + AppData(const int64_t v, const string& versionString, const string& installer) + : versionCode(v), versionString(versionString), installer(installer), deleted(false){}; }; // When calling appendUidMap, we retrieve all the ChangeRecords since the last @@ -61,15 +65,20 @@ struct ChangeRecord { const int32_t uid; const int64_t version; const int64_t prevVersion; + const string versionString; + const string prevVersionString; ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package, - const int32_t uid, const int64_t version, const int64_t prevVersion) + const int32_t uid, const int64_t version, const string versionString, + const int64_t prevVersion, const string prevVersionString) : deletion(isDeletion), timestampNs(timestampNs), package(package), uid(uid), version(version), - prevVersion(prevVersion) { + prevVersion(prevVersion), + versionString(versionString), + prevVersionString(prevVersionString) { } }; @@ -87,10 +96,12 @@ public: * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j]. */ void updateMap(const int64_t& timestamp, const vector<int32_t>& uid, - const vector<int64_t>& versionCode, const vector<String16>& packageName); + const vector<int64_t>& versionCode, const vector<String16>& versionString, + const vector<String16>& packageName, const vector<String16>& installer); void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid, - const int64_t& versionCode); + const int64_t& versionCode, const String16& versionString, + const String16& installer); void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid); // Returns true if the given uid contains the specified app (eg. com.google.android.gms). @@ -127,8 +138,9 @@ public: // Gets all snapshots and changes that have occurred since the last output. // If every config key has received a change or snapshot record, then this // record is deleted. - void appendUidMap(const int64_t& timestamp, const ConfigKey& key, - std::set<string> *str_set, util::ProtoOutputStream* proto); + void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set, + bool includeVersionStrings, bool includeInstaller, + util::ProtoOutputStream* proto); // Forces the output to be cleared. We still generate a snapshot based on the current state. // This results in extra data uploaded but helps us reconstruct the uid mapping on the server diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 5d0f3d1db8c9..32ee5af9ee21 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -233,6 +233,14 @@ message UidMapping { optional bool deleted = 4; optional uint64 name_hash = 5; + + optional string version_string = 6; + + optional uint64 version_string_hash = 7; + + optional string installer = 8; + + optional uint64 installer_hash = 9; } optional int64 elapsed_timestamp_nanos = 1; @@ -250,6 +258,10 @@ message UidMapping { optional int64 new_version = 5; optional int64 prev_version = 6; optional uint64 app_hash = 7; + optional string new_version_string = 8; + optional string prev_version_string = 9; + optional uint64 new_version_string_hash = 10; + optional uint64 prev_version_string_hash = 11; } repeated Change changes = 2; } diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index aa789c799056..f955df29aee0 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -409,6 +409,10 @@ message StatsdConfig { repeated MetricActivation metric_activation = 17; + optional bool version_strings_in_metric_report = 18; + + optional bool installer_in_metric_report = 19; + // Field number 1000 is reserved for later use. reserved 1000; } diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 4c6671dcd663..2b9528f7d1de 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -148,8 +148,12 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0) @@ -297,8 +301,12 @@ TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { UidMap uidMap; uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); AttributionNodeInternal attribution_node1; attribution_node1.set_uid(1111); @@ -372,8 +380,12 @@ TEST(AtomMatcherTest, TestEqAnyStringMatcher) { UidMap uidMap; uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); AttributionNodeInternal attribution_node1; attribution_node1.set_uid(1067); diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 8864252bcf4b..355df2986a0b 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -153,7 +153,8 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) { // Setup simple config key corresponding to empty config. sp<UidMap> m = new UidMap(); sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")}); + m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, + {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; @@ -182,7 +183,8 @@ TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) { // Setup simple config key corresponding to empty config. sp<UidMap> m = new UidMap(); sp<StatsPullerManager> pullerManager = new StatsPullerManager(); - m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")}); + m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, + {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp<AlarmMonitor> anomalyAlarmMonitor; sp<AlarmMonitor> subscriberAlarmMonitor; int broadcastCount = 0; diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp index 99082cc647f6..f0d9cf188661 100644 --- a/cmds/statsd/tests/UidMap_test.cpp +++ b/cmds/statsd/tests/UidMap_test.cpp @@ -71,14 +71,20 @@ TEST(UidMapTest, TestMatching) { vector<int32_t> uids; vector<int64_t> versions; vector<String16> apps; + vector<String16> versionStrings; + vector<String16> installers; uids.push_back(1000); uids.push_back(1000); + versionStrings.push_back(String16("v1")); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + installers.push_back(String16("")); apps.push_back(String16(kApp1.c_str())); apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); EXPECT_TRUE(m.hasApp(1000, kApp1)); EXPECT_TRUE(m.hasApp(1000, kApp2)); EXPECT_FALSE(m.hasApp(1000, "not.app")); @@ -97,14 +103,20 @@ TEST(UidMapTest, TestAddAndRemove) { vector<int32_t> uids; vector<int64_t> versions; vector<String16> apps; + vector<String16> versionStrings; + vector<String16> installers; uids.push_back(1000); uids.push_back(1000); + versionStrings.push_back(String16("v1")); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + installers.push_back(String16("")); apps.push_back(String16(kApp1.c_str())); apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 2u); @@ -112,7 +124,7 @@ TEST(UidMapTest, TestAddAndRemove) { EXPECT_TRUE(name_set.find(kApp2) != name_set.end()); // Update the app1 version. - m.updateApp(2, String16(kApp1.c_str()), 1000, 40); + m.updateApp(2, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); EXPECT_EQ(40, m.getAppVersion(1000, kApp1)); name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); @@ -138,14 +150,15 @@ TEST(UidMapTest, TestAddAndRemove) { TEST(UidMapTest, TestUpdateApp) { UidMap m; - m.updateMap(1, {1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())}); + m.updateMap(1, {1000, 1000}, {4, 5}, {String16("v4"), String16("v5")}, + {String16(kApp1.c_str()), String16(kApp2.c_str())}, {String16(""), String16("")}); std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 2u); EXPECT_TRUE(name_set.find(kApp1) != name_set.end()); EXPECT_TRUE(name_set.find(kApp2) != name_set.end()); // Adds a new name for uid 1000. - m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40); + m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40, String16("v40"), String16("")); name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 3u); EXPECT_TRUE(name_set.find(kApp1) != name_set.end()); @@ -154,7 +167,7 @@ TEST(UidMapTest, TestUpdateApp) { EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end()); // This name is also reused by another uid 2000. - m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1); + m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1, String16("v1"), String16("")); name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 1u); EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end()); @@ -185,21 +198,26 @@ TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) { vector<int32_t> uids; vector<int64_t> versions; vector<String16> apps; + vector<String16> versionStrings; + vector<String16> installers; uids.push_back(1000); apps.push_back(String16(kApp2.c_str())); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); // Set the last timestamp for this config key to be newer. m.mLastUpdatePerConfigKey[config1] = 2; ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); // Check there's still a uidmap attached this one. UidMapping results; protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); + EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string()); } TEST(UidMapTest, TestRemovedAppRetained) { @@ -209,15 +227,19 @@ TEST(UidMapTest, TestRemovedAppRetained) { m.OnConfigUpdated(config1); vector<int32_t> uids; vector<int64_t> versions; + vector<String16> versionStrings; + vector<String16> installers; vector<String16> apps; uids.push_back(1000); apps.push_back(String16(kApp2.c_str())); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v5")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); m.removeApp(2, String16(kApp2.c_str()), 1000); ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); // Snapshot should still contain this item as deleted. UidMapping results; @@ -233,30 +255,34 @@ TEST(UidMapTest, TestRemovedAppOverGuardrail) { m.OnConfigUpdated(config1); vector<int32_t> uids; vector<int64_t> versions; + vector<String16> versionStrings; + vector<String16> installers; vector<String16> apps; const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap; for (int j = 0; j < maxDeletedApps + 10; j++) { uids.push_back(j); apps.push_back(String16(kApp1.c_str())); versions.push_back(j); + versionStrings.push_back(String16("v")); + installers.push_back(String16("")); } - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); // First, verify that we have the expected number of items. UidMapping results; ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size()); // Now remove all the apps. - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); for (int j = 0; j < maxDeletedApps + 10; j++) { m.removeApp(4, String16(kApp1.c_str()), j); } proto.clear(); - m.appendUidMap(5, config1, nullptr, &proto); + m.appendUidMap(5, config1, nullptr, true, true, &proto); // Snapshot drops the first nine items. protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size()); @@ -272,6 +298,8 @@ TEST(UidMapTest, TestClearingOutput) { vector<int32_t> uids; vector<int64_t> versions; + vector<String16> versionStrings; + vector<String16> installers; vector<String16> apps; uids.push_back(1000); uids.push_back(1000); @@ -279,45 +307,49 @@ TEST(UidMapTest, TestClearingOutput) { apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v4")); + versionStrings.push_back(String16("v5")); + installers.push_back(String16("")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); ProtoOutputStream proto; - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); UidMapping results; protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // We have to keep at least one snapshot in memory at all times. proto.clear(); - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // Now add another configuration. m.OnConfigUpdated(config2); - m.updateApp(5, String16(kApp1.c_str()), 1000, 40); + m.updateApp(5, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); proto.clear(); - m.appendUidMap(6, config1, nullptr, &proto); + m.appendUidMap(6, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(1, results.changes_size()); EXPECT_EQ(1U, m.mChanges.size()); // Add another delta update. - m.updateApp(7, String16(kApp2.c_str()), 1001, 41); + m.updateApp(7, String16(kApp2.c_str()), 1001, 41, String16("v41"), String16("")); EXPECT_EQ(2U, m.mChanges.size()); // We still can't remove anything. proto.clear(); - m.appendUidMap(8, config1, nullptr, &proto); + m.appendUidMap(8, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(1, results.changes_size()); EXPECT_EQ(2U, m.mChanges.size()); proto.clear(); - m.appendUidMap(9, config2, nullptr, &proto); + m.appendUidMap(9, config2, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(2, results.changes_size()); @@ -335,19 +367,23 @@ TEST(UidMapTest, TestMemoryComputed) { vector<int32_t> uids; vector<int64_t> versions; vector<String16> apps; + vector<String16> versionStrings; + vector<String16> installers; uids.push_back(1000); apps.push_back(String16(kApp1.c_str())); versions.push_back(1); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); - m.updateApp(3, String16(kApp1.c_str()), 1000, 40); + m.updateApp(3, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); ProtoOutputStream proto; vector<uint8_t> bytes; - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); size_t prevBytes = m.mBytesUsed; - m.appendUidMap(4, config1, nullptr, &proto); + m.appendUidMap(4, config1, nullptr, true, true, &proto); EXPECT_TRUE(m.mBytesUsed < prevBytes); } @@ -361,21 +397,27 @@ TEST(UidMapTest, TestMemoryGuardrail) { size_t startBytes = m.mBytesUsed; vector<int32_t> uids; vector<int64_t> versions; + vector<String16> versionStrings; + vector<String16> installers; vector<String16> apps; for (int i = 0; i < 100; i++) { uids.push_back(1); buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i); apps.push_back(String16(buf.c_str())); versions.push_back(1); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); } - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); - m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2); + m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2, + String16("v2"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); // Now force deletion by limiting the memory to hold one delta change. - m.maxBytesOverride = 80; // Since the app string alone requires >45 characters. - m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4); + m.maxBytesOverride = 120; // Since the app string alone requires >45 characters. + m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4, + String16("v4"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); } diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index 5c47af797eea..a9841c91ada2 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -69,8 +69,10 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { // Here it assumes that GMS core has two uids. processor->getUidMap()->updateMap( 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), - String16("APP3")}); + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); // GMS core node is in the middle. std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), @@ -215,8 +217,10 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { // Here it assumes that GMS core has two uids. processor->getUidMap()->updateMap( 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), - String16("APP3")}); + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); // GMS core node is in the middle. std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"), diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp index 3cb553fd9a16..2b0285b37473 100644 --- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp @@ -132,7 +132,8 @@ TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) { service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); // This is a new installation, so there shouldn't be a split (should be same as the without // split case). - service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); // Goes into the second bucket. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); @@ -145,11 +146,13 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) { SendConfig(service, MakeConfig()); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. - service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())}); + service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); // Force the uidmap to update at timestamp 2. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); - service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); // Goes into the second bucket. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); @@ -168,7 +171,8 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { SendConfig(service, MakeConfig()); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. - service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())}); + service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); // Force the uidmap to update at timestamp 2. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); @@ -189,13 +193,14 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(0)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2, + String16("v2"), String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true); @@ -206,14 +211,15 @@ TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2; service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true); @@ -229,13 +235,14 @@ TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) { TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeGaugeMetricConfig(0)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2, + String16("v2"), String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true); @@ -246,14 +253,15 @@ TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) { TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2; service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true); diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 851e35b5e9f0..39b327c3674b 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1320,18 +1320,6 @@ Landroid/R$styleable;->Window_windowFrame:I Landroid/security/Credentials;->convertToPem([Ljava/security/cert/Certificate;)[B Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService; Landroid/security/IKeyChainService;->requestPrivateKey(Ljava/lang/String;)Ljava/lang/String; -Landroid/security/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeystoreService; -Landroid/security/IKeystoreService;->clear_uid(J)I -Landroid/security/IKeystoreService;->del(Ljava/lang/String;I)I -Landroid/security/IKeystoreService;->exist(Ljava/lang/String;I)I -Landroid/security/IKeystoreService;->generateKey(Ljava/lang/String;Landroid/security/keymaster/KeymasterArguments;[BIILandroid/security/keymaster/KeyCharacteristics;)I -Landroid/security/IKeystoreService;->get(Ljava/lang/String;I)[B -Landroid/security/IKeystoreService;->getState(I)I -Landroid/security/IKeystoreService;->insert(Ljava/lang/String;[BII)I -Landroid/security/IKeystoreService;->is_hardware_backed(Ljava/lang/String;)I -Landroid/security/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String; -Landroid/security/IKeystoreService;->reset()I -Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B @@ -1343,6 +1331,17 @@ Landroid/security/keymaster/KeymasterIntArgument;->value:I Landroid/security/keymaster/KeymasterLongArgument;-><init>(IJ)V Landroid/security/keymaster/KeymasterLongArgument;-><init>(ILandroid/os/Parcel;)V Landroid/security/keymaster/KeymasterLongArgument;->value:J +Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService; +Landroid/security/keystore/IKeystoreService;->clear_uid(J)I +Landroid/security/keystore/IKeystoreService;->del(Ljava/lang/String;I)I +Landroid/security/keystore/IKeystoreService;->exist(Ljava/lang/String;I)I +Landroid/security/keystore/IKeystoreService;->get(Ljava/lang/String;I)[B +Landroid/security/keystore/IKeystoreService;->getState(I)I +Landroid/security/keystore/IKeystoreService;->insert(Ljava/lang/String;[BII)I +Landroid/security/keystore/IKeystoreService;->is_hardware_backed(Ljava/lang/String;)I +Landroid/security/keystore/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String; +Landroid/security/keystore/IKeystoreService;->reset()I +Landroid/security/keystore/IKeystoreService;->ungrant(Ljava/lang/String;I)I Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager; diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index bd9cf6dda7ff..362f4aedc900 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -88,6 +88,8 @@ interface INotificationManager ParceledListSlice getRecentNotifyingAppsForUser(int userId); int getBlockedAppCount(int userId); boolean areChannelsBypassingDnd(); + int getAppsBypassingDndCount(int uid); + ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId); // TODO: Remove this when callers have been migrated to the equivalent // INotificationListener method. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 03eba7efea91..004417b80e26 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4335,6 +4335,16 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a + * {android.os.IIdmap2} for managing idmap files (used by overlay + * packages). + * + * @see #getSystemService(String) + * @hide + */ + public static final String IDMAP_SERVICE = "idmap"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link VrManager} for accessing the VR service. * * @see #getSystemService(String) diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 02f38a790570..e9b240448eed 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -7508,7 +7508,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, String) */ - public String getStringExtra(String name) { + public @Nullable String getStringExtra(String name) { return mExtras == null ? null : mExtras.getString(name); } @@ -7522,7 +7522,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, CharSequence) */ - public CharSequence getCharSequenceExtra(String name) { + public @Nullable CharSequence getCharSequenceExtra(String name) { return mExtras == null ? null : mExtras.getCharSequence(name); } @@ -7536,7 +7536,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, Parcelable) */ - public <T extends Parcelable> T getParcelableExtra(String name) { + public @Nullable <T extends Parcelable> T getParcelableExtra(String name) { return mExtras == null ? null : mExtras.<T>getParcelable(name); } @@ -7550,7 +7550,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, Parcelable[]) */ - public Parcelable[] getParcelableArrayExtra(String name) { + public @Nullable Parcelable[] getParcelableArrayExtra(String name) { return mExtras == null ? null : mExtras.getParcelableArray(name); } @@ -7565,7 +7565,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putParcelableArrayListExtra(String, ArrayList) */ - public <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) { + public @Nullable <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(String name) { return mExtras == null ? null : mExtras.<T>getParcelableArrayList(name); } @@ -7579,7 +7579,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, Serializable) */ - public Serializable getSerializableExtra(String name) { + public @Nullable Serializable getSerializableExtra(String name) { return mExtras == null ? null : mExtras.getSerializable(name); } @@ -7594,7 +7594,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putIntegerArrayListExtra(String, ArrayList) */ - public ArrayList<Integer> getIntegerArrayListExtra(String name) { + public @Nullable ArrayList<Integer> getIntegerArrayListExtra(String name) { return mExtras == null ? null : mExtras.getIntegerArrayList(name); } @@ -7609,7 +7609,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putStringArrayListExtra(String, ArrayList) */ - public ArrayList<String> getStringArrayListExtra(String name) { + public @Nullable ArrayList<String> getStringArrayListExtra(String name) { return mExtras == null ? null : mExtras.getStringArrayList(name); } @@ -7624,7 +7624,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putCharSequenceArrayListExtra(String, ArrayList) */ - public ArrayList<CharSequence> getCharSequenceArrayListExtra(String name) { + public @Nullable ArrayList<CharSequence> getCharSequenceArrayListExtra(String name) { return mExtras == null ? null : mExtras.getCharSequenceArrayList(name); } @@ -7638,7 +7638,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, boolean[]) */ - public boolean[] getBooleanArrayExtra(String name) { + public @Nullable boolean[] getBooleanArrayExtra(String name) { return mExtras == null ? null : mExtras.getBooleanArray(name); } @@ -7652,7 +7652,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, byte[]) */ - public byte[] getByteArrayExtra(String name) { + public @Nullable byte[] getByteArrayExtra(String name) { return mExtras == null ? null : mExtras.getByteArray(name); } @@ -7666,7 +7666,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, short[]) */ - public short[] getShortArrayExtra(String name) { + public @Nullable short[] getShortArrayExtra(String name) { return mExtras == null ? null : mExtras.getShortArray(name); } @@ -7680,7 +7680,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, char[]) */ - public char[] getCharArrayExtra(String name) { + public @Nullable char[] getCharArrayExtra(String name) { return mExtras == null ? null : mExtras.getCharArray(name); } @@ -7694,7 +7694,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, int[]) */ - public int[] getIntArrayExtra(String name) { + public @Nullable int[] getIntArrayExtra(String name) { return mExtras == null ? null : mExtras.getIntArray(name); } @@ -7708,7 +7708,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, long[]) */ - public long[] getLongArrayExtra(String name) { + public @Nullable long[] getLongArrayExtra(String name) { return mExtras == null ? null : mExtras.getLongArray(name); } @@ -7722,7 +7722,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, float[]) */ - public float[] getFloatArrayExtra(String name) { + public @Nullable float[] getFloatArrayExtra(String name) { return mExtras == null ? null : mExtras.getFloatArray(name); } @@ -7736,7 +7736,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, double[]) */ - public double[] getDoubleArrayExtra(String name) { + public @Nullable double[] getDoubleArrayExtra(String name) { return mExtras == null ? null : mExtras.getDoubleArray(name); } @@ -7750,7 +7750,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, String[]) */ - public String[] getStringArrayExtra(String name) { + public @Nullable String[] getStringArrayExtra(String name) { return mExtras == null ? null : mExtras.getStringArray(name); } @@ -7764,7 +7764,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, CharSequence[]) */ - public CharSequence[] getCharSequenceArrayExtra(String name) { + public @Nullable CharSequence[] getCharSequenceArrayExtra(String name) { return mExtras == null ? null : mExtras.getCharSequenceArray(name); } @@ -7778,7 +7778,7 @@ public class Intent implements Parcelable, Cloneable { * * @see #putExtra(String, Bundle) */ - public Bundle getBundleExtra(String name) { + public @Nullable Bundle getBundleExtra(String name) { return mExtras == null ? null : mExtras.getBundle(name); } @@ -8584,7 +8584,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getStringExtra(String) */ - public @NonNull Intent putExtra(String name, String value) { + public @NonNull Intent putExtra(String name, @Nullable String value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8607,7 +8607,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getCharSequenceExtra(String) */ - public @NonNull Intent putExtra(String name, CharSequence value) { + public @NonNull Intent putExtra(String name, @Nullable CharSequence value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8630,7 +8630,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getParcelableExtra(String) */ - public @NonNull Intent putExtra(String name, Parcelable value) { + public @NonNull Intent putExtra(String name, @Nullable Parcelable value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8653,7 +8653,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getParcelableArrayExtra(String) */ - public @NonNull Intent putExtra(String name, Parcelable[] value) { + public @NonNull Intent putExtra(String name, @Nullable Parcelable[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8677,7 +8677,7 @@ public class Intent implements Parcelable, Cloneable { * @see #getParcelableArrayListExtra(String) */ public @NonNull Intent putParcelableArrayListExtra(String name, - ArrayList<? extends Parcelable> value) { + @Nullable ArrayList<? extends Parcelable> value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8700,7 +8700,8 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getIntegerArrayListExtra(String) */ - public @NonNull Intent putIntegerArrayListExtra(String name, ArrayList<Integer> value) { + public @NonNull Intent putIntegerArrayListExtra(String name, + @Nullable ArrayList<Integer> value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8723,7 +8724,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getStringArrayListExtra(String) */ - public @NonNull Intent putStringArrayListExtra(String name, ArrayList<String> value) { + public @NonNull Intent putStringArrayListExtra(String name, @Nullable ArrayList<String> value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8747,7 +8748,7 @@ public class Intent implements Parcelable, Cloneable { * @see #getCharSequenceArrayListExtra(String) */ public @NonNull Intent putCharSequenceArrayListExtra(String name, - ArrayList<CharSequence> value) { + @Nullable ArrayList<CharSequence> value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8770,7 +8771,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getSerializableExtra(String) */ - public @NonNull Intent putExtra(String name, Serializable value) { + public @NonNull Intent putExtra(String name, @Nullable Serializable value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8793,7 +8794,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getBooleanArrayExtra(String) */ - public @NonNull Intent putExtra(String name, boolean[] value) { + public @NonNull Intent putExtra(String name, @Nullable boolean[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8816,7 +8817,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getByteArrayExtra(String) */ - public @NonNull Intent putExtra(String name, byte[] value) { + public @NonNull Intent putExtra(String name, @Nullable byte[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8839,7 +8840,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getShortArrayExtra(String) */ - public @NonNull Intent putExtra(String name, short[] value) { + public @NonNull Intent putExtra(String name, @Nullable short[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8862,7 +8863,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getCharArrayExtra(String) */ - public @NonNull Intent putExtra(String name, char[] value) { + public @NonNull Intent putExtra(String name, @Nullable char[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8885,7 +8886,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getIntArrayExtra(String) */ - public @NonNull Intent putExtra(String name, int[] value) { + public @NonNull Intent putExtra(String name, @Nullable int[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8908,7 +8909,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getLongArrayExtra(String) */ - public @NonNull Intent putExtra(String name, long[] value) { + public @NonNull Intent putExtra(String name, @Nullable long[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8931,7 +8932,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getFloatArrayExtra(String) */ - public @NonNull Intent putExtra(String name, float[] value) { + public @NonNull Intent putExtra(String name, @Nullable float[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8954,7 +8955,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getDoubleArrayExtra(String) */ - public @NonNull Intent putExtra(String name, double[] value) { + public @NonNull Intent putExtra(String name, @Nullable double[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -8977,7 +8978,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getStringArrayExtra(String) */ - public @NonNull Intent putExtra(String name, String[] value) { + public @NonNull Intent putExtra(String name, @Nullable String[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -9000,7 +9001,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getCharSequenceArrayExtra(String) */ - public @NonNull Intent putExtra(String name, CharSequence[] value) { + public @NonNull Intent putExtra(String name, @Nullable CharSequence[] value) { if (mExtras == null) { mExtras = new Bundle(); } @@ -9023,7 +9024,7 @@ public class Intent implements Parcelable, Cloneable { * @see #removeExtra * @see #getBundleExtra(String) */ - public @NonNull Intent putExtra(String name, Bundle value) { + public @NonNull Intent putExtra(String name, @Nullable Bundle value) { if (mExtras == null) { mExtras = new Bundle(); } diff --git a/core/java/android/content/MimeTypeFilter.java b/core/java/android/content/MimeTypeFilter.java new file mode 100644 index 000000000000..1c26fd917f76 --- /dev/null +++ b/core/java/android/content/MimeTypeFilter.java @@ -0,0 +1,154 @@ +/* + * 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.content; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.ArrayList; + +/** + * Provides utility methods for matching MIME type filters used in ContentProvider. + * + * <p>Wildcards are allowed only instead of the entire type or subtype with a tree prefix. + * Eg. image\/*, *\/* is a valid filter and will match image/jpeg, but image/j* is invalid and + * it will not match image/jpeg. Suffixes and parameters are not supported, and they are treated + * as part of the subtype during matching. Neither type nor subtype can be empty. + * + * <p><em>Note: MIME type matching in the Android framework is case-sensitive, unlike the formal + * RFC definitions. As a result, you should always write these elements with lower case letters, + * or use {@link android.content.Intent#normalizeMimeType} to ensure that they are converted to + * lower case.</em> + * + * <p>MIME types can be null or ill-formatted. In such case they won't match anything. + * + * <p>MIME type filters must be correctly formatted, or an exception will be thrown. + * Copied from support library. + * {@hide} + */ +public final class MimeTypeFilter { + + private MimeTypeFilter() { + } + + private static boolean mimeTypeAgainstFilter( + @NonNull String[] mimeTypeParts, @NonNull String[] filterParts) { + if (filterParts.length != 2) { + throw new IllegalArgumentException( + "Ill-formatted MIME type filter. Must be type/subtype."); + } + if (filterParts[0].isEmpty() || filterParts[1].isEmpty()) { + throw new IllegalArgumentException( + "Ill-formatted MIME type filter. Type or subtype empty."); + } + if (mimeTypeParts.length != 2) { + return false; + } + if (!"*".equals(filterParts[0]) + && !filterParts[0].equals(mimeTypeParts[0])) { + return false; + } + if (!"*".equals(filterParts[1]) + && !filterParts[1].equals(mimeTypeParts[1])) { + return false; + } + + return true; + } + + /** + * Matches one nullable MIME type against one MIME type filter. + * @return True if the {@code mimeType} matches the {@code filter}. + */ + public static boolean matches(@Nullable String mimeType, @NonNull String filter) { + if (mimeType == null) { + return false; + } + + final String[] mimeTypeParts = mimeType.split("/"); + final String[] filterParts = filter.split("/"); + + return mimeTypeAgainstFilter(mimeTypeParts, filterParts); + } + + /** + * Matches one nullable MIME type against an array of MIME type filters. + * @return The first matching filter, or null if nothing matches. + */ + @Nullable + public static String matches( + @Nullable String mimeType, @NonNull String[] filters) { + if (mimeType == null) { + return null; + } + + final String[] mimeTypeParts = mimeType.split("/"); + for (String filter : filters) { + final String[] filterParts = filter.split("/"); + if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) { + return filter; + } + } + + return null; + } + + /** + * Matches multiple MIME types against an array of MIME type filters. + * @return The first matching MIME type, or null if nothing matches. + */ + @Nullable + public static String matches( + @Nullable String[] mimeTypes, @NonNull String filter) { + if (mimeTypes == null) { + return null; + } + + final String[] filterParts = filter.split("/"); + for (String mimeType : mimeTypes) { + final String[] mimeTypeParts = mimeType.split("/"); + if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) { + return mimeType; + } + } + + return null; + } + + /** + * Matches multiple MIME types against an array of MIME type filters. + * @return The list of matching MIME types, or empty array if nothing matches. + */ + @NonNull + public static String[] matchesMany( + @Nullable String[] mimeTypes, @NonNull String filter) { + if (mimeTypes == null) { + return new String[] {}; + } + + final ArrayList<String> list = new ArrayList<>(); + final String[] filterParts = filter.split("/"); + for (String mimeType : mimeTypes) { + final String[] mimeTypeParts = mimeType.split("/"); + if (mimeTypeAgainstFilter(mimeTypeParts, filterParts)) { + list.add(mimeType); + } + } + + return list.toArray(new String[list.size()]); + } +} diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 5f2374995775..4371c772c047 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -58,6 +58,7 @@ import java.util.HashMap; public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean DEBUG_REFS = false; + private static final boolean FEATURE_FLAG_IDMAP2 = false; private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; @@ -195,13 +196,23 @@ public final class AssetManager implements AutoCloseable { return; } - // Make sure that all IDMAPs are up to date. - nativeVerifySystemIdmaps(); try { final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/)); - loadStaticRuntimeOverlays(apkAssets); + if (FEATURE_FLAG_IDMAP2) { + final String[] systemIdmapPaths = + nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); + if (systemIdmapPaths == null) { + throw new IOException("idmap2 scan failed"); + } + for (String idmapPath : systemIdmapPaths) { + apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); + } + } else { + nativeVerifySystemIdmaps(); + loadStaticRuntimeOverlays(apkAssets); + } sSystemApkAssetsSet = new ArraySet<>(apkAssets); sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]); @@ -1404,6 +1415,7 @@ public final class AssetManager implements AutoCloseable { private static native long nativeAssetGetRemainingLength(long assetPtr); private static native void nativeVerifySystemIdmaps(); + private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); // Global debug native methods. /** diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 9cf7de586d17..c437dde2dacc 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2421,7 +2421,7 @@ public abstract class BatteryStats implements Parcelable { public static final IntToString[] HISTORY_EVENT_INT_FORMATTERS = new IntToString[] { sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, - sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, + sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sIntToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sUidToString, sIntToString }; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index 1f47f933cde9..28ea553c8800 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1390,3 +1390,4 @@ public class FileUtils { } } } + diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 124f2072933e..74d434c51781 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -62,12 +62,15 @@ interface IStatsManager { * Inform statsd what the version and package are for each uid. Note that each array should * have the same number of elements, and version[i] and package[i] correspond to uid[i]. */ - oneway void informAllUidData(in int[] uid, in long[] version, in String[] app); + oneway void informAllUidData(in int[] uid, in long[] version, in String[] version_string, + in String[] app, in String[] installer); /** - * Inform statsd what the uid and version are for one app that was updated. + * Inform statsd what the uid, version, version_string, and installer are for one app that was + * updated. */ - oneway void informOnePackage(in String app, in int uid, in long version); + oneway void informOnePackage(in String app, in int uid, in long version, + in String version_string, in String installer); /** * Inform stats that an app was removed. diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 126588a3a817..44b9e311dc0b 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -1056,6 +1056,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { /** * Internal class representing a remote status read by * {@link ParcelFileDescriptor#readCommStatus(FileDescriptor, byte[])}. + * + * Warning: this must be kept in sync with ParcelFileDescriptorStatus at + * frameworks/native/libs/binder/Parcel.cpp */ private static class Status { /** Special value indicating remote side died. */ diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index 72e1ab972846..866bd9a17f41 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -104,14 +104,6 @@ public final class StatsLogEventWrapper implements Parcelable { } /** - * Write a double value. - */ - public void writeDouble(double val) { - mTypes.add(EVENT_TYPE_DOUBLE); - mValues.add(val); - } - - /** * Write a storage value. */ public void writeStorage(byte[] val) { diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 67e52aad9206..16d454dd0179 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -16,12 +16,11 @@ package android.provider; -import static android.system.OsConstants.SEEK_SET; - import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull; import static com.android.internal.util.Preconditions.checkCollectionNotEmpty; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.ContentProviderClient; @@ -29,13 +28,12 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.MimeTypeFilter; import android.content.pm.ResolveInfo; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.ImageDecoder; -import android.graphics.Matrix; import android.graphics.Point; import android.media.ExifInterface; import android.net.Uri; @@ -50,20 +48,13 @@ import android.os.Parcelable; import android.os.ParcelableException; import android.os.RemoteException; import android.os.storage.StorageVolume; -import android.system.ErrnoException; -import android.system.Os; import android.util.DataUnit; import android.util.Log; -import android.util.Size; - -import libcore.io.IoUtils; -import java.io.BufferedInputStream; import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -113,6 +104,54 @@ public final class DocumentsContract { public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI"; /** + * Key for {@link DocumentsProvider} to query display name is matched. + * The match of display name is partial matching and case-insensitive. + * Ex: The value is "o", the display name of the results will contain + * both "foo" and "Open". + * + * @see DocumentsProvider#querySearchDocuments(String, String[], + * Bundle) + * {@hide} + */ + public static final String QUERY_ARG_DISPLAY_NAME = "android:query-arg-display-name"; + + /** + * Key for {@link DocumentsProvider} to query mime types is matched. + * The value is a string array, it can support different mime types. + * Each items will be treated as "OR" condition. Ex: {"image/*" , + * "video/*"}. The mime types of the results will contain both image + * type and video type. + * + * @see DocumentsProvider#querySearchDocuments(String, String[], + * Bundle) + * {@hide} + */ + public static final String QUERY_ARG_MIME_TYPES = "android:query-arg-mime-types"; + + /** + * Key for {@link DocumentsProvider} to query the file size in bytes is + * larger than the value. + * + * @see DocumentsProvider#querySearchDocuments(String, String[], + * Bundle) + * {@hide} + */ + public static final String QUERY_ARG_FILE_SIZE_OVER = "android:query-arg-file-size-over"; + + /** + * Key for {@link DocumentsProvider} to query the last modified time + * is newer than the value. The unit is in milliseconds since + * January 1, 1970 00:00:00.0 UTC. + * + * @see DocumentsProvider#querySearchDocuments(String, String[], + * Bundle) + * @see Document#COLUMN_LAST_MODIFIED + * {@hide} + */ + public static final String QUERY_ARG_LAST_MODIFIED_AFTER = + "android:query-arg-last-modified-after"; + + /** * Sets the desired initial location visible to user when file chooser is shown. * * <p>Applicable to {@link Intent} with actions: @@ -929,6 +968,89 @@ public final class DocumentsContract { } /** + * Check if the values match the query arguments. + * + * @param queryArgs the query arguments + * @param displayName the display time to check against + * @param mimeType the mime type to check against + * @param lastModified the last modified time to check against + * @param size the size to check against + * @hide + */ + public static boolean matchSearchQueryArguments(Bundle queryArgs, String displayName, + String mimeType, long lastModified, long size) { + if (queryArgs == null) { + return true; + } + + final String argDisplayName = queryArgs.getString(QUERY_ARG_DISPLAY_NAME, ""); + if (!argDisplayName.isEmpty()) { + // TODO (118795812) : Enhance the search string handled in DocumentsProvider + if (!displayName.toLowerCase().contains(argDisplayName.toLowerCase())) { + return false; + } + } + + final long argFileSize = queryArgs.getLong(QUERY_ARG_FILE_SIZE_OVER, -1 /* defaultValue */); + if (argFileSize != -1 && size < argFileSize) { + return false; + } + + final long argLastModified = queryArgs.getLong(QUERY_ARG_LAST_MODIFIED_AFTER, + -1 /* defaultValue */); + if (argLastModified != -1 && lastModified < argLastModified) { + return false; + } + + final String[] argMimeTypes = queryArgs.getStringArray(QUERY_ARG_MIME_TYPES); + if (argMimeTypes != null && argMimeTypes.length > 0) { + mimeType = Intent.normalizeMimeType(mimeType); + for (String type : argMimeTypes) { + if (MimeTypeFilter.matches(mimeType, Intent.normalizeMimeType(type))) { + return true; + } + } + return false; + } + return true; + } + + /** + * Get the handled query arguments from the query bundle. The handled arguments are + * {@link DocumentsContract#QUERY_ARG_DISPLAY_NAME}, + * {@link DocumentsContract#QUERY_ARG_MIME_TYPES}, + * {@link DocumentsContract#QUERY_ARG_FILE_SIZE_OVER} and + * {@link DocumentsContract#QUERY_ARG_LAST_MODIFIED_AFTER}. + * + * @param queryArgs the query arguments to be parsed. + * @return the handled query arguments + * @hide + */ + public static String[] getHandledQueryArguments(Bundle queryArgs) { + if (queryArgs == null) { + return new String[0]; + } + + final ArrayList<String> args = new ArrayList<>(); + if (queryArgs.keySet().contains(QUERY_ARG_DISPLAY_NAME)) { + args.add(QUERY_ARG_DISPLAY_NAME); + } + + if (queryArgs.keySet().contains(QUERY_ARG_FILE_SIZE_OVER)) { + args.add(QUERY_ARG_FILE_SIZE_OVER); + } + + if (queryArgs.keySet().contains(QUERY_ARG_LAST_MODIFIED_AFTER)) { + args.add(QUERY_ARG_LAST_MODIFIED_AFTER); + } + + if (queryArgs.keySet().contains(QUERY_ARG_MIME_TYPES)) { + args.add(QUERY_ARG_MIME_TYPES); + } + return args.toArray(new String[0]); + } + + /** * Test if the given URI represents a {@link Document} backed by a * {@link DocumentsProvider}. * @@ -1052,6 +1174,15 @@ public final class DocumentsContract { return searchDocumentsUri.getQueryParameter(PARAM_QUERY); } + /** + * Extract the search query from a Bundle + * {@link #QUERY_ARG_DISPLAY_NAME}. + * {@hide} + */ + public static String getSearchDocumentsQuery(@NonNull Bundle bundle) { + return bundle.getString(QUERY_ARG_DISPLAY_NAME, "" /* defaultValue */); + } + /** {@hide} */ @UnsupportedAppUsage public static Uri setManageMode(Uri uri) { diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 68f8acd8a586..58f82134ec50 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -32,7 +32,6 @@ import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree; import static android.provider.DocumentsContract.buildTreeDocumentUri; import static android.provider.DocumentsContract.getDocumentId; import static android.provider.DocumentsContract.getRootId; -import static android.provider.DocumentsContract.getSearchDocumentsQuery; import static android.provider.DocumentsContract.getTreeDocumentId; import static android.provider.DocumentsContract.isTreeUri; @@ -47,6 +46,7 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.MimeTypeFilter; import android.content.UriMatcher; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; @@ -651,6 +651,55 @@ public abstract class DocumentsProvider extends ContentProvider { } /** + * Return documents that match the given query under the requested + * root. The returned documents should be sorted by relevance in descending + * order. How documents are matched against the query string is an + * implementation detail left to each provider, but it's suggested that at + * least {@link Document#COLUMN_DISPLAY_NAME} be matched in a + * case-insensitive fashion. + * <p> + * If your provider is cloud-based, and you have some data cached or pinned + * locally, you may return the local data immediately, setting + * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that + * you are still fetching additional data. Then, when the network data is + * available, you can send a change notification to trigger a requery and + * return the complete contents. + * <p> + * To support change notifications, you must + * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant + * Uri, such as {@link DocumentsContract#buildSearchDocumentsUri(String, + * String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri, + * android.database.ContentObserver, boolean)} with that Uri to send change + * notifications. + * + * @param rootId the root to search under. + * @param projection list of {@link Document} columns to put into the + * cursor. If {@code null} all supported columns should be + * included. + * @param queryArgs the query arguments. + * {@link DocumentsContract#QUERY_ARG_DISPLAY_NAME}, + * {@link DocumentsContract#QUERY_ARG_MIME_TYPES}, + * {@link DocumentsContract#QUERY_ARG_FILE_SIZE_OVER}, + * {@link DocumentsContract#QUERY_ARG_LAST_MODIFIED_AFTER}. + * @return cursor containing search result. Include + * {@link ContentResolver#EXTRA_HONORED_ARGS} in {@link Cursor} + * extras {@link Bundle} when any QUERY_ARG_* value was honored + * during the preparation of the results. + * + * @see ContentResolver#EXTRA_HONORED_ARGS + * @see DocumentsContract#EXTRA_LOADING + * @see DocumentsContract#EXTRA_INFO + * @see DocumentsContract#EXTRA_ERROR + * {@hide} + */ + @SuppressWarnings("unused") + public Cursor querySearchDocuments(String rootId, String[] projection, Bundle queryArgs) + throws FileNotFoundException { + return querySearchDocuments(rootId, DocumentsContract.getSearchDocumentsQuery(queryArgs), + projection); + } + + /** * Ejects the root. Throws {@link IllegalStateException} if ejection failed. * * @param rootId the root to be ejected. @@ -795,7 +844,7 @@ public abstract class DocumentsProvider extends ContentProvider { * {@link #queryDocument(String, String[])}, * {@link #queryRecentDocuments(String, String[])}, * {@link #queryRoots(String[])}, and - * {@link #querySearchDocuments(String, String, String[])}. + * {@link #querySearchDocuments(String, String[], Bundle)}. */ @Override public Cursor query(Uri uri, String[] projection, String selection, @@ -812,7 +861,7 @@ public abstract class DocumentsProvider extends ContentProvider { * @see #queryRecentDocuments(String, String[], Bundle, CancellationSignal) * @see #queryDocument(String, String[]) * @see #queryChildDocuments(String, String[], String) - * @see #querySearchDocuments(String, String, String[]) + * @see #querySearchDocuments(String, String[], Bundle) */ @Override public final Cursor query( @@ -825,8 +874,7 @@ public abstract class DocumentsProvider extends ContentProvider { return queryRecentDocuments( getRootId(uri), projection, queryArgs, cancellationSignal); case MATCH_SEARCH: - return querySearchDocuments( - getRootId(uri), getSearchDocumentsQuery(uri), projection); + return querySearchDocuments(getRootId(uri), projection, queryArgs); case MATCH_DOCUMENT: case MATCH_DOCUMENT_TREE: enforceTree(uri); @@ -1301,7 +1349,7 @@ public abstract class DocumentsProvider extends ContentProvider { final long flags = cursor.getLong(cursor.getColumnIndexOrThrow(Document.COLUMN_FLAGS)); if ((flags & Document.FLAG_VIRTUAL_DOCUMENT) == 0 && mimeType != null && - mimeTypeMatches(mimeTypeFilter, mimeType)) { + MimeTypeFilter.matches(mimeType, mimeTypeFilter)) { return new String[] { mimeType }; } } @@ -1354,21 +1402,4 @@ public abstract class DocumentsProvider extends ContentProvider { // For any other yet unhandled case, let the provider subclass handle it. return openTypedDocument(documentId, mimeTypeFilter, opts, signal); } - - /** - * @hide - */ - public static boolean mimeTypeMatches(String filter, String test) { - if (test == null) { - return false; - } else if (filter == null || "*/*".equals(filter)) { - return true; - } else if (filter.equals(test)) { - return true; - } else if (filter.endsWith("/*")) { - return filter.regionMatches(0, test, 0, filter.indexOf('/')); - } else { - return false; - } - } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e3401e76623e..b2666482c10d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10324,6 +10324,18 @@ public final class Settings { private static final Validator WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; + /** + * Setting to enable including recency information when determining pno network priorities. + * 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_RECENCY_SORTING_ENABLED = + "wifi_pno_recency_sorting_enabled"; + + private static final Validator WIFI_PNO_RECENCY_SORTING_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. @@ -12799,6 +12811,8 @@ public final class Settings { VALIDATORS.put(DEVICE_DEMO_MODE, BOOLEAN_VALIDATOR); VALIDATORS.put(WIFI_PNO_FREQUENCY_CULLING_ENABLED, WIFI_PNO_FREQUENCY_CULLING_ENABLED_VALIDATOR); + VALIDATORS.put(WIFI_PNO_RECENCY_SORTING_ENABLED, + WIFI_PNO_RECENCY_SORTING_ENABLED_VALIDATOR); } /** diff --git a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl index 0000b9f8c76c..ac5be06abff3 100644 --- a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl +++ b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl @@ -30,4 +30,6 @@ oneway interface IRoleControllerService { in IRoleManagerCallback callback); void onClearRoleHolders(in String roleName, in IRoleManagerCallback callback); + + void onGrantDefaultRoles(in IRoleManagerCallback callback); } diff --git a/core/java/android/rolecontrollerservice/RoleControllerService.java b/core/java/android/rolecontrollerservice/RoleControllerService.java index da11bca220d4..44c45bb32acd 100644 --- a/core/java/android/rolecontrollerservice/RoleControllerService.java +++ b/core/java/android/rolecontrollerservice/RoleControllerService.java @@ -89,6 +89,13 @@ public abstract class RoleControllerService extends Service { RoleControllerService.this.onClearRoleHolders(roleName, new RoleManagerCallbackDelegate(callback)); } + + @Override + public void onGrantDefaultRoles(IRoleManagerCallback callback) { + Preconditions.checkNotNull(callback, "callback cannot be null"); + RoleControllerService.this.onGrantDefaultRoles( + new RoleManagerCallbackDelegate(callback)); + } }; } @@ -133,6 +140,16 @@ public abstract class RoleControllerService extends Service { public abstract void onClearRoleHolders(@NonNull String roleName, @NonNull RoleManagerCallback callback); + /** + * Called by system to grant default permissions and roles. + * <p> + * This is typically when creating a new user or upgrading either system or + * permission controller package + * + * @param callback the callback for whether this call is successful + */ + public abstract void onGrantDefaultRoles(@NonNull RoleManagerCallback callback); + private static class RoleManagerCallbackDelegate implements RoleManagerCallback { private IRoleManagerCallback mCallback; diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java index c104671fc129..1ab79fbee0b6 100644 --- a/core/java/android/security/keymaster/ExportResult.java +++ b/core/java/android/security/keymaster/ExportResult.java @@ -28,6 +28,11 @@ public class ExportResult implements Parcelable { public final int resultCode; public final byte[] exportData; + public ExportResult(int resultCode) { + this.resultCode = resultCode; + this.exportData = new byte[0]; + } + @UnsupportedAppUsage public static final Parcelable.Creator<ExportResult> CREATOR = new Parcelable.Creator<ExportResult>() { diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java index 555863efec91..a4fe75d6d0c0 100644 --- a/core/java/android/security/keymaster/KeyCharacteristics.java +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -52,6 +52,14 @@ public class KeyCharacteristics implements Parcelable { readFromParcel(in); } + /** + * Makes a shallow copy of other by copying the other's references to the KeymasterArguments + */ + public void shallowCopyFrom(KeyCharacteristics other) { + this.swEnforced = other.swEnforced; + this.hwEnforced = other.hwEnforced; + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.java b/core/java/android/security/keymaster/KeymasterCertificateChain.java index 243b9fe5f7c6..00a1a1c06e79 100644 --- a/core/java/android/security/keymaster/KeymasterCertificateChain.java +++ b/core/java/android/security/keymaster/KeymasterCertificateChain.java @@ -54,6 +54,14 @@ public class KeymasterCertificateChain implements Parcelable { readFromParcel(in); } + /** + * Makes a shallow copy of other by copying the reference to the certificate chain list. + * @param other + */ + public void shallowCopyFrom(KeymasterCertificateChain other) { + this.mCertificates = other.mCertificates; + } + public List<byte[]> getCertificates() { return mCertificates; } diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java index 2943211a45f5..bc4f36000b85 100644 --- a/core/java/android/security/keymaster/OperationResult.java +++ b/core/java/android/security/keymaster/OperationResult.java @@ -59,6 +59,10 @@ public class OperationResult implements Parcelable { this.outParams = outParams; } + public OperationResult(int resultCode) { + this(resultCode, null, 0, 0, null, null); + } + protected OperationResult(Parcel in) { resultCode = in.readInt(); token = in.readStrongBinder(); diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index c8e0dd291041..2d5f3bf8c862 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -1270,7 +1270,13 @@ public abstract class Layout { */ public float getLineLeft(int line) { final int dir = getParagraphDirection(line); - final Alignment align = getParagraphAlignment(line); + Alignment align = getParagraphAlignment(line); + // Before Q, StaticLayout.Builder.setAlignment didn't check whether the input alignment + // is null. And when it is null, the old behavior is the same as ALIGN_CENTER. + // To keep consistency, we convert a null alignment to ALIGN_CENTER. + if (align == null) { + align = Alignment.ALIGN_CENTER; + } // First convert combinations of alignment and direction settings to // three basic cases: ALIGN_LEFT, ALIGN_RIGHT and ALIGN_CENTER. @@ -1319,7 +1325,13 @@ public abstract class Layout { */ public float getLineRight(int line) { final int dir = getParagraphDirection(line); - final Alignment align = getParagraphAlignment(line); + Alignment align = getParagraphAlignment(line); + // Before Q, StaticLayout.Builder.setAlignment didn't check whether the input alignment + // is null. And when it is null, the old behavior is the same as ALIGN_CENTER. + // To keep consistency, we convert a null alignment to ALIGN_CENTER. + if (align == null) { + align = Alignment.ALIGN_CENTER; + } final Alignment resultAlign; switch(align) { diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index 7b638b4c4a63..6eb433abf16c 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -201,7 +201,7 @@ public class TextLine { } } - mCharsValid = hasReplacement || hasTabs || directions != Layout.DIRS_ALL_LEFT_TO_RIGHT; + mCharsValid = hasReplacement; if (mCharsValid) { if (mChars == null || mChars.length < mLen) { @@ -815,7 +815,6 @@ public class TextLine { } else { final int delta = mStart; if (mComputed == null) { - // TODO: Enable measured getRunAdvance for ReplacementSpan and RTL text. return wp.getRunAdvance(mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, runIsRtl, delta + offset); } else { diff --git a/services/core/java/com/android/server/input/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java index 3cf7edcd6b2e..dc1e505ef36d 100644 --- a/services/core/java/com/android/server/input/InputApplicationHandle.java +++ b/core/java/android/view/InputApplicationHandle.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.input; +package android.view; /** * Functions as a handle for an application that can receive input. diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java index b2dd6ac9e971..84c8e7a2221e 100644 --- a/core/java/android/view/InputChannel.java +++ b/core/java/android/view/InputChannel.java @@ -18,6 +18,7 @@ package android.view; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.os.IBinder; import android.os.Parcelable; import android.util.Slog; @@ -50,15 +51,17 @@ public final class InputChannel implements Parcelable { @SuppressWarnings("unused") @UnsupportedAppUsage private long mPtr; // used by native code - + private static native InputChannel[] nativeOpenInputChannelPair(String name); - + private native void nativeDispose(boolean finalized); private native void nativeTransferTo(InputChannel other); private native void nativeReadFromParcel(Parcel parcel); private native void nativeWriteToParcel(Parcel parcel); private native void nativeDup(InputChannel target); - + private native IBinder nativeGetToken(); + private native void nativeSetToken(IBinder token); + private native String nativeGetName(); /** @@ -159,14 +162,22 @@ public final class InputChannel implements Parcelable { } nativeWriteToParcel(out); - + if ((flags & PARCELABLE_WRITE_RETURN_VALUE) != 0) { dispose(); } } - + @Override public String toString() { return getName(); } + + public IBinder getToken() { + return nativeGetToken(); + } + + public void setToken(IBinder token) { + nativeSetToken(token); + } } diff --git a/services/core/java/com/android/server/input/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index bb29bf823eb8..621ee89fac45 100644 --- a/services/core/java/com/android/server/input/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.input; +package android.view; import android.graphics.Region; import android.view.IWindow; @@ -34,9 +34,6 @@ public final class InputWindowHandle { // The input application handle. public final InputApplicationHandle inputApplicationHandle; - // The window manager's window state. - public final Object windowState; - // The client window. public final IWindow clientWindow; @@ -97,9 +94,8 @@ public final class InputWindowHandle { private native void nativeDispose(); public InputWindowHandle(InputApplicationHandle inputApplicationHandle, - Object windowState, IWindow clientWindow, int displayId) { + IWindow clientWindow, int displayId) { this.inputApplicationHandle = inputApplicationHandle; - this.windowState = windowState; this.clientWindow = clientWindow; this.displayId = displayId; } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 3d16eb89c41d..a7a5024cd2a6 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -153,6 +153,9 @@ public class SurfaceControl implements Parcelable { private static native Display.HdrCapabilities nativeGetHdrCapabilities(IBinder displayToken); + private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject, + InputWindowHandle handle); + private final CloseGuard mCloseGuard = CloseGuard.get(); private final String mName; @@ -1459,6 +1462,12 @@ public class SurfaceControl implements Parcelable { return this; } + public Transaction setInputWindowInfo(SurfaceControl sc, InputWindowHandle handle) { + sc.checkNotReleased(); + nativeSetInputWindowInfo(mNativeObject, sc.mNativeObject, handle); + return this; + } + @UnsupportedAppUsage public Transaction setMatrix(SurfaceControl sc, float dsdx, float dtdx, float dtdy, float dsdy) { diff --git a/core/java/android/view/textclassifier/ModelFileManager.java b/core/java/android/view/textclassifier/ModelFileManager.java index 896b516bbf9a..8558a462fa40 100644 --- a/core/java/android/view/textclassifier/ModelFileManager.java +++ b/core/java/android/view/textclassifier/ModelFileManager.java @@ -251,6 +251,9 @@ public final class ModelFileManager { if (!mLanguageIndependent && model.mLanguageIndependent) { return true; } + if (mLanguageIndependent && !model.mLanguageIndependent) { + return false; + } // A higher-version model is preferred. if (mVersion > model.getVersion()) { diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index b754d84fbaf8..eb35587cb7e7 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -16,302 +16,22 @@ */ package android.widget; -import android.annotation.UnsupportedAppUsage; -import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageItemInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.pm.PermissionGroupInfo; -import android.content.pm.PermissionInfo; import android.graphics.drawable.Drawable; -import android.os.Parcel; -import android.os.UserHandle; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import com.android.internal.R; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** - * This class contains the SecurityPermissions view implementation. - * Initially the package's advanced or dangerous security permissions - * are displayed under categorized - * groups. Clicking on the additional permissions presents - * extended information consisting of all groups and permissions. - * To use this view define a LinearLayout or any ViewGroup and add this - * view by instantiating AppSecurityPermissions and invoking getPermissionsView. + * Allows the device admin to show certain dialogs. Should be integrated into settings. * + * @deprecated * {@hide} */ +@Deprecated public class AppSecurityPermissions { - public static final int WHICH_NEW = 1<<2; - public static final int WHICH_ALL = 0xffff; - - private final static String TAG = "AppSecurityPermissions"; - private final static boolean localLOGV = false; - private final Context mContext; - private final LayoutInflater mInflater; - private final PackageManager mPm; - private final Map<String, MyPermissionGroupInfo> mPermGroups - = new HashMap<String, MyPermissionGroupInfo>(); - private final List<MyPermissionGroupInfo> mPermGroupsList - = new ArrayList<MyPermissionGroupInfo>(); - private final PermissionGroupInfoComparator mPermGroupComparator = - new PermissionGroupInfoComparator(); - private final PermissionInfoComparator mPermComparator = new PermissionInfoComparator(); - private final List<MyPermissionInfo> mPermsList = new ArrayList<MyPermissionInfo>(); - private final CharSequence mNewPermPrefix; - private String mPackageName; - - /** @hide */ - static class MyPermissionGroupInfo extends PermissionGroupInfo { - CharSequence mLabel; - - final ArrayList<MyPermissionInfo> mNewPermissions = new ArrayList<MyPermissionInfo>(); - final ArrayList<MyPermissionInfo> mAllPermissions = new ArrayList<MyPermissionInfo>(); - - MyPermissionGroupInfo(PermissionInfo perm) { - name = perm.packageName; - packageName = perm.packageName; - } - - MyPermissionGroupInfo(PermissionGroupInfo info) { - super(info); - } - - public Drawable loadGroupIcon(Context context, PackageManager pm) { - if (icon != 0) { - return loadUnbadgedIcon(pm); - } else { - return context.getDrawable(R.drawable.ic_perm_device_info); - } - } - } - - /** @hide */ - private static class MyPermissionInfo extends PermissionInfo { - CharSequence mLabel; - - /** - * PackageInfo.requestedPermissionsFlags for the new package being installed. - */ - int mNewReqFlags; - - /** - * PackageInfo.requestedPermissionsFlags for the currently installed - * package, if it is installed. - */ - int mExistingReqFlags; - - /** - * True if this should be considered a new permission. - */ - boolean mNew; - - MyPermissionInfo(PermissionInfo info) { - super(info); - } - } - - /** @hide */ - public static class PermissionItemView extends LinearLayout implements View.OnClickListener { - MyPermissionGroupInfo mGroup; - MyPermissionInfo mPerm; - AlertDialog mDialog; - private boolean mShowRevokeUI = false; - private String mPackageName; - - public PermissionItemView(Context context, AttributeSet attrs) { - super(context, attrs); - setClickable(true); - } - - public void setPermission(MyPermissionGroupInfo grp, MyPermissionInfo perm, - boolean first, CharSequence newPermPrefix, String packageName, - boolean showRevokeUI) { - mGroup = grp; - mPerm = perm; - mShowRevokeUI = showRevokeUI; - mPackageName = packageName; - - ImageView permGrpIcon = findViewById(R.id.perm_icon); - TextView permNameView = findViewById(R.id.perm_name); - - PackageManager pm = getContext().getPackageManager(); - Drawable icon = null; - if (first) { - icon = grp.loadGroupIcon(getContext(), pm); - } - CharSequence label = perm.mLabel; - if (perm.mNew && newPermPrefix != null) { - // If this is a new permission, format it appropriately. - SpannableStringBuilder builder = new SpannableStringBuilder(); - Parcel parcel = Parcel.obtain(); - TextUtils.writeToParcel(newPermPrefix, parcel, 0); - parcel.setDataPosition(0); - CharSequence newStr = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel); - parcel.recycle(); - builder.append(newStr); - builder.append(label); - label = builder; - } - - permGrpIcon.setImageDrawable(icon); - permNameView.setText(label); - setOnClickListener(this); - if (localLOGV) Log.i(TAG, "Made perm item " + perm.name - + ": " + label + " in group " + grp.name); - } - - @Override - public void onClick(View v) { - if (mGroup != null && mPerm != null) { - if (mDialog != null) { - mDialog.dismiss(); - } - PackageManager pm = getContext().getPackageManager(); - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(mGroup.mLabel); - if (mPerm.descriptionRes != 0) { - builder.setMessage(mPerm.loadDescription(pm)); - } else { - CharSequence appName; - try { - ApplicationInfo app = pm.getApplicationInfo(mPerm.packageName, 0); - appName = app.loadLabel(pm); - } catch (NameNotFoundException e) { - appName = mPerm.packageName; - } - StringBuilder sbuilder = new StringBuilder(128); - sbuilder.append(getContext().getString( - R.string.perms_description_app, appName)); - sbuilder.append("\n\n"); - sbuilder.append(mPerm.name); - builder.setMessage(sbuilder.toString()); - } - builder.setCancelable(true); - builder.setIcon(mGroup.loadGroupIcon(getContext(), pm)); - addRevokeUIIfNecessary(builder); - mDialog = builder.show(); - mDialog.setCanceledOnTouchOutside(true); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (mDialog != null) { - mDialog.dismiss(); - } - } - - private void addRevokeUIIfNecessary(AlertDialog.Builder builder) { - if (!mShowRevokeUI) { - return; - } - - final boolean isRequired = - ((mPerm.mExistingReqFlags & PackageInfo.REQUESTED_PERMISSION_REQUIRED) != 0); - - if (isRequired) { - return; - } - - DialogInterface.OnClickListener ocl = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - PackageManager pm = getContext().getPackageManager(); - pm.revokeRuntimePermission(mPackageName, mPerm.name, - new UserHandle(mContext.getUserId())); - PermissionItemView.this.setVisibility(View.GONE); - } - }; - builder.setNegativeButton(R.string.revoke, ocl); - builder.setPositiveButton(R.string.ok, null); - } - } - - private AppSecurityPermissions(Context context) { - mContext = context; - mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mPm = mContext.getPackageManager(); - // Pick up from framework resources instead. - mNewPermPrefix = mContext.getText(R.string.perms_new_perm_prefix); - } - - @UnsupportedAppUsage - public AppSecurityPermissions(Context context, String packageName) { - this(context); - mPackageName = packageName; - Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>(); - PackageInfo pkgInfo; - try { - pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); - } catch (NameNotFoundException e) { - Log.w(TAG, "Couldn't retrieve permissions for package:"+packageName); - return; - } - // Extract all user permissions - if((pkgInfo.applicationInfo != null) && (pkgInfo.applicationInfo.uid != -1)) { - getAllUsedPermissions(pkgInfo.applicationInfo.uid, permSet); - } - mPermsList.addAll(permSet); - setPermissions(mPermsList); - } - - public AppSecurityPermissions(Context context, PackageInfo info) { - this(context); - Set<MyPermissionInfo> permSet = new HashSet<MyPermissionInfo>(); - if(info == null) { - return; - } - mPackageName = info.packageName; - - // Convert to a PackageInfo - PackageInfo installedPkgInfo = null; - // Get requested permissions - if (info.requestedPermissions != null) { - try { - installedPkgInfo = mPm.getPackageInfo(info.packageName, - PackageManager.GET_PERMISSIONS); - } catch (NameNotFoundException e) { - } - extractPerms(info, permSet, installedPkgInfo); - } - // Get permissions related to shared user if any - if (info.sharedUserId != null) { - int sharedUid; - try { - sharedUid = mPm.getUidForSharedUser(info.sharedUserId); - getAllUsedPermissions(sharedUid, permSet); - } catch (NameNotFoundException e) { - Log.w(TAG, "Couldn't retrieve shared user id for: " + info.packageName); - } - } - // Retrieve list of permissions - mPermsList.addAll(permSet); - setPermissions(mPermsList); - } - /** * Utility to retrieve a view displaying a single permission. This provides * the old UI layout for permissions; it is only here for the device admin @@ -327,197 +47,6 @@ public class AppSecurityPermissions { description, dangerous, icon); } - private void getAllUsedPermissions(int sharedUid, Set<MyPermissionInfo> permSet) { - String sharedPkgList[] = mPm.getPackagesForUid(sharedUid); - if(sharedPkgList == null || (sharedPkgList.length == 0)) { - return; - } - for(String sharedPkg : sharedPkgList) { - getPermissionsForPackage(sharedPkg, permSet); - } - } - - private void getPermissionsForPackage(String packageName, Set<MyPermissionInfo> permSet) { - try { - PackageInfo pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS); - extractPerms(pkgInfo, permSet, pkgInfo); - } catch (NameNotFoundException e) { - Log.w(TAG, "Couldn't retrieve permissions for package: " + packageName); - } - } - - private void extractPerms(PackageInfo info, Set<MyPermissionInfo> permSet, - PackageInfo installedPkgInfo) { - String[] strList = info.requestedPermissions; - int[] flagsList = info.requestedPermissionsFlags; - if ((strList == null) || (strList.length == 0)) { - return; - } - for (int i=0; i<strList.length; i++) { - String permName = strList[i]; - try { - PermissionInfo tmpPermInfo = mPm.getPermissionInfo(permName, 0); - if (tmpPermInfo == null) { - continue; - } - int existingIndex = -1; - if (installedPkgInfo != null - && installedPkgInfo.requestedPermissions != null) { - for (int j=0; j<installedPkgInfo.requestedPermissions.length; j++) { - if (permName.equals(installedPkgInfo.requestedPermissions[j])) { - existingIndex = j; - break; - } - } - } - final int existingFlags = existingIndex >= 0 ? - installedPkgInfo.requestedPermissionsFlags[existingIndex] : 0; - if (!isDisplayablePermission(tmpPermInfo, flagsList[i], existingFlags)) { - // This is not a permission that is interesting for the user - // to see, so skip it. - continue; - } - final String origGroupName = tmpPermInfo.group; - String groupName = origGroupName; - if (groupName == null) { - groupName = tmpPermInfo.packageName; - tmpPermInfo.group = groupName; - } - MyPermissionGroupInfo group = mPermGroups.get(groupName); - if (group == null) { - PermissionGroupInfo grp = null; - if (origGroupName != null) { - grp = mPm.getPermissionGroupInfo(origGroupName, 0); - } - if (grp != null) { - group = new MyPermissionGroupInfo(grp); - } else { - // We could be here either because the permission - // didn't originally specify a group or the group it - // gave couldn't be found. In either case, we consider - // its group to be the permission's package name. - tmpPermInfo.group = tmpPermInfo.packageName; - group = mPermGroups.get(tmpPermInfo.group); - if (group == null) { - group = new MyPermissionGroupInfo(tmpPermInfo); - } - group = new MyPermissionGroupInfo(tmpPermInfo); - } - mPermGroups.put(tmpPermInfo.group, group); - } - final boolean newPerm = installedPkgInfo != null - && (existingFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) == 0; - MyPermissionInfo myPerm = new MyPermissionInfo(tmpPermInfo); - myPerm.mNewReqFlags = flagsList[i]; - myPerm.mExistingReqFlags = existingFlags; - // This is a new permission if the app is already installed and - // doesn't currently hold this permission. - myPerm.mNew = newPerm; - permSet.add(myPerm); - } catch (NameNotFoundException e) { - Log.i(TAG, "Ignoring unknown permission:"+permName); - } - } - } - - @UnsupportedAppUsage - public int getPermissionCount() { - return getPermissionCount(WHICH_ALL); - } - - private List<MyPermissionInfo> getPermissionList(MyPermissionGroupInfo grp, int which) { - if (which == WHICH_NEW) { - return grp.mNewPermissions; - } else { - return grp.mAllPermissions; - } - } - - public int getPermissionCount(int which) { - int N = 0; - for (int i=0; i<mPermGroupsList.size(); i++) { - N += getPermissionList(mPermGroupsList.get(i), which).size(); - } - return N; - } - - @UnsupportedAppUsage - public View getPermissionsView() { - return getPermissionsView(WHICH_ALL, false); - } - - public View getPermissionsViewWithRevokeButtons() { - return getPermissionsView(WHICH_ALL, true); - } - - public View getPermissionsView(int which) { - return getPermissionsView(which, false); - } - - private View getPermissionsView(int which, boolean showRevokeUI) { - LinearLayout permsView = (LinearLayout) mInflater.inflate(R.layout.app_perms_summary, null); - LinearLayout displayList = permsView.findViewById(R.id.perms_list); - View noPermsView = permsView.findViewById(R.id.no_permissions); - - displayPermissions(mPermGroupsList, displayList, which, showRevokeUI); - if (displayList.getChildCount() <= 0) { - noPermsView.setVisibility(View.VISIBLE); - } - - return permsView; - } - - /** - * Utility method that displays permissions from a map containing group name and - * list of permission descriptions. - */ - private void displayPermissions(List<MyPermissionGroupInfo> groups, - LinearLayout permListView, int which, boolean showRevokeUI) { - permListView.removeAllViews(); - - int spacing = (int)(8*mContext.getResources().getDisplayMetrics().density); - - for (int i=0; i<groups.size(); i++) { - MyPermissionGroupInfo grp = groups.get(i); - final List<MyPermissionInfo> perms = getPermissionList(grp, which); - for (int j=0; j<perms.size(); j++) { - MyPermissionInfo perm = perms.get(j); - View view = getPermissionItemView(grp, perm, j == 0, - which != WHICH_NEW ? mNewPermPrefix : null, showRevokeUI); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - if (j == 0) { - lp.topMargin = spacing; - } - if (j == grp.mAllPermissions.size()-1) { - lp.bottomMargin = spacing; - } - if (permListView.getChildCount() == 0) { - lp.topMargin *= 2; - } - permListView.addView(view, lp); - } - } - } - - private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp, - MyPermissionInfo perm, boolean first, CharSequence newPermPrefix, boolean showRevokeUI) { - return getPermissionItemView(mContext, mInflater, grp, perm, first, newPermPrefix, - mPackageName, showRevokeUI); - } - - private static PermissionItemView getPermissionItemView(Context context, LayoutInflater inflater, - MyPermissionGroupInfo grp, MyPermissionInfo perm, boolean first, - CharSequence newPermPrefix, String packageName, boolean showRevokeUI) { - PermissionItemView permView = (PermissionItemView)inflater.inflate( - (perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0 - ? R.layout.app_permission_item_money : R.layout.app_permission_item, - null); - permView.setPermission(grp, perm, first, newPermPrefix, packageName, showRevokeUI); - return permView; - } - private static View getPermissionItemViewOld(Context context, LayoutInflater inflater, CharSequence grpName, CharSequence permList, boolean dangerous, Drawable icon) { View permView = inflater.inflate(R.layout.app_permission_item_old, null); @@ -536,116 +65,4 @@ public class AppSecurityPermissions { } return permView; } - - private boolean isDisplayablePermission(PermissionInfo pInfo, int newReqFlags, - int existingReqFlags) { - final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; - final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL); - - // We do not show normal permissions in the UI. - if (isNormal) { - return false; - } - - final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS) - || ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_PRE23) != 0); - final boolean isRequired = - ((newReqFlags&PackageInfo.REQUESTED_PERMISSION_REQUIRED) != 0); - final boolean isDevelopment = - ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0); - final boolean wasGranted = - ((existingReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0); - final boolean isGranted = - ((newReqFlags&PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0); - - // Dangerous and normal permissions are always shown to the user if the permission - // is required, or it was previously granted - if (isDangerous && (isRequired || wasGranted || isGranted)) { - return true; - } - - // Development permissions are only shown to the user if they are already - // granted to the app -- if we are installing an app and they are not - // already granted, they will not be granted as part of the install. - if (isDevelopment && wasGranted) { - if (localLOGV) Log.i(TAG, "Special perm " + pInfo.name - + ": protlevel=0x" + Integer.toHexString(pInfo.protectionLevel)); - return true; - } - return false; - } - - private static class PermissionGroupInfoComparator implements Comparator<MyPermissionGroupInfo> { - private final Collator sCollator = Collator.getInstance(); - @Override - public final int compare(MyPermissionGroupInfo a, MyPermissionGroupInfo b) { - return sCollator.compare(a.mLabel, b.mLabel); - } - } - - private static class PermissionInfoComparator implements Comparator<MyPermissionInfo> { - private final Collator sCollator = Collator.getInstance(); - PermissionInfoComparator() { - } - public final int compare(MyPermissionInfo a, MyPermissionInfo b) { - return sCollator.compare(a.mLabel, b.mLabel); - } - } - - private void addPermToList(List<MyPermissionInfo> permList, - MyPermissionInfo pInfo) { - if (pInfo.mLabel == null) { - pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); - } - int idx = Collections.binarySearch(permList, pInfo, mPermComparator); - if(localLOGV) Log.i(TAG, "idx="+idx+", list.size="+permList.size()); - if (idx < 0) { - idx = -idx-1; - permList.add(idx, pInfo); - } - } - - private void setPermissions(List<MyPermissionInfo> permList) { - if (permList != null) { - // First pass to group permissions - for (MyPermissionInfo pInfo : permList) { - if(localLOGV) Log.i(TAG, "Processing permission:"+pInfo.name); - if(!isDisplayablePermission(pInfo, pInfo.mNewReqFlags, pInfo.mExistingReqFlags)) { - if(localLOGV) Log.i(TAG, "Permission:"+pInfo.name+" is not displayable"); - continue; - } - MyPermissionGroupInfo group = mPermGroups.get(pInfo.group); - if (group != null) { - pInfo.mLabel = pInfo.loadSafeLabel(mPm, 20000, - PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); - addPermToList(group.mAllPermissions, pInfo); - if (pInfo.mNew) { - addPermToList(group.mNewPermissions, pInfo); - } - } - } - } - - for (MyPermissionGroupInfo pgrp : mPermGroups.values()) { - if (pgrp.labelRes != 0 || pgrp.nonLocalizedLabel != null) { - pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); - } else { - ApplicationInfo app; - try { - app = mPm.getApplicationInfo(pgrp.packageName, 0); - pgrp.mLabel = app.loadSafeLabel(mPm, 20000, PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); - } catch (NameNotFoundException e) { - pgrp.mLabel = pgrp.loadSafeLabel(mPm, 20000, - PackageItemInfo.SAFE_LABEL_FLAG_TRIM - | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE); - } - } - mPermGroupsList.add(pgrp); - } - Collections.sort(mPermGroupsList, mPermGroupComparator); - } } diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index 81dab2f6aeef..8bc90a891352 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -389,14 +389,18 @@ public abstract class FileSystemProvider extends DocumentsProvider { * @param query the search condition used to match file names * @param projection projection of the returned cursor * @param exclusion absolute file paths to exclude from result - * @return cursor containing search result + * @param queryArgs the query arguments for search + * @return cursor containing search result. Include + * {@link ContentResolver#EXTRA_HONORED_ARGS} in {@link Cursor} + * extras {@link Bundle} when any QUERY_ARG_* value was honored + * during the preparation of the results. * @throws FileNotFoundException when root folder doesn't exist or search fails + * + * @see ContentResolver#EXTRA_HONORED_ARGS */ protected final Cursor querySearchDocuments( - File folder, String query, String[] projection, Set<String> exclusion) + File folder, String[] projection, Set<String> exclusion, Bundle queryArgs) throws FileNotFoundException { - - query = query.toLowerCase(); final MatrixCursor result = new MatrixCursor(resolveProjection(projection)); final LinkedList<File> pending = new LinkedList<>(); pending.add(folder); @@ -407,11 +411,18 @@ public abstract class FileSystemProvider extends DocumentsProvider { pending.add(child); } } - if (file.getName().toLowerCase().contains(query) - && !exclusion.contains(file.getAbsolutePath())) { + if (!exclusion.contains(file.getAbsolutePath()) && matchSearchQueryArguments(file, + queryArgs)) { includeFile(result, null, file); } } + + final String[] handledQueryArgs = DocumentsContract.getHandledQueryArguments(queryArgs); + if (handledQueryArgs.length > 0) { + final Bundle extras = new Bundle(); + extras.putStringArray(ContentResolver.EXTRA_HONORED_ARGS, handledQueryArgs); + result.setExtras(extras); + } return result; } @@ -457,6 +468,34 @@ public abstract class FileSystemProvider extends DocumentsProvider { } } + /** + * Test if the file matches the query arguments. + * + * @param file the file to test + * @param queryArgs the query arguments + */ + private boolean matchSearchQueryArguments(File file, Bundle queryArgs) { + if (file == null) { + return false; + } + + final String fileMimeType; + final String fileName = file.getName(); + + if (file.isDirectory()) { + fileMimeType = DocumentsContract.Document.MIME_TYPE_DIR; + } else { + int dotPos = fileName.lastIndexOf('.'); + if (dotPos < 0) { + return false; + } + final String extension = fileName.substring(dotPos + 1); + fileMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + } + return DocumentsContract.matchSearchQueryArguments(queryArgs, fileName, fileMimeType, + file.lastModified(), file.length()); + } + private void scanFile(File visibleFile) { final Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(visibleFile)); diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java index 0baf73cc024a..02c9542fa40d 100644 --- a/core/java/com/android/internal/os/BatterySipper.java +++ b/core/java/com/android/internal/os/BatterySipper.java @@ -130,6 +130,10 @@ public class BatterySipper implements Comparable<BatterySipper> { public double wakeLockPowerMah; public double wifiPowerMah; + // **************** + // This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto) + // so the ordinal values (and therefore the order) must never change. + // **************** public enum DrainType { AMBIENT_DISPLAY, @UnsupportedAppUsage diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 8f87f9193c1f..8bdb000aad0e 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -173,12 +173,13 @@ public class ZygoteInit { } native private static void nativePreloadAppProcessHALs(); + native private static void nativePreloadOpenGL(); private static void preloadOpenGL() { String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false) && (driverPackageName == null || driverPackageName.isEmpty())) { - EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + nativePreloadOpenGL(); } } diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp index 8ace8da77b2f..5887fa7a0841 100644 --- a/core/jni/android_hardware_input_InputApplicationHandle.cpp +++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp @@ -135,13 +135,13 @@ static const JNINativeMethod gInputApplicationHandleMethods[] = { LOG_FATAL_IF(! (var), "Unable to find field " fieldName); int register_android_server_InputApplicationHandle(JNIEnv* env) { - int res = jniRegisterNativeMethods(env, "com/android/server/input/InputApplicationHandle", + int res = jniRegisterNativeMethods(env, "android/view/InputApplicationHandle", gInputApplicationHandleMethods, NELEM(gInputApplicationHandleMethods)); (void) res; // Faked use when LOG_NDEBUG. LOG_FATAL_IF(res < 0, "Unable to register native methods."); jclass clazz; - FIND_CLASS(clazz, "com/android/server/input/InputApplicationHandle"); + FIND_CLASS(clazz, "android/view/InputApplicationHandle"); GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz, "ptr", "J"); diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index 5b722416487b..6ecb5de35ae1 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -221,20 +221,20 @@ static const JNINativeMethod gInputWindowHandleMethods[] = { LOG_FATAL_IF(! (var), "Unable to find field " fieldName); int register_android_server_InputWindowHandle(JNIEnv* env) { - int res = jniRegisterNativeMethods(env, "com/android/server/input/InputWindowHandle", + int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle", gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods)); (void) res; // Faked use when LOG_NDEBUG. LOG_FATAL_IF(res < 0, "Unable to register native methods."); jclass clazz; - FIND_CLASS(clazz, "com/android/server/input/InputWindowHandle"); + FIND_CLASS(clazz, "android/view/InputWindowHandle"); GET_FIELD_ID(gInputWindowHandleClassInfo.ptr, clazz, "ptr", "J"); GET_FIELD_ID(gInputWindowHandleClassInfo.inputApplicationHandle, clazz, - "inputApplicationHandle", "Lcom/android/server/input/InputApplicationHandle;"); + "inputApplicationHandle", "Landroid/view/InputApplicationHandle;"); GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz, "inputChannel", "Landroid/view/InputChannel;"); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index b2d44e73d861..7b564ae162ce 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -24,9 +24,13 @@ #include <sys/system_properties.h> #include <sys/types.h> #include <sys/wait.h> +#include <unistd.h> #include <private/android_filesystem_config.h> // for AID_SYSTEM +#include <sstream> +#include <string> + #include "android-base/logging.h" #include "android-base/properties.h" #include "android-base/stringprintf.h" @@ -38,6 +42,7 @@ #include "androidfw/AssetManager2.h" #include "androidfw/AttributeResolution.h" #include "androidfw/MutexGuard.h" +#include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" #include "core_jni_helpers.h" #include "jni.h" @@ -54,6 +59,7 @@ extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); using ::android::base::StringPrintf; +using ::android::util::ExecuteBinary; namespace android { @@ -161,18 +167,20 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::IDMAP_DIR; // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined, - // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR. + // use VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in + // addition to VENDOR_OVERLAY_DIR. std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY, ""); if (!overlay_theme_path.empty()) { - overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path; + overlay_theme_path = + std::string(AssetManager::VENDOR_OVERLAY_DIR) + "/" + overlay_theme_path; if (stat(overlay_theme_path.c_str(), &st) == 0) { argv[argc++] = overlay_theme_path.c_str(); } } - if (stat(AssetManager::OVERLAY_DIR, &st) == 0) { - argv[argc++] = AssetManager::OVERLAY_DIR; + if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::VENDOR_OVERLAY_DIR; } if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { @@ -200,6 +208,75 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } } +static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env, + jclass /*clazz*/) { + // --input-directory can be given multiple times, but idmap2 expects the directory to exist + std::vector<std::string> input_dirs; + struct stat st; + if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR); + } + + if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR); + } + + if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR); + } + + if (input_dirs.empty()) { + LOG(WARNING) << "no directories for idmap2 to scan"; + return env->NewObjectArray(0, g_stringClass, nullptr); + } + + std::vector<std::string> argv{"/system/bin/idmap2", + "scan", + "--recursive", + "--target-package-name", "android", + "--target-apk-path", "/system/framework/framework-res.apk", + "--output-directory", "/data/resource-cache"}; + + for (const auto& dir : input_dirs) { + argv.push_back("--input-directory"); + argv.push_back(dir); + } + + const auto result = ExecuteBinary(argv); + + if (!result) { + LOG(ERROR) << "failed to execute idmap2"; + return nullptr; + } + + if (result->status != 0) { + LOG(ERROR) << "idmap2: " << result->stderr; + return nullptr; + } + + std::vector<std::string> idmap_paths; + std::istringstream input(result->stdout); + std::string path; + while (std::getline(input, path)) { + idmap_paths.push_back(path); + } + + jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr); + if (array == nullptr) { + return nullptr; + } + for (size_t i = 0; i < idmap_paths.size(); i++) { + const std::string path = idmap_paths[i]; + jstring java_string = env->NewStringUTF(path.c_str()); + if (env->ExceptionCheck()) { + return nullptr; + } + env->SetObjectArrayElement(array, i, java_string); + env->DeleteLocalRef(java_string); + } + return array; +} + static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref, uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) { env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType); @@ -1405,6 +1482,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { // System/idmap related methods. {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps}, + {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;", + (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid}, // Global management/debug methods. {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount}, diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 2f179078aed8..fb6be6b4c91a 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -249,6 +249,24 @@ static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobjec } } +static jobject android_view_InputChannel_nativeGetToken(JNIEnv* env, jobject obj) { + NativeInputChannel* nativeInputChannel = + android_view_InputChannel_getNativeInputChannel(env, obj); + if (nativeInputChannel) { + return javaObjectForIBinder(env, nativeInputChannel->getInputChannel()->getToken()); + } + return 0; +} + +static void android_view_InputChannel_nativeSetToken(JNIEnv* env, jobject obj, jobject tokenObj) { + NativeInputChannel* nativeInputChannel = + android_view_InputChannel_getNativeInputChannel(env, obj); + sp<IBinder> token = ibinderForJavaObject(env, tokenObj); + if (nativeInputChannel != nullptr) { + nativeInputChannel->getInputChannel()->setToken(token); + } +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputChannelMethods[] = { @@ -267,6 +285,10 @@ static const JNINativeMethod gInputChannelMethods[] = { (void*)android_view_InputChannel_nativeGetName }, { "nativeDup", "(Landroid/view/InputChannel;)V", (void*)android_view_InputChannel_nativeDup }, + { "nativeGetToken", "()Landroid/os/IBinder;", + (void*)android_view_InputChannel_nativeGetToken }, + { "nativeSetToken", "(Landroid/os/IBinder;)V", + (void*)android_view_InputChannel_nativeSetToken } }; int register_android_view_InputChannel(JNIEnv* env) { diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 4eda3abdd0d6..ec9c8606e8df 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -19,6 +19,7 @@ #include "android_os_Parcel.h" #include "android_util_Binder.h" +#include "android_hardware_input_InputWindowHandle.h" #include "android/graphics/Bitmap.h" #include "android/graphics/GraphicsJNI.h" #include "android/graphics/Region.h" @@ -324,6 +325,18 @@ static void nativeSetAlpha(JNIEnv* env, jclass clazz, jlong transactionObj, transaction->setAlpha(ctrl, alpha); } +static void nativeSetInputWindowInfo(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jobject inputWindow) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + + sp<NativeInputWindowHandle> handle = android_server_InputWindowHandle_getHandle( + env, inputWindow); + handle->updateInfo(); + + SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + transaction->setInputWindowInfo(ctrl, *handle->getInfo()); +} + static void nativeSetColor(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jfloatArray fColor) { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); @@ -930,6 +943,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeScreenshot }, {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;", (void*)nativeCaptureLayers }, + {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V", + (void*)nativeSetInputWindowInfo }, }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp index 258a55c7123a..ac0e60030fc5 100644 --- a/core/jni/com_android_internal_os_ZygoteInit.cpp +++ b/core/jni/com_android_internal_os_ZygoteInit.cpp @@ -16,21 +16,58 @@ #define LOG_TAG "Zygote" +#include <EGL/egl.h> #include <ui/GraphicBufferMapper.h> #include "core_jni_helpers.h" namespace { +// Shadow call stack (SCS) is a security mitigation that uses a separate stack +// (the SCS) for return addresses. In versions of Android newer than P, the +// compiler cooperates with the system to ensure that the SCS address is always +// stored in register x18, as long as the app was compiled with a new enough +// compiler and does not use features that rely on SP-HALs (this restriction is +// because the SP-HALs might not preserve x18 due to potentially having been +// compiled with an old compiler as a consequence of Treble; it generally means +// that the app must be a system app without a UI). This struct is used to +// temporarily store the address on the stack while preloading the SP-HALs, so +// that such apps can use the same zygote as everything else. +struct ScopedSCSExit { +#ifdef __aarch64__ + void* scs; + + ScopedSCSExit() { + __asm__ __volatile__("str x18, [%0]" ::"r"(&scs)); + } + + ~ScopedSCSExit() { + __asm__ __volatile__("ldr x18, [%0]; str xzr, [%0]" ::"r"(&scs)); + } +#else + // Silence unused variable warnings in non-SCS builds. + ScopedSCSExit() {} + ~ScopedSCSExit() {} +#endif +}; + void android_internal_os_ZygoteInit_nativePreloadAppProcessHALs(JNIEnv* env, jclass) { + ScopedSCSExit x; android::GraphicBufferMapper::preloadHal(); // Add preloading here for other HALs that are (a) always passthrough, and // (b) loaded by most app processes. } +void android_internal_os_ZygoteInit_nativePreloadOpenGL(JNIEnv* env, jclass) { + ScopedSCSExit x; + eglGetDisplay(EGL_DEFAULT_DISPLAY); +} + const JNINativeMethod gMethods[] = { { "nativePreloadAppProcessHALs", "()V", (void*)android_internal_os_ZygoteInit_nativePreloadAppProcessHALs }, + { "nativePreloadOpenGL", "()V", + (void*)android_internal_os_ZygoteInit_nativePreloadOpenGL }, }; } // anonymous namespace diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 2465759a9fa5..a398e498a301 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -85,7 +85,7 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { // See AssetManager.cpp for more details on overlay-subdir. static const char* kOverlayDir = "/system/vendor/overlay/"; static const char* kVendorOverlayDir = "/vendor/overlay"; - static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/"; static const char* kSystemProductOverlayDir = "/system/product/overlay/"; static const char* kProductOverlayDir = "/product/overlay"; static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/"; @@ -93,7 +93,7 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) - || android::base::StartsWith(path, kOverlaySubdir) + || android::base::StartsWith(path, kVendorOverlaySubdir) || android::base::StartsWith(path, kVendorOverlayDir) || android::base::StartsWith(path, kSystemProductOverlayDir) || android::base::StartsWith(path, kProductOverlayDir) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 297687933018..62896bed05ad 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -746,7 +746,7 @@ android:description="@string/permdesc_receiveMms" android:protectionLevel="dangerous" /> - <!-- @TestApi Allows an application to read previously received cell broadcast + <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast messages and to register a content observer to get notifications when a cell broadcast has been received and added to the database. For emergency alerts, the database is updated immediately after the diff --git a/core/res/res/values/colors_car.xml b/core/res/res/values/colors_car.xml index 32671ac8f752..ea7c00919527 100644 --- a/core/res/res/values/colors_car.xml +++ b/core/res/res/values/colors_car.xml @@ -284,4 +284,8 @@ <color name="car_red_500a">#ffd50000</color> <color name="car_red_a700">#ffd50000</color> + + <color name="car_keyboard_divider_line">#38ffffff</color> + <color name="car_keyboard_text_primary_color">@color/car_grey_50</color> + <color name="car_keyboard_text_secondary_color">#8af8f9fa</color> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 26f3370f0dc5..829d6f57f896 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -55,6 +55,8 @@ <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item> <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item> <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_microphone</xliff:g></item> + <item><xliff:g id="id">@string/status_bar_camera</xliff:g></item> <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item> </string-array> @@ -87,6 +89,8 @@ <string translatable="false" name="status_bar_mobile">mobile</string> <string translatable="false" name="status_bar_vpn">vpn</string> <string translatable="false" name="status_bar_ethernet">ethernet</string> + <string translatable="false" name="status_bar_microphone">microphone</string> + <string translatable="false" name="status_bar_camera">camera</string> <string translatable="false" name="status_bar_airplane">airplane</string> <!-- Flag indicating whether the surface flinger has limited diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index c1ca33e430cd..5014a29f4eab 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -34,7 +34,6 @@ <!-- The diff between keyline 1 and keyline 3. --> <dimen name="car_keyline_1_keyline_3_diff">88dp</dimen> <dimen name="car_dialog_action_bar_height">@dimen/car_card_action_bar_height</dimen> - <dimen name="car_primary_icon_size">44dp</dimen> <!-- Text size for car --> <dimen name="car_title_size">32sp</dimen> @@ -56,16 +55,19 @@ <!-- Common icon size for car app --> <dimen name="car_icon_size">56dp</dimen> + <dimen name="car_primary_icon_size">44dp</dimen> + <dimen name="car_secondary_icon_size">36dp</dimen> - <dimen name="car_card_header_height">96dp</dimen> - <dimen name="car_card_action_bar_height">96dp</dimen> + <dimen name="car_card_header_height">76dp</dimen> + <dimen name="car_card_action_bar_height">76dp</dimen> <!-- Paddings --> - <dimen name="car_padding_1">4dp</dimen> - <dimen name="car_padding_2">10dp</dimen> - <dimen name="car_padding_3">16dp</dimen> - <dimen name="car_padding_4">28dp</dimen> - <dimen name="car_padding_5">32dp</dimen> + <dimen name="car_padding_0">4dp</dimen> + <dimen name="car_padding_1">8dp</dimen> + <dimen name="car_padding_2">16dp</dimen> + <dimen name="car_padding_3">28dp</dimen> + <dimen name="car_padding_4">32dp</dimen> + <dimen name="car_padding_5">64dp</dimen> <!-- Radius --> <dimen name="car_radius_1">4dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4eb723eb973d..626206b9b9d9 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2808,6 +2808,8 @@ <java-symbol type="string" name="status_bar_mobile" /> <java-symbol type="string" name="status_bar_ethernet" /> <java-symbol type="string" name="status_bar_vpn" /> + <java-symbol type="string" name="status_bar_microphone" /> + <java-symbol type="string" name="status_bar_camera" /> <!-- Locale picker --> <java-symbol type="id" name="locale_search_menu" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 8c91c370fcf6..002b6a84f592 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -494,6 +494,7 @@ public class SettingsBackupTest { 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_PNO_RECENCY_SORTING_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/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java index f2efabf5f722..88d162b34144 100644 --- a/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/ModelFileManagerTest.java @@ -203,6 +203,28 @@ public class ModelFileManagerTest { } @Test + public void findBestModel_languageIsMoreImportantThanVersion_bestModelComesFirst() { + ModelFileManager.ModelFile matchLocaleModel = + new ModelFileManager.ModelFile( + new File("/path/b"), 1, + Collections.singletonList(Locale.forLanguageTag("ja")), false); + + ModelFileManager.ModelFile languageIndependentModel = + new ModelFileManager.ModelFile( + new File("/path/a"), 2, + Collections.emptyList(), true); + when(mModelFileSupplier.get()) + .thenReturn( + Arrays.asList(matchLocaleModel, languageIndependentModel)); + + ModelFileManager.ModelFile bestModelFile = + mModelFileManager.findBestModelFile( + LocaleList.forLanguageTags("ja")); + + assertThat(bestModelFile).isEqualTo(matchLocaleModel); + } + + @Test public void modelFileEquals() { ModelFileManager.ModelFile modelA = new ModelFileManager.ModelFile( diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java index e81f6789185e..7467114a7596 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java @@ -41,6 +41,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.format.DateUtils; +import android.util.StatsLog; import junit.framework.TestCase; @@ -258,6 +259,36 @@ public class BatteryStatsHelperTest extends TestCase { assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS); } + @Test + public void testDrainTypesSyncedWithProto() { + assertEquals(BatterySipper.DrainType.AMBIENT_DISPLAY.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__AMBIENT_DISPLAY); + // AtomsProto has no "APP" + assertEquals(BatterySipper.DrainType.BLUETOOTH.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__BLUETOOTH); + assertEquals(BatterySipper.DrainType.CAMERA.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CAMERA); + assertEquals(BatterySipper.DrainType.CELL.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__CELL); + assertEquals(BatterySipper.DrainType.FLASHLIGHT.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__FLASHLIGHT); + assertEquals(BatterySipper.DrainType.IDLE.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__IDLE); + assertEquals(BatterySipper.DrainType.MEMORY.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__MEMORY); + assertEquals(BatterySipper.DrainType.OVERCOUNTED.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__OVERCOUNTED); + assertEquals(BatterySipper.DrainType.PHONE.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__PHONE); + assertEquals(BatterySipper.DrainType.SCREEN.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__SCREEN); + assertEquals(BatterySipper.DrainType.UNACCOUNTED.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__UNACCOUNTED); + // AtomsProto has no "USER" + assertEquals(BatterySipper.DrainType.WIFI.ordinal(), + StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER__DRAIN_TYPE__WIFI); + } + private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah, int uidCode, boolean isUidNull) { final BatterySipper sipper = mock(BatterySipper.class); diff --git a/data/etc/Android.mk b/data/etc/Android.mk index 936ad22d4fc5..d24c140ad19a 100644 --- a/data/etc/Android.mk +++ b/data/etc/Android.mk @@ -47,3 +47,11 @@ LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/sysconfig LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) + +######################## +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.timezone.updater.xml +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_RELATIVE_PATH := permissions +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) diff --git a/data/etc/com.android.timezone.updater.xml b/data/etc/com.android.timezone.updater.xml new file mode 100644 index 000000000000..60a66e22027d --- /dev/null +++ b/data/etc/com.android.timezone.updater.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<permissions> + <privapp-permissions package="com.android.timezone.updater"> + <permission name="android.permission.QUERY_TIME_ZONE_RULES" /> + <permission name="android.permission.UPDATE_TIME_ZONE_RULES" /> + </privapp-permissions> +</permissions> diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 68f24fb7b661..a4c5ed2ee30f 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -173,6 +173,7 @@ <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" /> <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" /> + <assign-permission name="android.permission.BATTERY_STATS" uid="statsd" /> <assign-permission name="android.permission.DUMP" uid="statsd" /> <assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" /> <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" /> diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index c10e482f1d33..835b735ad55f 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -38,11 +38,13 @@ import android.security.keymaster.KeymasterBlob; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; import android.security.keymaster.OperationResult; +import android.security.keystore.IKeystoreService; import android.security.keystore.KeyExpiredException; import android.security.keystore.KeyNotYetValidException; import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; +import android.security.keystore.KeystoreResponse; import android.security.keystore.StrongBoxUnavailableException; import android.security.keystore.UserNotAuthenticatedException; import android.util.Log; @@ -52,8 +54,11 @@ import java.math.BigInteger; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; +import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import sun.security.util.ObjectIdentifier; import sun.security.x509.AlgorithmId; @@ -303,6 +308,31 @@ public class KeyStore { } } + /** + * List uids of all keys that are auth bound to the current user. + * Only system is allowed to call this method. + */ + @UnsupportedAppUsage + public int[] listUidsOfAuthBoundKeys() { + final int MAX_RESULT_SIZE = 100; + int[] uidsOut = new int[MAX_RESULT_SIZE]; + try { + int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut); + if (rc != NO_ERROR) { + Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc)); + return null; + } + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return null; + } catch (android.os.ServiceSpecificException e) { + Log.w(TAG, "KeyStore exception", e); + return null; + } + // Remove any 0 entries + return Arrays.stream(uidsOut).filter(x -> x > 0).toArray(); + } + public String[] list(String prefix) { return list(prefix, UID_SELF); } @@ -451,27 +481,107 @@ public class KeyStore { public boolean addRngEntropy(byte[] data, int flags) { try { - return mBinder.addRngEntropy(data, flags) == NO_ERROR; + KeystoreResultPromise promise = new KeystoreResultPromise(); + int errorCode = mBinder.addRngEntropy(promise, data, flags); + if (errorCode == NO_ERROR) { + return promise.getFuture().get().getErrorCode() == NO_ERROR; + } else { + return false; + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "AddRngEntropy completed with exception", e); + return false; } } + private class KeyCharacteristicsCallbackResult { + private KeystoreResponse keystoreResponse; + private KeyCharacteristics keyCharacteristics; + + public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse, + KeyCharacteristics keyCharacteristics) { + this.keystoreResponse = keystoreResponse; + this.keyCharacteristics = keyCharacteristics; + } + + public KeystoreResponse getKeystoreResponse() { + return keystoreResponse; + } + + public void setKeystoreResponse(KeystoreResponse keystoreResponse) { + this.keystoreResponse = keystoreResponse; + } + + public KeyCharacteristics getKeyCharacteristics() { + return keyCharacteristics; + } + + public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) { + this.keyCharacteristics = keyCharacteristics; + } + } + + private class KeyCharacteristicsPromise + extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub { + final private CompletableFuture<KeyCharacteristicsCallbackResult> future = + new CompletableFuture<KeyCharacteristicsCallbackResult>(); + @Override + public void onFinished(KeystoreResponse keystoreResponse, + KeyCharacteristics keyCharacteristics) + throws android.os.RemoteException { + future.complete( + new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics)); + } + public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() { + return future; + } + }; + + private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid, + int flags, KeyCharacteristics outCharacteristics) + throws RemoteException, ExecutionException, InterruptedException { + KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); + int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags); + if (error != NO_ERROR) { + Log.e(TAG, "generateKeyInternal failed on request " + error); + return error; + } + + KeyCharacteristicsCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error != NO_ERROR) { + Log.e(TAG, "generateKeyInternal failed on response " + error); + return error; + } + KeyCharacteristics characteristics = result.getKeyCharacteristics(); + if (characteristics == null) { + Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error); + return SYSTEM_ERROR; + } + outCharacteristics.shallowCopyFrom(characteristics); + return NO_ERROR; + } + public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid, int flags, KeyCharacteristics outCharacteristics) { try { entropy = entropy != null ? entropy : new byte[0]; args = args != null ? args : new KeymasterArguments(); - int error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); + int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics); if (error == KEY_ALREADY_EXISTS) { mBinder.del(alias, uid); - error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); + error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics); } return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "generateKey completed with exception", e); + return SYSTEM_ERROR; } } @@ -485,10 +595,24 @@ public class KeyStore { try { clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]); appId = appId != null ? appId : new KeymasterBlob(new byte[0]); - return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics); + KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); + int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid); + if (error != NO_ERROR) return error; + + KeyCharacteristicsCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error != NO_ERROR) return error; + + KeyCharacteristics characteristics = result.getKeyCharacteristics(); + if (characteristics == null) return SYSTEM_ERROR; + outCharacteristics.shallowCopyFrom(characteristics); + return NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "GetKeyCharacteristics completed with exception", e); + return SYSTEM_ERROR; } } @@ -497,20 +621,40 @@ public class KeyStore { return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics); } + private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData, + int uid, int flags, KeyCharacteristics outCharacteristics) + throws RemoteException, ExecutionException, InterruptedException { + KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); + int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags); + if (error != NO_ERROR) return error; + + KeyCharacteristicsCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error != NO_ERROR) return error; + + KeyCharacteristics characteristics = result.getKeyCharacteristics(); + if (characteristics == null) return SYSTEM_ERROR; + outCharacteristics.shallowCopyFrom(characteristics); + return NO_ERROR; + } + public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics) { try { - int error = mBinder.importKey(alias, args, format, keyData, uid, flags, + int error = importKeyInternal(alias, args, format, keyData, uid, flags, outCharacteristics); if (error == KEY_ALREADY_EXISTS) { mBinder.del(alias, uid); - error = mBinder.importKey(alias, args, format, keyData, uid, flags, + error = importKeyInternal(alias, args, format, keyData, uid, flags, outCharacteristics); } return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "ImportKey completed with exception", e); + return SYSTEM_ERROR; } } @@ -578,34 +722,79 @@ public class KeyStore { return true; } + private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey, + String wrappingKeyAlias, + byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, + KeyCharacteristics outCharacteristics) + throws RemoteException, ExecutionException, InterruptedException { + KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise(); + int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + maskingKey, args, rootSid, fingerprintSid); + if (error != NO_ERROR) return error; + + KeyCharacteristicsCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error != NO_ERROR) return error; + + KeyCharacteristics characteristics = result.getKeyCharacteristics(); + if (characteristics == null) return SYSTEM_ERROR; + outCharacteristics.shallowCopyFrom(characteristics); + return NO_ERROR; + } + public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics) { + // TODO b/119217337 uid parameter gets silently ignored. try { - int error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid, outCharacteristics); if (error == KEY_ALREADY_EXISTS) { - mBinder.del(wrappedKeyAlias, -1); - error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + mBinder.del(wrappedKeyAlias, UID_SELF); + error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid, outCharacteristics); } return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "ImportWrappedKey completed with exception", e); + return SYSTEM_ERROR; } } + private class ExportKeyPromise + extends android.security.keystore.IKeystoreExportKeyCallback.Stub { + final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>(); + @Override + public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException { + future.complete(exportKeyResult); + } + public final CompletableFuture<ExportResult> getFuture() { + return future; + } + }; + public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, KeymasterBlob appId, int uid) { try { clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]); appId = appId != null ? appId : new KeymasterBlob(new byte[0]); - return mBinder.exportKey(alias, format, clientId, appId, uid); + ExportKeyPromise promise = new ExportKeyPromise(); + int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid); + if (error == NO_ERROR) { + return promise.getFuture().get(); + } else { + return new ExportResult(error); + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return null; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "ExportKey completed with exception", e); + return null; } } public ExportResult exportKey(String alias, int format, KeymasterBlob clientId, @@ -613,15 +802,37 @@ public class KeyStore { return exportKey(alias, format, clientId, appId, UID_SELF); } + private class OperationPromise + extends android.security.keystore.IKeystoreOperationResultCallback.Stub { + final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>(); + @Override + public void onFinished(OperationResult operationResult) throws android.os.RemoteException { + future.complete(operationResult); + } + public final CompletableFuture<OperationResult> getFuture() { + return future; + } + }; + public OperationResult begin(String alias, int purpose, boolean pruneable, KeymasterArguments args, byte[] entropy, int uid) { try { args = args != null ? args : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; - return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid); + OperationPromise promise = new OperationPromise(); + int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args, + entropy, uid); + if (errorCode == NO_ERROR) { + return promise.getFuture().get(); + } else { + return new OperationResult(errorCode); + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return null; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "Begin completed with exception", e); + return null; } } @@ -636,10 +847,19 @@ public class KeyStore { try { arguments = arguments != null ? arguments : new KeymasterArguments(); input = input != null ? input : new byte[0]; - return mBinder.update(token, arguments, input); + OperationPromise promise = new OperationPromise(); + int errorCode = mBinder.update(promise, token, arguments, input); + if (errorCode == NO_ERROR) { + return promise.getFuture().get(); + } else { + return new OperationResult(errorCode); + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return null; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "Update completed with exception", e); + return null; } } @@ -649,10 +869,19 @@ public class KeyStore { arguments = arguments != null ? arguments : new KeymasterArguments(); entropy = entropy != null ? entropy : new byte[0]; signature = signature != null ? signature : new byte[0]; - return mBinder.finish(token, arguments, signature, entropy); + OperationPromise promise = new OperationPromise(); + int errorCode = mBinder.finish(promise, token, arguments, signature, entropy); + if (errorCode == NO_ERROR) { + return promise.getFuture().get(); + } else { + return new OperationResult(errorCode); + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return null; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "Finish completed with exception", e); + return null; } } @@ -660,12 +889,33 @@ public class KeyStore { return finish(token, arguments, signature, null); } + private class KeystoreResultPromise + extends android.security.keystore.IKeystoreResponseCallback.Stub { + final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>(); + @Override + public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException { + future.complete(keystoreResponse); + } + public final CompletableFuture<KeystoreResponse> getFuture() { + return future; + } + }; + public int abort(IBinder token) { try { - return mBinder.abort(token); + KeystoreResultPromise promise = new KeystoreResultPromise(); + int errorCode = mBinder.abort(promise, token); + if (errorCode == NO_ERROR) { + return promise.getFuture().get().getErrorCode(); + } else { + return errorCode; + } } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "Abort completed with exception", e); + return SYSTEM_ERROR; } } @@ -747,6 +997,47 @@ public class KeyStore { return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword); } + private class KeyAttestationCallbackResult { + private KeystoreResponse keystoreResponse; + private KeymasterCertificateChain certificateChain; + + public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse, + KeymasterCertificateChain certificateChain) { + this.keystoreResponse = keystoreResponse; + this.certificateChain = certificateChain; + } + + public KeystoreResponse getKeystoreResponse() { + return keystoreResponse; + } + + public void setKeystoreResponse(KeystoreResponse keystoreResponse) { + this.keystoreResponse = keystoreResponse; + } + + public KeymasterCertificateChain getCertificateChain() { + return certificateChain; + } + + public void setCertificateChain(KeymasterCertificateChain certificateChain) { + this.certificateChain = certificateChain; + } + } + + private class CertificateChainPromise + extends android.security.keystore.IKeystoreCertificateChainCallback.Stub { + final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>(); + @Override + public void onFinished(KeystoreResponse keystoreResponse, + KeymasterCertificateChain certificateChain) throws android.os.RemoteException { + future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain)); + } + public final CompletableFuture<KeyAttestationCallbackResult> getFuture() { + return future; + } + }; + + public int attestKey( String alias, KeymasterArguments params, KeymasterCertificateChain outChain) { try { @@ -756,10 +1047,21 @@ public class KeyStore { if (outChain == null) { outChain = new KeymasterCertificateChain(); } - return mBinder.attestKey(alias, params, outChain); + CertificateChainPromise promise = new CertificateChainPromise(); + int error = mBinder.attestKey(promise, alias, params); + if (error != NO_ERROR) return error; + KeyAttestationCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error == NO_ERROR) { + outChain.shallowCopyFrom(result.getCertificateChain()); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "AttestKey completed with exception", e); + return SYSTEM_ERROR; } } @@ -771,10 +1073,21 @@ public class KeyStore { if (outChain == null) { outChain = new KeymasterCertificateChain(); } - return mBinder.attestDeviceIds(params, outChain); + CertificateChainPromise promise = new CertificateChainPromise(); + int error = mBinder.attestDeviceIds(promise, params); + if (error != NO_ERROR) return error; + KeyAttestationCallbackResult result = promise.getFuture().get(); + error = result.getKeystoreResponse().getErrorCode(); + if (error == NO_ERROR) { + outChain.shallowCopyFrom(result.getCertificateChain()); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "AttestDevicdeIds completed with exception", e); + return SYSTEM_ERROR; } } diff --git a/keystore/java/android/security/keystore/KeystoreResponse.java b/keystore/java/android/security/keystore/KeystoreResponse.java new file mode 100644 index 000000000000..3a229cb610a8 --- /dev/null +++ b/keystore/java/android/security/keystore/KeystoreResponse.java @@ -0,0 +1,78 @@ +/* + * 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.security.keystore; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelFormatException; + +/** + * The Java side of the KeystoreResponse. + * <p> + * Serialization code for this and subclasses must be kept in sync with system/security/keystore. + * @hide + */ +public class KeystoreResponse implements Parcelable { + public final int error_code_; + public final String error_msg_; + + public static final Parcelable.Creator<KeystoreResponse> CREATOR = new + Parcelable.Creator<KeystoreResponse>() { + @Override + public KeystoreResponse createFromParcel(Parcel in) { + final int error_code = in.readInt(); + final String error_msg = in.readString(); + return new KeystoreResponse(error_code, error_msg); + } + + @Override + public KeystoreResponse[] newArray(int size) { + return new KeystoreResponse[size]; + } + }; + + protected KeystoreResponse(int error_code, String error_msg) { + this.error_code_ = error_code; + this.error_msg_ = error_msg; + } + + /** + * @return the error_code_ + */ + public final int getErrorCode() { + return error_code_; + } + + /** + * @return the error_msg_ + */ + public final String getErrorMessage() { + return error_msg_; + } + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(error_code_); + out.writeString(error_msg_); + } +} diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 843c1461e21b..1cb0d25d8c08 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -72,7 +72,7 @@ static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; -const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index cdb87bcb8e11..e22e2d239a55 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -59,13 +59,13 @@ class AssetManager : public AAssetManager { public: static const char* RESOURCES_FILENAME; static const char* IDMAP_BIN; - static const char* OVERLAY_DIR; + static const char* VENDOR_OVERLAY_DIR; static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay - * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to - * OVERLAY_DIR. + * APKs in VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in + * addition to VENDOR_OVERLAY_DIR. */ static const char* OVERLAY_THEME_DIR_PROPERTY; static const char* TARGET_PACKAGE_NAME; diff --git a/libs/services/src/os/StatsLogEventWrapper.cpp b/libs/services/src/os/StatsLogEventWrapper.cpp index a1a6d9fe0e22..04c4629b5432 100644 --- a/libs/services/src/os/StatsLogEventWrapper.cpp +++ b/libs/services/src/os/StatsLogEventWrapper.cpp @@ -85,9 +85,6 @@ status_t StatsLogEventWrapper::readFromParcel(const Parcel* in) { case StatsLogValue::FLOAT: mElements.push_back(StatsLogValue(in->readFloat())); break; - case StatsLogValue::DOUBLE: - mElements.push_back(StatsLogValue(in->readDouble())); - break; case StatsLogValue::STORAGE: mElements.push_back(StatsLogValue()); mElements.back().setType(StatsLogValue::STORAGE); diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java index 1cc650bf2702..823af656abaa 100644 --- a/media/java/android/media/AudioPresentation.java +++ b/media/java/android/media/AudioPresentation.java @@ -18,7 +18,6 @@ package android.media; import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.TestApi; import android.icu.util.ULocale; import java.lang.annotation.Retention; @@ -172,6 +171,10 @@ public final class AudioPresentation { return localeLabels; } + private Map<ULocale, String> getULabels() { + return mLabels; + } + /** * @return the locale corresponding to audio presentation's ISO 639-1/639-2 language code. */ @@ -231,17 +234,24 @@ public final class AudioPresentation { AudioPresentation obj = (AudioPresentation) o; return mPresentationId == obj.getPresentationId() && mProgramId == obj.getProgramId() - && mLanguage == obj.getULocale() + && mLanguage.equals(obj.getULocale()) && mMasteringIndication == obj.getMasteringIndication() && mAudioDescriptionAvailable == obj.hasAudioDescription() && mSpokenSubtitlesAvailable == obj.hasSpokenSubtitles() && mDialogueEnhancementAvailable == obj.hasDialogueEnhancement() - && mLabels.equals(obj.getLabels()); + && mLabels.equals(obj.getULabels()); } @Override public int hashCode() { - return Objects.hashCode(mPresentationId); + return Objects.hash(mPresentationId, + mProgramId, + mLanguage.hashCode(), + mMasteringIndication, + mAudioDescriptionAvailable, + mSpokenSubtitlesAvailable, + mDialogueEnhancementAvailable, + mLabels.hashCode()); } /** diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java index 24b7f36e228b..cdbc7b44f905 100644 --- a/media/java/android/media/MediaDrm.java +++ b/media/java/android/media/MediaDrm.java @@ -418,9 +418,6 @@ public final class MediaDrm implements AutoCloseable { /** * Returns the status code for the key - * @return one of {@link #STATUS_USABLE}, {@link #STATUS_EXPIRED}, - * {@link #STATUS_OUTPUT_NOT_ALLOWED}, {@link #STATUS_PENDING} - * or {@link #STATUS_INTERNAL_ERROR}. */ @KeyStatusCode public int getStatusCode() { return mStatusCode; } @@ -654,13 +651,7 @@ public final class MediaDrm implements AutoCloseable { * can be queried using {@link #getSecurityLevel}. A session * ID is returned. * - * @param level the new security level, one of - * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}, - * {@link #SECURITY_LEVEL_SW_SECURE_DECODE}, - * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO}, - * {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or - * {@link #SECURITY_LEVEL_HW_SECURE_ALL}. - * + * @param level the new security level * @throws NotProvisionedException if provisioning is needed * @throws ResourceBusyException if required resources are in use * @throws IllegalArgumentException if the requested security level is @@ -790,9 +781,6 @@ public final class MediaDrm implements AutoCloseable { /** * Get the type of the request - * @return one of {@link #REQUEST_TYPE_INITIAL}, - * {@link #REQUEST_TYPE_RENEWAL}, {@link #REQUEST_TYPE_RELEASE}, - * {@link #REQUEST_TYPE_NONE} or {@link #REQUEST_TYPE_UPDATE} */ @RequestType public int getRequestType() { return mRequestType; } @@ -1051,8 +1039,7 @@ public final class MediaDrm implements AutoCloseable { * an inactive offline license are not usable for decryption. * * @param keySetId selects the offline license - * @return the offline license state, one of {@link #OFFLINE_LICENSE_USABLE}, - * {@link #OFFLINE_LICENSE_INACTIVE} or {@link #OFFLINE_LICENSE_STATE_UNKNOWN}. + * @return the offline license state * @throws IllegalArgumentException if the keySetId does not refer to an * offline license. */ @@ -1191,9 +1178,7 @@ public final class MediaDrm implements AutoCloseable { * enforcing compliance with HDCP requirements. Trusted enforcement of * HDCP policies must be handled by the DRM system. * <p> - * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE}, - * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2} - * or {@link #HDCP_NO_DIGITAL_OUTPUT}. + * @return the connected HDCP level */ @HdcpLevel public native int getConnectedHdcpLevel(); @@ -1204,9 +1189,7 @@ public final class MediaDrm implements AutoCloseable { * that may be connected. If multiple HDCP-capable interfaces are present, * it indicates the highest of the maximum HDCP levels of all interfaces. * <p> - * @return one of {@link #HDCP_LEVEL_UNKNOWN}, {@link #HDCP_NONE}, - * {@link #HDCP_V1}, {@link #HDCP_V2}, {@link #HDCP_V2_1}, {@link #HDCP_V2_2} - * or {@link #HDCP_NO_DIGITAL_OUTPUT}. + * @return the maximum supported HDCP level */ @HdcpLevel public native int getMaxHdcpLevel(); @@ -1296,10 +1279,7 @@ public final class MediaDrm implements AutoCloseable { * time a session is opened using {@link #openSession}. * @param sessionId the session to query. * <p> - * @return one of {@link #SECURITY_LEVEL_UNKNOWN}, - * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_SW_SECURE_DECODE}, - * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or - * {@link #SECURITY_LEVEL_HW_SECURE_ALL}. + * @return the security level of the session */ @SecurityLevel public native int getSecurityLevel(@NonNull byte[] sessionId); diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index 4e901629b114..e8b2f6513984 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -856,11 +856,9 @@ public abstract class MediaPlayer2 implements AutoCloseable * Checks whether the MediaPlayer2 is looping or non-looping. * * @return true if the MediaPlayer2 is currently looping, false otherwise - * @hide */ - public boolean isLooping() { - return false; - } + // This is a synchronous call. + public abstract boolean isLooping(); /** * Sets the audio session ID. @@ -875,7 +873,8 @@ public abstract class MediaPlayer2 implements AutoCloseable * When created, a MediaPlayer2 instance automatically generates its own audio session ID. * However, it is possible to force this player to be part of an already existing audio session * by calling this method. - * This method must be called before one of the overloaded <code> setDataSource </code> methods. + * This method must be called when player is in {@link #PLAYER_STATE_IDLE} or + * {@link #PLAYER_STATE_PREPARED} state in order to have sessionId take effect. * @return a token which can be used to cancel the operation later with {@link #cancelCommand}. */ // This is an asynchronous call. @@ -885,8 +884,10 @@ public abstract class MediaPlayer2 implements AutoCloseable * Returns the audio session ID. * * @return the audio session ID. {@see #setAudioSessionId(int)} - * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was contructed. + * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was + * contructed. */ + // This is a synchronous call. public abstract int getAudioSessionId(); /** @@ -907,7 +908,6 @@ public abstract class MediaPlayer2 implements AutoCloseable // This is an asynchronous call. public abstract Object attachAuxEffect(int effectId); - /** * Sets the send level of the player to the attached auxiliary effect. * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0. @@ -972,36 +972,10 @@ public abstract class MediaPlayer2 implements AutoCloseable * @return List of track info. The total number of tracks is the array length. * Must be called again if an external timed text source has been added after * addTimedTextSource method is called. + * @throws IllegalStateException if it is called in an invalid state. */ public abstract List<TrackInfo> getTrackInfo(); - /* Do not change these values without updating their counterparts - * in include/media/stagefright/MediaDefs.h and media/libstagefright/MediaDefs.cpp! - */ - /** - * MIME type for SubRip (SRT) container. Used in addTimedTextSource APIs. - * @hide - */ - public static final String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; - - /** - * MIME type for WebVTT subtitle data. - * @hide - */ - public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; - - /** - * MIME type for CEA-608 closed caption data. - * @hide - */ - public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608"; - - /** - * MIME type for CEA-708 closed caption data. - * @hide - */ - public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708"; - /** * Returns the index of the audio, video, or subtitle track currently selected for playback, * The return value is an index into the array returned by {@link #getTrackInfo()}, and can @@ -1202,7 +1176,7 @@ public abstract class MediaPlayer2 implements AutoCloseable public abstract void unregisterEventCallback(EventCallback eventCallback); /* Do not change these values without updating their counterparts - * in include/media/mediaplayer2.h! + * in include/media/MediaPlayer2Types.h! */ /** Unspecified media player error. * @see EventCallback#onError diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index 9b97b1060c8a..babf24ee08c8 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -56,7 +56,6 @@ import java.net.URL; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -64,7 +63,6 @@ import java.util.List; import java.util.Map; import java.util.Queue; import java.util.UUID; -import java.util.WeakHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; @@ -1015,24 +1013,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native final void _seekTo(long msec, int mode); - /** - * Get current playback position as a {@link MediaTimestamp}. - * <p> - * The MediaTimestamp represents how the media time correlates to the system time in - * a linear fashion using an anchor and a clock rate. During regular playback, the media - * time moves fairly constantly (though the anchor frame may be rebased to a current - * system time, the linear correlation stays steady). Therefore, this method does not - * need to be called often. - * <p> - * To help users get current playback position, this method always anchors the timestamp - * to the current {@link System#nanoTime system time}, so - * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position. - * - * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp - * is available, e.g. because the media player has not been initialized. - * - * @see MediaTimestamp - */ @Override @Nullable public MediaTimestamp getTimestamp() @@ -1048,11 +1028,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } - /** - * Resets the MediaPlayer2 to its uninitialized state. After calling - * this method, you will have to initialize it again by setting the - * data source and calling prepare(). - */ @Override public void reset() { synchronized (mEventCbLock) { @@ -1085,41 +1060,14 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400; - /** - * Sets the audio attributes. - * @param value value of the parameter to be set. - * @return true if the parameter is set successfully, false otherwise - */ + + // return true if the parameter is set successfully, false otherwise private native boolean native_setAudioAttributes(AudioAttributes audioAttributes); private native AudioAttributes native_getAudioAttributes(); - - /** - * Checks whether the MediaPlayer2 is looping or non-looping. - * - * @return true if the MediaPlayer2 is currently looping, false otherwise - * @hide - */ @Override public native boolean isLooping(); - /** - * Sets the audio session ID. - * - * @param sessionId the audio session ID. - * The audio session ID is a system wide unique identifier for the audio stream played by - * this MediaPlayer2 instance. - * The primary use of the audio session ID is to associate audio effects to a particular - * instance of MediaPlayer2: if an audio session ID is provided when creating an audio effect, - * this effect will be applied only to the audio content of media players within the same - * audio session and not to the output mix. - * When created, a MediaPlayer2 instance automatically generates its own audio session ID. - * However, it is possible to force this player to be part of an already existing audio session - * by calling this method. - * This method must be called before one of the overloaded <code> setDataSource </code> methods. - * @throws IllegalStateException if it is called in an invalid state - * @throws IllegalArgumentException if the sessionId is invalid. - */ @Override public Object setAudioSessionId(int sessionId) { return addTask(new Task(CALL_COMPLETED_SET_AUDIO_SESSION_ID, false) { @@ -1132,29 +1080,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _setAudioSessionId(int sessionId); - /** - * Returns the audio session ID. - * - * @return the audio session ID. {@see #setAudioSessionId(int)} - * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was contructed. - */ @Override public native int getAudioSessionId(); - /** - * Attaches an auxiliary effect to the player. A typical auxiliary effect is a reverberation - * effect which can be applied on any sound source that directs a certain amount of its - * energy to this effect. This amount is defined by setAuxEffectSendLevel(). - * See {@link #setAuxEffectSendLevel(float)}. - * <p>After creating an auxiliary effect (e.g. - * {@link android.media.audiofx.EnvironmentalReverb}), retrieve its ID with - * {@link android.media.audiofx.AudioEffect#getId()} and use it when calling this method - * to attach the player to the effect. - * <p>To detach the effect from the player, call this method with a null effect id. - * <p>This method must be called after one of the overloaded <code> setDataSource </code> - * methods. - * @param effectId system wide unique id of the effect to attach - */ @Override public Object attachAuxEffect(int effectId) { return addTask(new Task(CALL_COMPLETED_ATTACH_AUX_EFFECT, false) { @@ -1167,18 +1095,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _attachAuxEffect(int effectId); - /** - * Sets the send level of the player to the attached auxiliary effect. - * See {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0. - * <p>By default the send level is 0, so even if an effect is attached to the player - * this method must be called for the effect to be applied. - * <p>Note that the passed level value is a raw scalar. UI controls should be scaled - * logarithmically: the gain applied by audio framework ranges from -72dB to 0dB, - * so an appropriate conversion from linear UI input x to level is: - * x == 0 -> level = 0 - * 0 < x <= R -> level = 10^(72*(x-R)/20/R) - * @param level send level scalar - */ @Override public Object setAuxEffectSendLevel(float level) { return addTask(new Task(CALL_COMPLETED_SET_AUX_EFFECT_SEND_LEVEL, false) { @@ -1208,31 +1124,17 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * @see android.media.MediaPlayer2#getTrackInfo */ public static final class TrackInfoImpl extends TrackInfo { - /** - * Gets the track type. - * @return TrackType which indicates if the track is video, audio, timed text. - */ @Override public int getTrackType() { return mTrackType; } - /** - * Gets the language code of the track. - * @return a language code in either way of ISO-639-1 or ISO-639-2. - * When the language is unknown or could not be determined, - * ISO-639-2 language code, "und", is returned. - */ @Override public String getLanguage() { String language = mFormat.getString(MediaFormat.KEY_LANGUAGE); return language == null ? "und" : language; } - /** - * Gets the {@link MediaFormat} of the track. If the format is - * unknown or could not be determined, null is returned. - */ @Override public MediaFormat getFormat() { if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT @@ -1294,14 +1196,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } }; - /** - * Returns a List of track information. - * - * @return List of track info. The total number of tracks is the array length. - * Must be called again if an external timed text source has been added after - * addTimedTextSource method is called. - * @throws IllegalStateException if it is called in an invalid state. - */ @Override public List<TrackInfo> getTrackInfo() { TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl(); @@ -1328,33 +1222,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return trackInfo; } - /* - * A helper function to check if the mime type is supported by media framework. - */ - private static boolean availableMimeTypeForExternalSource(String mimeType) { - if (MEDIA_MIMETYPE_TEXT_SUBRIP.equals(mimeType)) { - return true; - } - return false; - } - - /** - * Returns the index of the audio, video, or subtitle track currently selected for playback, - * The return value is an index into the array returned by {@link #getTrackInfo()}, and can - * be used in calls to {@link #selectTrack(int)} or {@link #deselectTrack(int)}. - * - * @param trackType should be one of {@link TrackInfo#MEDIA_TRACK_TYPE_VIDEO}, - * {@link TrackInfo#MEDIA_TRACK_TYPE_AUDIO}, or - * {@link TrackInfo#MEDIA_TRACK_TYPE_SUBTITLE} - * @return index of the audio, video, or subtitle track currently selected for playback; - * a negative integer is returned when there is no selected track for {@code trackType} or - * when {@code trackType} is not one of audio, video, or subtitle. - * @throws IllegalStateException if called after {@link #close()} - * - * @see #getTrackInfo() - * @see #selectTrack(int) - * @see #deselectTrack(int) - */ @Override public int getSelectedTrack(int trackType) { PlayerMessage request = PlayerMessage.newBuilder() @@ -1368,34 +1235,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return response.getValues(0).getInt32Value(); } - /** - * Selects a track. - * <p> - * If a MediaPlayer2 is in invalid state, it throws an IllegalStateException exception. - * If a MediaPlayer2 is in <em>Started</em> state, the selected track is presented immediately. - * If a MediaPlayer2 is not in Started state, it just marks the track to be played. - * </p> - * <p> - * In any valid state, if it is called multiple times on the same type of track (ie. Video, - * Audio, Timed Text), the most recent one will be chosen. - * </p> - * <p> - * The first audio and video tracks are selected by default if available, even though - * this method is not called. However, no timed text track will be selected until - * this function is called. - * </p> - * <p> - * Currently, only timed text tracks or audio tracks can be selected via this method. - * In addition, the support for selecting an audio track at runtime is pretty limited - * in that an audio track can only be selected in the <em>Prepared</em> state. - * </p> - * @param index the index of the track to be selected. The valid range of the index - * is 0..total number of track - 1. The total number of tracks as well as the type of - * each individual track can be found by calling {@link #getTrackInfo()} method. - * @throws IllegalStateException if called in an invalid state. - * - * @see android.media.MediaPlayer2#getTrackInfo - */ @Override public Object selectTrack(int index) { return addTask(new Task(CALL_COMPLETED_SELECT_TRACK, false) { @@ -1406,20 +1245,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { }); } - /** - * Deselect a track. - * <p> - * Currently, the track must be a timed text track and no audio or video tracks can be - * deselected. If the timed text track identified by index has not been - * selected before, it throws an exception. - * </p> - * @param index the index of the track to be deselected. The valid range of the index - * is 0..total number of tracks - 1. The total number of tracks as well as the type of - * each individual track can be found by calling {@link #getTrackInfo()} method. - * @throws IllegalStateException if called in an invalid state. - * - * @see android.media.MediaPlayer2#getTrackInfo - */ @Override public Object deselectTrack(int index) { return addTask(new Task(CALL_COMPLETED_DESELECT_TRACK, false) { diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index 0769e5c84674..c49e720fa6ad 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -1050,9 +1050,9 @@ android_media_MediaPlayer2_native_finalize(JNIEnv *env, jobject thiz) android_media_MediaPlayer2_release(env, thiz); } -static void android_media_MediaPlayer2_set_audio_session_id(JNIEnv *env, jobject thiz, +static void android_media_MediaPlayer2_setAudioSessionId(JNIEnv *env, jobject thiz, jint sessionId) { - ALOGV("set_session_id(): %d", sessionId); + ALOGV("setAudioSessionId(): %d", sessionId); sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); @@ -1062,8 +1062,8 @@ static void android_media_MediaPlayer2_set_audio_session_id(JNIEnv *env, jobjec NULL); } -static jint android_media_MediaPlayer2_get_audio_session_id(JNIEnv *env, jobject thiz) { - ALOGV("get_session_id()"); +static jint android_media_MediaPlayer2_getAudioSessionId(JNIEnv *env, jobject thiz) { + ALOGV("getAudioSessionId()"); sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); if (mp == NULL ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); @@ -1419,8 +1419,8 @@ static const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_MediaPlayer2_native_init}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer2_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer2_native_finalize}, - {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer2_get_audio_session_id}, - {"_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_set_audio_session_id}, + {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer2_getAudioSessionId}, + {"_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer2_setAudioSessionId}, {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer2_setAuxEffectSendLevel}, {"_attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer2_attachAuxEffect}, // Modular DRM diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index 942614815c3d..942eafdbc48d 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -37,6 +37,7 @@ cc_library_shared { ldflags: ["-Wl,--hash-style=both"], }, }, + version_script: "libjnigraphics.map.txt", } // The headers module is in frameworks/native/Android.bp. diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml index 9ecaa03d6e53..5ab66324930d 100644 --- a/packages/CaptivePortalLogin/AndroidManifest.xml +++ b/packages/CaptivePortalLogin/AndroidManifest.xml @@ -26,7 +26,8 @@ <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <application android:label="@string/app_name" - android:usesCleartextTraffic="true"> + android:usesCleartextTraffic="true" + android:supportsRtl="true" > <activity android:name="com.android.captiveportallogin.CaptivePortalLoginActivity" android:label="@string/action_bar_label" diff --git a/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml b/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml new file mode 100644 index 000000000000..d460041e59ae --- /dev/null +++ b/packages/CaptivePortalLogin/res/layout/ssl_error_msg.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/ssl_error_msg" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:layout_marginStart="20dip" + android:layout_marginEnd="20dip" + android:gravity="center_vertical" + android:layout_marginBottom="4dip" + android:layout_marginTop="4dip" /> + diff --git a/packages/CaptivePortalLogin/res/layout/ssl_warning.xml b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml new file mode 100644 index 000000000000..ffd57a430662 --- /dev/null +++ b/packages/CaptivePortalLogin/res/layout/ssl_warning.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + + <!-- ssl error type --> + <TextView + android:id="@+id/ssl_error_type" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:text="SSL_UNKNOWN" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" + android:layout_marginBottom="0dip" + android:layout_marginTop="24dip" /> + + <!-- Page info: --> + <TextView + android:id="@+id/page_info" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/page_info" + android:textStyle="bold" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" /> + + <!-- Title: --> + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textStyle="bold" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" /> + + <!-- Address: --> + <TextView + android:id="@+id/address_header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/page_info_address" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" /> + + <TextView + android:id="@+id/address" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dip" + android:layout_marginEnd="24dip" /> + + <ScrollView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="4dip" + android:paddingEnd="4dip" > + + <!-- certificate view: --> + <LinearLayout + android:id="@+id/certificate_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="16dip" > + </LinearLayout> + + </ScrollView> + +</LinearLayout> diff --git a/packages/CaptivePortalLogin/res/values-af/strings.xml b/packages/CaptivePortalLogin/res/values-af/strings.xml index fa6f3fae2e33..cf4dc824f597 100644 --- a/packages/CaptivePortalLogin/res/values-af/strings.xml +++ b/packages/CaptivePortalLogin/res/values-af/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Die netwerk waarby jy probeer aansluit, het sekuriteitkwessies."</string> <string name="ssl_error_example" msgid="647898534624078900">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Gaan in elk geval deur blaaier voort"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Bladsy-inligting"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sekuriteitswaarskuwing"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Bekyk sertifikaat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Hierdie sertifikaat is nie van \'n betroubare owerheid nie."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Die naam van die werf kom nie ooreen met die naam op die sertifikaat nie."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Hierdie sertifikaat het verval."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Hierdie sertifikaat is nog nie geldig nie."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Hierdie sertifikaat het \'n ongeldige datum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Hierdie sertifikaat is ongeldig."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Onbekende sertifikaatfout."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-am/strings.xml b/packages/CaptivePortalLogin/res/values-am/strings.xml index 36d5e19d8a84..cdcb5a54daed 100644 --- a/packages/CaptivePortalLogin/res/values-am/strings.xml +++ b/packages/CaptivePortalLogin/res/values-am/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"ለመቀላቀል እየሞከሩ ያሉት አውታረ መረብ የደህንነት ችግሮች አሉበት።"</string> <string name="ssl_error_example" msgid="647898534624078900">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string> + <string name="ok" msgid="1509280796718850364">"እሺ"</string> + <string name="page_info" msgid="4048529256302257195">"የገፅ መረጃ"</string> + <string name="page_info_address" msgid="2222306609532903254">"አድራሻ:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"የደህንነት ቅንብሮች"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"ምስክሮች ይመልከቱ"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"ይህ ምስክር ከታማኝ ቦታ አይደለም።"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"የጣቢያው ስም ከምስክር ወረቀቱ ስም ጋር አይዛመድም።"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"ይህ ምስክር ጊዜው አልፏል"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"ይህ ምስክር ገና ትክክል አይደለም።"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"ይህ ምስክር ትክክለኛ ቀን አለው።"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"ይህ ምስክር ትክክል ያልሆነ ነው።"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"ያልታወቀ የምስክር ስህተት።"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ar/strings.xml b/packages/CaptivePortalLogin/res/values-ar/strings.xml index 8eb259b57b77..7773eeb22e04 100644 --- a/packages/CaptivePortalLogin/res/values-ar/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ar/strings.xml @@ -11,4 +11,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"الشبكة التي تحاول الانضمام إليها بها مشاكل أمنية."</string> <string name="ssl_error_example" msgid="647898534624078900">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المنظمة المعروضة."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"المتابعة على أي حال عبر المتصفح"</string> + <string name="ok" msgid="1509280796718850364">"موافق"</string> + <string name="page_info" msgid="4048529256302257195">"معلومات الصفحة"</string> + <string name="page_info_address" msgid="2222306609532903254">"العنوان:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"تحذير أمان"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"عرض الشهادة"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"هذه الشهادة ليست من جهة موثوق بها."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"لا يتطابق اسم الموقع مع الاسم على الشهادة."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"انتهت صلاحية هذه الشهادة."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"هذه الشهادة ليست صالحة بعد."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"تشتمل هذه الشهادة على تاريخ غير صالح."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"هذه الشهادة غير صالحة."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"حدث خطأ غير معروف بالشهادة."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-bg/strings.xml b/packages/CaptivePortalLogin/res/values-bg/strings.xml index 8ce9deb1eb78..4dd8aa0c536c 100644 --- a/packages/CaptivePortalLogin/res/values-bg/strings.xml +++ b/packages/CaptivePortalLogin/res/values-bg/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Мрежата, към която опитвате да се присъедините, има проблеми със сигурността."</string> <string name="ssl_error_example" msgid="647898534624078900">"Например страницата за вход може да не принадлежи на показаната организация."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Продължаване през браузър въпреки това"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Данни за страницата"</string> + <string name="page_info_address" msgid="2222306609532903254">"Адрес:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Предупреждение относно защитата"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Преглед на сертификата"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Сертификатът не е от надежден орган."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Името на сайта не съответства на името в сертификата."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Сертификатът е изтекъл."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Сертификатът още не е валиден."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Този сертификат е с невалидна дата."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Този сертификат е невалиден."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Неизвестна грешка в сертификата."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-bn/strings.xml b/packages/CaptivePortalLogin/res/values-bn/strings.xml index b75d76e69f7c..fb703cfaadc9 100644 --- a/packages/CaptivePortalLogin/res/values-bn/strings.xml +++ b/packages/CaptivePortalLogin/res/values-bn/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন তাতে নিরাপত্তার সমস্যা আছে।"</string> <string name="ssl_error_example" msgid="647898534624078900">"উদাহরণস্বরূপ, লগ-ইন পৃষ্ঠাটি প্রদর্শিত প্রতিষ্ঠানের অন্তর্গত নাও হতে পারে৷"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"যাই হোক না কেন ব্রাউজারের মাধ্যমে অবিরত রাখুন"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Sideinfo"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhetsadvarsel"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis sertifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikatet er ikke fra en pålitelig myndighet."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på nettstedet samsvarer ikke med navnet på sertifikatet."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikatet er utløpt."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikatet er ikke gyldig ennå."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette sertifikatet har en ugyldig dato."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette sertifikatet er ugyldig."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukjent sertifikatfeil."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ca/strings.xml b/packages/CaptivePortalLogin/res/values-ca/strings.xml index fe189edaf311..a2c9ed809ba3 100644 --- a/packages/CaptivePortalLogin/res/values-ca/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ca/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"La xarxa a què et vols connectar té problemes de seguretat."</string> <string name="ssl_error_example" msgid="647898534624078900">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continua igualment mitjançant el navegador"</string> + <string name="ok" msgid="1509280796718850364">"D\'acord"</string> + <string name="page_info" msgid="4048529256302257195">"Informació de la pàgina"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adreça:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertiment de seguretat"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualitza el certificat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Aquest certificat no és d\'una autoritat de confiança."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nom del lloc no coincideix amb el del certificat."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Aquest certificat ha caducat."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Aquest certificat encara no és vàlid."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Aquest certificat té una data no vàlida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Aquest certificat no és vàlid."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificat desconegut."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-cs/strings.xml b/packages/CaptivePortalLogin/res/values-cs/strings.xml index 09dcc5f5989f..be649a50f26c 100644 --- a/packages/CaptivePortalLogin/res/values-cs/strings.xml +++ b/packages/CaptivePortalLogin/res/values-cs/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Síť, ke které se pokoušíte připojit, má bezpečnostní problémy."</string> <string name="ssl_error_example" msgid="647898534624078900">"Například přihlašovací stránka nemusí patřit do zobrazované organizace."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Přesto pokračovat prostřednictvím prohlížeče"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informace o stránce"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozornění zabezpečení"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zobrazit certifikát"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Tento certifikát nepochází od důvěryhodné autority."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Název webu se neshoduje s názvem uvedeným v certifikátu."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Platnost certifikátu vypršela."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Tento certifikát ještě není platný."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Datum tohoto certifikátu není platné."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Tento certifikát je neplatný."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznámá chyba certifikátu."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-da/strings.xml b/packages/CaptivePortalLogin/res/values-da/strings.xml index dc0dd17c0bf4..8183105a1aff 100644 --- a/packages/CaptivePortalLogin/res/values-da/strings.xml +++ b/packages/CaptivePortalLogin/res/values-da/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Der er sikkerhedsproblemer på det netværk, du forsøger at logge ind på."</string> <string name="ssl_error_example" msgid="647898534624078900">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsæt alligevel via browseren"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Sideoplysninger"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhedsadvarsel"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis certifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dette certifikat stammer ikke fra en troværdig autoritet."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på websitet stemmer ikke overens med navnet på certifikatet."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Dette certifikat er udløbet."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dette certifikat er endnu ikke gyldigt."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette certifikat har en ugyldig dato."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette certifikat er ugyldigt."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukendt fejl i certifikatet."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-de/strings.xml b/packages/CaptivePortalLogin/res/values-de/strings.xml index d8f7be991846..a9b7415d8427 100644 --- a/packages/CaptivePortalLogin/res/values-de/strings.xml +++ b/packages/CaptivePortalLogin/res/values-de/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string> <string name="ssl_error_example" msgid="647898534624078900">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Trotzdem in einem Browser fortfahren"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Seiteninfo"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sicherheitswarnung"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zertifikat ansehen"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dieses Zertifikat wurde nicht von einer vertrauenswürdigen Stelle ausgegeben."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Name der Website stimmt nicht mit dem Namen auf dem Zertifikat überein."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Dieses Zertifikat ist abgelaufen."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dieses Zertifikat ist noch nicht gültig."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dieses Zertifikat weist ein ungültiges Datum auf."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Dieses Zertifikat ist ungültig."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Unbekannter Zertifikatfehler"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-el/strings.xml b/packages/CaptivePortalLogin/res/values-el/strings.xml index cb6171093f12..16bf6e22761d 100644 --- a/packages/CaptivePortalLogin/res/values-el/strings.xml +++ b/packages/CaptivePortalLogin/res/values-el/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Παρουσιάζονται προβλήματα ασφάλειας στο δίκτυο στο οποίο προσπαθείτε να συνδεθείτε."</string> <string name="ssl_error_example" msgid="647898534624078900">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Πληροφορίες σελίδας"</string> + <string name="page_info_address" msgid="2222306609532903254">"Διεύθυνση:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Προειδοποίηση ασφαλείας"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Προβολή πιστοποιητικού"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Αυτό το πιστοποιητικό δεν προέρχεται από αξιόπιστη αρχή."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Το όνομα του ιστότοπου δεν αντιστοιχεί με το όνομα στο πιστοποιητικό."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Αυτό το πιστοποιητικό έχει λήξει."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Αυτό το πιστοποιητικό δεν είναι έγκυρο ακόμα."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Αυτό το πιστοποιητικό δεν έχει έγκυρη ημερομηνία."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Αυτό το πιστοποιητικό δεν είναι έγκυρο."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Άγνωστο σφάλμα πιστοποιητικού."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml b/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml index 2e8d1f082d1f..f940299af6a8 100644 --- a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml +++ b/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string> <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Page info"</string> + <string name="page_info_address" msgid="2222306609532903254">"Address:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Security warning"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"View certificate"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"This certificate isn\'t from a trusted authority."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"The name of the site doesn\'t match the name on the certificate."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"This certificate has expired."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"This certificate isn\'t valid yet."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"This certificate has an invalid date."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"This certificate is invalid."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Unknown certificate error."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml b/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml index 2e8d1f082d1f..f940299af6a8 100644 --- a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml +++ b/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"The network that you’re trying to join has security issues."</string> <string name="ssl_error_example" msgid="647898534624078900">"For example, the login page might not belong to the organisation shown."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continue anyway via browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Page info"</string> + <string name="page_info_address" msgid="2222306609532903254">"Address:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Security warning"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"View certificate"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"This certificate isn\'t from a trusted authority."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"The name of the site doesn\'t match the name on the certificate."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"This certificate has expired."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"This certificate isn\'t valid yet."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"This certificate has an invalid date."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"This certificate is invalid."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Unknown certificate error."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml b/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml index 5d7ba9163895..c01166474074 100644 --- a/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml +++ b/packages/CaptivePortalLogin/res/values-es-rUS/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"La red a la que intentas conectarte tiene problemas de seguridad."</string> <string name="ssl_error_example" msgid="647898534624078900">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar de todos modos desde el navegador"</string> + <string name="ok" msgid="1509280796718850364">"Aceptar"</string> + <string name="page_info" msgid="4048529256302257195">"Información de la página"</string> + <string name="page_info_address" msgid="2222306609532903254">"Dirección:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertencia de seguridad"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado no proviene de una autoridad confiable."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nombre del sitio no coincide con el nombre del certificado."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado ha expirado."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado aún no es válido."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La fecha de este certificado no es válida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado no es válido."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificado desconocido"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-es/strings.xml b/packages/CaptivePortalLogin/res/values-es/strings.xml index da2eae9038bf..65244e7e9156 100644 --- a/packages/CaptivePortalLogin/res/values-es/strings.xml +++ b/packages/CaptivePortalLogin/res/values-es/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"La red a la que intentas unirte tiene problemas de seguridad."</string> <string name="ssl_error_example" msgid="647898534624078900">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar de todos modos a través del navegador"</string> + <string name="ok" msgid="1509280796718850364">"Aceptar"</string> + <string name="page_info" msgid="4048529256302257195">"Información de la página"</string> + <string name="page_info_address" msgid="2222306609532903254">"Dirección:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Advertencia de seguridad"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado no procede de una entidad de certificación de confianza."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"El nombre del sitio no coincide con el del certificado."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado ha caducado."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado aún no es válido."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La fecha de este certificado no es válida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado no es válido."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Error de certificado desconocido"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-et/strings.xml b/packages/CaptivePortalLogin/res/values-et/strings.xml index 41fcb9a6bd6a..e4c4c9801d5c 100644 --- a/packages/CaptivePortalLogin/res/values-et/strings.xml +++ b/packages/CaptivePortalLogin/res/values-et/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Võrgul, millega üritate ühenduse luua, on turvaprobleeme."</string> <string name="ssl_error_example" msgid="647898534624078900">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Jätka siiski brauseris"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Lehe teave"</string> + <string name="page_info_address" msgid="2222306609532903254">"Aadress:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Turvahoiatus"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Kuva sertifikaat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"See sertifikaat ei pärine usaldusväärselt asutuselt."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Saidi nimi ei vasta sertifikaadil olevale nimele."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"See sertifikaat on aegunud."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"See sertifikaat pole veel kehtiv."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Sellel sertifikaadil on kehtetu kuupäev."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"See sertifikaat on kehtetu."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Tundmatu sertifikaadiviga."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-fa/strings.xml b/packages/CaptivePortalLogin/res/values-fa/strings.xml index 2e4cc5134e1b..27b9b7f15fab 100644 --- a/packages/CaptivePortalLogin/res/values-fa/strings.xml +++ b/packages/CaptivePortalLogin/res/values-fa/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"شبکهای که میخواهید به آن بپیوندید مشکلات امنیتی دارد."</string> <string name="ssl_error_example" msgid="647898534624078900">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"در هر صورت از طریق مرورگر ادامه یابد"</string> + <string name="ok" msgid="1509280796718850364">"تأیید"</string> + <string name="page_info" msgid="4048529256302257195">"اطلاعات صفحه"</string> + <string name="page_info_address" msgid="2222306609532903254">"آدرس:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"اخطار امنیتی"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"مشاهده گواهی"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"این گواهی از یک منبع مورد اطمینان صادر نشده است."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"نام سایت با نام موجود در گواهی مطابقت ندارد."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"این گواهی منقضی شده است."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"این گواهی هنوز معتبر نیست."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"تاریخ این گواهی نامعتبر است."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"این گواهی نامعتبر است."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"خطای ناشناخته در گواهی."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-fi/strings.xml b/packages/CaptivePortalLogin/res/values-fi/strings.xml index 1976f7d1c1e6..8086fbf96088 100644 --- a/packages/CaptivePortalLogin/res/values-fi/strings.xml +++ b/packages/CaptivePortalLogin/res/values-fi/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Verkossa, johon yrität muodostaa yhteyttä, on turvallisuusongelmia."</string> <string name="ssl_error_example" msgid="647898534624078900">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Jatka silti selaimen kautta."</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Sivun tiedot"</string> + <string name="page_info_address" msgid="2222306609532903254">"Osoite:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Suojausvaroitus"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Näytä varmenne"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Varmenteen myöntäjä ei ole luotettava taho."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Sivuston nimi ei vastaa varmenteessa olevaa nimeä."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Varmenne ei ole enää voimassa."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Varmenne ei ole vielä voimassa."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Varmenteen päiväys ei kelpaa."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Varmenne on virheellinen."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Tuntematon varmennevirhe."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-fr/strings.xml b/packages/CaptivePortalLogin/res/values-fr/strings.xml index 8f98bb5131ca..39fc5692bc21 100644 --- a/packages/CaptivePortalLogin/res/values-fr/strings.xml +++ b/packages/CaptivePortalLogin/res/values-fr/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Le réseau que vous essayez de rejoindre présente des problèmes de sécurité."</string> <string name="ssl_error_example" msgid="647898534624078900">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuer quand même dans le navigateur"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Infos sur la page"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresse :"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avertissement de sécurité"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Afficher le certificat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ce certificat provient d\'une autorité non approuvée."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Le nom du site ne correspond pas au nom indiqué dans le certificat."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Le certificat a expiré."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Ce certificat n\'est pas encore valide."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"La date de ce certificat n\'est pas valide."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Ce certificat n\'est pas valide."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Erreur : Certificat inconnu."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-hi/strings.xml b/packages/CaptivePortalLogin/res/values-hi/strings.xml index 1bacc4680f1c..d924fffb8c1a 100644 --- a/packages/CaptivePortalLogin/res/values-hi/strings.xml +++ b/packages/CaptivePortalLogin/res/values-hi/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"आप जिस नेटवर्क में शामिल होने का प्रयास कर रहे हैं उसमें सुरक्षा समस्याएं हैं."</string> <string name="ssl_error_example" msgid="647898534624078900">"उदाहरण के लिए, हो सकता है कि लॉगिन पृष्ठ दिखाए गए संगठन से संबद्ध ना हो."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"ब्राउज़र के द्वारा फिर जारी रखें"</string> + <string name="ok" msgid="1509280796718850364">"ठीक"</string> + <string name="page_info" msgid="4048529256302257195">"पृष्ठ जानकारी"</string> + <string name="page_info_address" msgid="2222306609532903254">"पता:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"सुरक्षा चेतावनी"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"प्रमाणपत्र देखें"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"यह प्रमाणपत्र किसी विश्वस्त प्राधिकारी का नहीं है."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"साइट का नाम, प्रमाणपत्र के नाम से मिलान नहीं करता."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"इस प्रमाणपत्र की समय सीमा समाप्त हो गई है."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"यह प्रमाणपत्र अभी तक मान्य नहीं है."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"इस प्रमाणपत्र में एक अमान्य दिनांक है."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"यह प्रमाणपत्र अमान्य है."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"अज्ञात प्रमाणपत्र त्रुटि."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-hr/strings.xml b/packages/CaptivePortalLogin/res/values-hr/strings.xml index e44cd3b22cf2..11b1dd3f50e9 100644 --- a/packages/CaptivePortalLogin/res/values-hr/strings.xml +++ b/packages/CaptivePortalLogin/res/values-hr/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj se pokušavate pridružiti ima sigurnosne poteškoće."</string> <string name="ssl_error_example" msgid="647898534624078900">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi putem preglednika"</string> + <string name="ok" msgid="1509280796718850364">"U redu"</string> + <string name="page_info" msgid="4048529256302257195">"Informacije o stranici"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozorenje o sigurnosti"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Prikaži certifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ovaj certifikat ne potječe iz pouzdanog izvora."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Naziv web-lokacije ne podudara se s nazivom na certifikatu."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Ovaj je certifikat istekao."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Ovaj certifikat još nije važeći."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Ovaj certifikat ima nevažeći datum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Ovaj certifikat nije valjan."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Nepoznata pogreška certifikata."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-hu/strings.xml b/packages/CaptivePortalLogin/res/values-hu/strings.xml index f15fb49634e1..145e2abd0906 100644 --- a/packages/CaptivePortalLogin/res/values-hu/strings.xml +++ b/packages/CaptivePortalLogin/res/values-hu/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string> <string name="ssl_error_example" msgid="647898534624078900">"Például lehet, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Folytatás ennek ellenére böngészőn keresztül"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Oldaladatok"</string> + <string name="page_info_address" msgid="2222306609532903254">"Cím:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Biztonsági figyelmeztetés"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tanúsítvány megtekintése"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ez a tanúsítvány nem hiteles tanúsítványkibocsátótól származik."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"A webhely neve nem egyezik a tanúsítványon lévő névvel."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"A tanúsítvány lejárt."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"A tanúsítvány még nem érvényes."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"A tanúsítvány dátuma érvénytelen."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Ez a tanúsítvány érvénytelen."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Ismeretlen tanúsítványhiba."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-in/strings.xml b/packages/CaptivePortalLogin/res/values-in/strings.xml index 10e3de6b9f24..4a335dd38979 100644 --- a/packages/CaptivePortalLogin/res/values-in/strings.xml +++ b/packages/CaptivePortalLogin/res/values-in/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Jaringan yang ingin Anda masuki mengalami masalah keamanan."</string> <string name="ssl_error_example" msgid="647898534624078900">"Misalnya, halaman masuk mungkin bukan milik organisasi yang ditampilkan."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Tetap lanjutkan melalui browser"</string> + <string name="ok" msgid="1509280796718850364">"Oke"</string> + <string name="page_info" msgid="4048529256302257195">"Info laman"</string> + <string name="page_info_address" msgid="2222306609532903254">"Alamat:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Peringatan sertifikat"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Lihat sertifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikat ini tidak berasal dari otoritas tepercaya."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nama situs tidak cocok dengan nama pada sertifikat."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikat ini telah kedaluwarsa."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikat ini belum valid."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Tanggal sertifikat ini tidak valid."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Sertifikat ini tidak valid."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Kesalahan sertifikat tak dikenal."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-it/strings.xml b/packages/CaptivePortalLogin/res/values-it/strings.xml index a01a55339da4..2cc4038fbe63 100644 --- a/packages/CaptivePortalLogin/res/values-it/strings.xml +++ b/packages/CaptivePortalLogin/res/values-it/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"La rete a cui stai tentando di accedere presenta problemi di sicurezza."</string> <string name="ssl_error_example" msgid="647898534624078900">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continua comunque dal browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Info pagina"</string> + <string name="page_info_address" msgid="2222306609532903254">"Indirizzo:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avviso di sicurezza"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualizza certificato"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Questo certificato non proviene da un\'autorità attendibile."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Il nome del sito non corrisponde al nome nel certificato."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Il certificato è scaduto."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Questo certificato non è ancora valido."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Questo certificato presenta una data non valida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Questo certificato non è valido."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Errore certificato sconosciuto."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-iw/strings.xml b/packages/CaptivePortalLogin/res/values-iw/strings.xml index 8e7915d83cc6..527e69247104 100644 --- a/packages/CaptivePortalLogin/res/values-iw/strings.xml +++ b/packages/CaptivePortalLogin/res/values-iw/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"יש בעיות אבטחה ברשת שאליה אתה מנסה להתחבר."</string> <string name="ssl_error_example" msgid="647898534624078900">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"המשך בכל זאת באמצעות דפדפן"</string> + <string name="ok" msgid="1509280796718850364">"אישור"</string> + <string name="page_info" msgid="4048529256302257195">"פרטי דף"</string> + <string name="page_info_address" msgid="2222306609532903254">"כתובת:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"אזהרת אבטחה"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"הצג אישור"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"אישור זה אינו מגיע מרשות אמינה."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"שם האתר לא תואם לשם באישור."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"פג תוקפו של אישור זה."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"אישור זה אינו חוקי עדיין."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"לאישור זה יש תאריך בלתי חוקי."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"אישור זה אינו חוקי."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"שגיאת אישור לא ידועה."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ja/strings.xml b/packages/CaptivePortalLogin/res/values-ja/strings.xml index e275b95849c1..bcc8686f8c65 100644 --- a/packages/CaptivePortalLogin/res/values-ja/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ja/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"接続しようとしているネットワークにセキュリティの問題があります。"</string> <string name="ssl_error_example" msgid="647898534624078900">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"ブラウザから続行"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"ページ情報"</string> + <string name="page_info_address" msgid="2222306609532903254">"アドレス:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"セキュリティ警告"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"証明書を表示"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"この証明書は信頼できる認証機関のものではありません。"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"サイト名と証明書上の名前が一致しません。"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"この証明書は有効期限切れです。"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"この証明書はまだ有効ではありません。"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"この証明書の日付は無効です。"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"この証明書は無効です。"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"不明な証明書エラーです。"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ko/strings.xml b/packages/CaptivePortalLogin/res/values-ko/strings.xml index 75f2b48d98c2..7a7f7e075b30 100644 --- a/packages/CaptivePortalLogin/res/values-ko/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ko/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"가입하려는 네트워크에 보안 문제가 있습니다."</string> <string name="ssl_error_example" msgid="647898534624078900">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"브라우저를 통해 계속하기"</string> + <string name="ok" msgid="1509280796718850364">"확인"</string> + <string name="page_info" msgid="4048529256302257195">"페이지 정보"</string> + <string name="page_info_address" msgid="2222306609532903254">"주소:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"보안 경고"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"인증서 보기"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"신뢰할 수 있는 인증 기관에서 발급한 인증서가 아닙니다."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"사이트 이름이 인증서에 있는 것과 일치하지 않습니다."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"인증서가 만료되었습니다."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"인증서가 아직 유효하지 않습니다."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"인증서 날짜가 유효하지 않습니다."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"인증서가 잘못되었습니다."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"알 수 없는 인증서 오류입니다."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-lt/strings.xml b/packages/CaptivePortalLogin/res/values-lt/strings.xml index 17da83fd15ce..158f7cea00d8 100644 --- a/packages/CaptivePortalLogin/res/values-lt/strings.xml +++ b/packages/CaptivePortalLogin/res/values-lt/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Kilo tinklo, prie kurio bandote prisijungti, problemų."</string> <string name="ssl_error_example" msgid="647898534624078900">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Vis tiek tęsti naudojant naršyklę"</string> + <string name="ok" msgid="1509280796718850364">"Gerai"</string> + <string name="page_info" msgid="4048529256302257195">"Puslapio informacija"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresas:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Saugos įspėjimas"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Žiūrėti sertifikatą"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Šį sertifikatą išdavė nepatikima įstaiga."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Svetainės pavadinimas neatitinka sertifikate nurodyto pavadinimo."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Šio sertifikato galiojimo laikas baigėsi."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Šis sertifikatas dar negalioja."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Šio sertifikato data netinkama."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Šis sertifikatas netinkamas."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Nežinoma sertifikato klaida."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-lv/strings.xml b/packages/CaptivePortalLogin/res/values-lv/strings.xml index 95b855884c11..a42cb220a0d1 100644 --- a/packages/CaptivePortalLogin/res/values-lv/strings.xml +++ b/packages/CaptivePortalLogin/res/values-lv/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Tīklam, kuram mēģināt pievienoties, ir drošības problēmas."</string> <string name="ssl_error_example" msgid="647898534624078900">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Tik un tā turpināt, izmantojot pārlūkprogrammu"</string> + <string name="ok" msgid="1509280796718850364">"Labi"</string> + <string name="page_info" msgid="4048529256302257195">"Lapas informācija"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adrese:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Drošības brīdinājums"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Skatīt sertifikātu"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Šo sertifikātu nav izsniegusi uzticama iestāde."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Vietnes nosaukums neatbilst nosaukumam sertifikātā."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Šī sertifikāta derīguma termiņš ir beidzies."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Šis sertifikāts vēl nav derīgs."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Šī sertifikāta datums nav derīgs."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Šis sertifikāts nav derīgs."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Nezināma sertifikāta kļūda."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ms/strings.xml b/packages/CaptivePortalLogin/res/values-ms/strings.xml index 933721ace248..aaa51c8fbe3f 100644 --- a/packages/CaptivePortalLogin/res/values-ms/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ms/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Rangkaian yang anda cuba sertai mempunyai isu keselamatan."</string> <string name="ssl_error_example" msgid="647898534624078900">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Teruskan juga melalui penyemak imbas"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Maklumat halaman"</string> + <string name="page_info_address" msgid="2222306609532903254">"Alamat:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Amaran keselamatan"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Lihat sijil"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sijil ini bukan daripada pihak berkuasa yang dipercayai."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nama tapak tidak sepadan dengan nama pada sijil."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Sijil ini telah tamat tempoh."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sijil ini belum lagi sah."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Sijil ini mempunyai tarikh yang tidak sah."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Sijil ini tidak sah."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Ralat sijil tidak diketahui."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-nb/strings.xml b/packages/CaptivePortalLogin/res/values-nb/strings.xml index 0dd5b6ceefa5..29c23ed2ee61 100644 --- a/packages/CaptivePortalLogin/res/values-nb/strings.xml +++ b/packages/CaptivePortalLogin/res/values-nb/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Nettverket du prøver å logge på, har sikkerhetsproblemer."</string> <string name="ssl_error_example" msgid="647898534624078900">"Det er for eksempel mulig at påloggingssiden kanskje ikke tilhører organisasjonen som vises."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsett likevel via nettleseren"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Sideinfo"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Sikkerhetsadvarsel"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vis sertifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Sertifikatet er ikke fra en pålitelig myndighet."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Navnet på nettstedet samsvarer ikke med navnet på sertifikatet."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Sertifikatet er utløpt."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Sertifikatet er ikke gyldig ennå."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dette sertifikatet har en ugyldig dato."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Dette sertifikatet er ugyldig."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Ukjent sertifikatfeil."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-nl/strings.xml b/packages/CaptivePortalLogin/res/values-nl/strings.xml index 1c5960155f4d..2cbca06c13dd 100644 --- a/packages/CaptivePortalLogin/res/values-nl/strings.xml +++ b/packages/CaptivePortalLogin/res/values-nl/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Het netwerk waarmee u verbinding probeert te maken, heeft beveiligingsproblemen."</string> <string name="ssl_error_example" msgid="647898534624078900">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Toch doorgaan via browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Pagina-informatie"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Beveiligingsmelding"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Certificaat weergeven"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Dit is geen certificaat van een vertrouwde autoriteit."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"De naam van deze site komt niet overeen met de naam op het certificaat."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Dit certificaat is verlopen."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Dit certificaat is nog niet geldig."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Dit certificaat heeft een ongeldige datum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Dit certificaat is ongeldig."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Onbekende certificaatfout."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-pl/strings.xml b/packages/CaptivePortalLogin/res/values-pl/strings.xml index 17f20df33717..9ba066ebb12d 100644 --- a/packages/CaptivePortalLogin/res/values-pl/strings.xml +++ b/packages/CaptivePortalLogin/res/values-pl/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"W sieci, z którą próbujesz się połączyć, występują problemy z zabezpieczeniami."</string> <string name="ssl_error_example" msgid="647898534624078900">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Kontynuuj mimo to w przeglądarce"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informacje o stronie"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Ostrzeżenie zabezpieczeń"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Wyświetl certyfikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Certyfikat nie pochodzi od zaufanego urzędu."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Nazwa witryny nie pasuje do nazwy na certyfikacie."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Ten certyfikat wygasł."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Certyfikat nie jest jeszcze ważny."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Certyfikat ma nieprawidłową datę."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Certyfikat jest nieprawidłowy."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Nieznany błąd certyfikatu"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml b/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml index 94b9d60f69da..5bef235af136 100644 --- a/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml +++ b/packages/CaptivePortalLogin/res/values-pt-rPT/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"A rede à qual está a tentar aceder tem problemas de segurança."</string> <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar mesmo assim através do navegador"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informações da página"</string> + <string name="page_info_address" msgid="2222306609532903254">"Endereço:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Aviso de segurança"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Ver certificado"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado não pertence a uma autoridade fidedigna."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"O nome do Web site não corresponde ao nome constante no certificado."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado expirou."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado ainda não é válido."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Este certificado tem uma data inválida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado é inválido."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Erro: certificado desconhecido."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-pt/strings.xml b/packages/CaptivePortalLogin/res/values-pt/strings.xml index 3d1064cf98d9..ebe4148fcca9 100644 --- a/packages/CaptivePortalLogin/res/values-pt/strings.xml +++ b/packages/CaptivePortalLogin/res/values-pt/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"A rede à qual você está tentando se conectar tem problemas de segurança."</string> <string name="ssl_error_example" msgid="647898534624078900">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuar mesmo assim pelo navegador"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informações da página"</string> + <string name="page_info_address" msgid="2222306609532903254">"Endereço:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Aviso de segurança"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visualizar certificado"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Este certificado não é de uma autoridade confiável."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"O nome do site não corresponde ao nome no certificado."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Este certificado expirou."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Este certificado ainda não é válido."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Este certificado tem uma data inválida."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Este certificado é inválido."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Erro de certificado desconhecido."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ro/strings.xml b/packages/CaptivePortalLogin/res/values-ro/strings.xml index cf1b6b5cd478..e2e4eac97876 100644 --- a/packages/CaptivePortalLogin/res/values-ro/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ro/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Rețeaua la care încercați să vă conectați are probleme de securitate."</string> <string name="ssl_error_example" msgid="647898534624078900">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Continuați oricum prin browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informaţii pagină"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresă:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Avertisment de securitate"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Vizualizaţi certificatul"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Acest certificat nu provine de la o autoritate de încredere."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Numele acestui site nu se potriveşte cu numele de pe certificat."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Acest certificat a expirat."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Acest certificat nu este încă valid."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Acest certificat are o dată nevalidă."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Acest certificat este nevalid."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Eroare de certificat necunoscută."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-ru/strings.xml b/packages/CaptivePortalLogin/res/values-ru/strings.xml index 6966bcd69290..c0153e6d7611 100644 --- a/packages/CaptivePortalLogin/res/values-ru/strings.xml +++ b/packages/CaptivePortalLogin/res/values-ru/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Сеть, к которой вы хотите подключиться, небезопасна."</string> <string name="ssl_error_example" msgid="647898534624078900">"Например, страница входа в аккаунт может быть фиктивной."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Игнорировать и открыть браузер"</string> + <string name="ok" msgid="1509280796718850364">"ОК"</string> + <string name="page_info" msgid="4048529256302257195">"Информация о странице"</string> + <string name="page_info_address" msgid="2222306609532903254">"Адрес:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Угроза безопасности"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Просмотреть сертификат"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Этот сертификат получен из ненадежных источников."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Название сайта не соответствует названию в сертификате."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Срок действия сертификата истек."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Сертификат еще не действителен."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Дата этого сертификата недействительна."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Этот сертификат недействителен."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Неизвестная ошибка сертификата."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-sk/strings.xml b/packages/CaptivePortalLogin/res/values-sk/strings.xml index 54763be28912..8ba24b1c4ed9 100644 --- a/packages/CaptivePortalLogin/res/values-sk/strings.xml +++ b/packages/CaptivePortalLogin/res/values-sk/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Sieť, ku ktorej sa pokúšate pripojiť, má problémy so zabezpečením"</string> <string name="ssl_error_example" msgid="647898534624078900">"Napríklad prihlasovacia stránka nemusí patriť uvedenej organizácii."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Pokračovať pomocou prehliadača"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Informácie o stránke"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adresa:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Upozornenie zabezpečenia"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Zobraziť certifikát"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Tento certifikát nepochádza od dôveryhodnej autority."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Názov stránky sa nezhoduje s názvom uvedeným v certifikáte."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Platnosť certifikátu skončila."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Tento certifikát zatiaľ nie je platný."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Tento certifikát má neplatný dátum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Tento certifikát je neplatný."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznáma chyba certifikátu."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-sl/strings.xml b/packages/CaptivePortalLogin/res/values-sl/strings.xml index 7dd0b374f483..b7d9a8a81b8b 100644 --- a/packages/CaptivePortalLogin/res/values-sl/strings.xml +++ b/packages/CaptivePortalLogin/res/values-sl/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Omrežje, ki se mu poskušate pridružiti, ima varnostne težave."</string> <string name="ssl_error_example" msgid="647898534624078900">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Vseeno nadaljuj v brskalniku"</string> + <string name="ok" msgid="1509280796718850364">"V redu"</string> + <string name="page_info" msgid="4048529256302257195">"Podatki o strani"</string> + <string name="page_info_address" msgid="2222306609532903254">"Naslov:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Varnostno opozorilo"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Prikaži potrdilo"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Potrdila ni izdal zaupanja vreden overitelj."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Ime spletnega mesta se ne ujema z imenom na potrdilu."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Potrdilo je poteklo."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"To potrdilo še ni veljavno."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Potrdilo ima neveljaven datum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"To potrdilo ni veljavno."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Neznana napaka potrdila."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-sr/strings.xml b/packages/CaptivePortalLogin/res/values-sr/strings.xml index f6042897e493..967c8ba87ac1 100644 --- a/packages/CaptivePortalLogin/res/values-sr/strings.xml +++ b/packages/CaptivePortalLogin/res/values-sr/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Мрежа којој покушавате да се придружите има безбедносних проблема."</string> <string name="ssl_error_example" msgid="647898534624078900">"На пример, страница за пријављивање можда не припада приказаној организацији."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Ипак настави преко прегледача"</string> + <string name="ok" msgid="1509280796718850364">"Потврди"</string> + <string name="page_info" msgid="4048529256302257195">"Информације о страници"</string> + <string name="page_info_address" msgid="2222306609532903254">"Адреса:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Безбедносно упозорење"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Прикажи сертификат"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Овај сертификат не потиче од поузданог ауторитета."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Назив сајта се не подудара са називом на сертификату."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Овај сертификат је истекао."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Овај сертификат још увек није важећи."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Датум овог сертификата је неважећи."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Овај сертификат је неважећи."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Непозната грешка сертификата."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-sv/strings.xml b/packages/CaptivePortalLogin/res/values-sv/strings.xml index 8cf70413ef67..75356f01d81f 100644 --- a/packages/CaptivePortalLogin/res/values-sv/strings.xml +++ b/packages/CaptivePortalLogin/res/values-sv/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Nätverket du försöker ansluta till har säkerhetsproblem."</string> <string name="ssl_error_example" msgid="647898534624078900">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Fortsätt ändå via webbläsaren"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Sidinformation"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adress:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Säkerhetsvarning"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Visa certifikat"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Certifikatet kommer inte från en betrodd utfärdare."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Webbplatsens namn stämmer inte med namnet på certifikatet."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Certifikatet har upphört att gälla."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Certifikatet är inte giltigt än."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Det här certifikatet har ett ogiltigt datum."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Certifikatet är ogiltigt."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Okänt certifikatfel."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-sw/strings.xml b/packages/CaptivePortalLogin/res/values-sw/strings.xml index 1c8b6e1c9dcd..feb2ddeba9c1 100644 --- a/packages/CaptivePortalLogin/res/values-sw/strings.xml +++ b/packages/CaptivePortalLogin/res/values-sw/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Mtandao unaojaribu kujiunga nao una matatizo ya usalama."</string> <string name="ssl_error_example" msgid="647898534624078900">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Endelea hata hivyo kupitia kivinjari"</string> + <string name="ok" msgid="1509280796718850364">"Sawa"</string> + <string name="page_info" msgid="4048529256302257195">"Maelezo ya ukurasa"</string> + <string name="page_info_address" msgid="2222306609532903254">"Anwani:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Ilani ya usalama"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tazama cheti"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Cheti hiki hakijatoka kwa mamlaka inayoaminika."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Jina la tovuti halilingani na jina lililo katika cheti."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Cheti hiki kimepitwa na muda"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Cheti bado si halali."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Cheti hiki kina tarehe batili."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Hati hii ni batili."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Hitilafu isiyojulikana ya cheti."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-th/strings.xml b/packages/CaptivePortalLogin/res/values-th/strings.xml index 9a3a626d7dbe..11a2131dc64c 100644 --- a/packages/CaptivePortalLogin/res/values-th/strings.xml +++ b/packages/CaptivePortalLogin/res/values-th/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"เครือข่ายที่คุณพยายามเข้าร่วมมีปัญหาด้านความปลอดภัย"</string> <string name="ssl_error_example" msgid="647898534624078900">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"ดำเนินการต่อผ่านเบราว์เซอร์"</string> + <string name="ok" msgid="1509280796718850364">"ตกลง"</string> + <string name="page_info" msgid="4048529256302257195">"ข้อมูลหน้าเว็บ"</string> + <string name="page_info_address" msgid="2222306609532903254">"ที่อยู่:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"คำเตือนเกี่ยวกับความปลอดภัย"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"ดูใบรับรอง"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"ใบรับรองนี้ไม่ได้มาจากผู้ออกที่เชื่อถือได้"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"ชื่อไซต์ไม่ตรงกับในใบรับรอง"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"ใบรับรองนี้หมดอายุแล้ว"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"ใบรับรองนี้ยังใช้งานไม่ได้"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"ใบรับรองนี้มีวันที่ไม่ถูกต้อง"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"ใบรับรองนี้ไม่ถูกต้อง"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"ข้อผิดพลาดใบรับรองที่ไม่รู้จัก"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-tl/strings.xml b/packages/CaptivePortalLogin/res/values-tl/strings.xml index 565ef8f486e4..07a247992197 100644 --- a/packages/CaptivePortalLogin/res/values-tl/strings.xml +++ b/packages/CaptivePortalLogin/res/values-tl/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"May mga isyu sa seguridad ang network kung saan mo sinusubukang sumali."</string> <string name="ssl_error_example" msgid="647898534624078900">"Halimbawa, maaaring hindi sa organisasyong ipinapakita ang page sa pag-log in."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Magpatuloy pa rin sa pamamagitan ng browser"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Impormasyon ng pahina"</string> + <string name="page_info_address" msgid="2222306609532903254">"Address:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Babala sa seguridad"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Tingnan ang certificate"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Ang certificate ay hindi mula sa isang pinagkakatiwalaang kinauukulan."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Ang pangalan ng site ay hindi tumutugma sa pangalan sa certificate."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Nag-expire na ang certificate na ito."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Wala pang bisa ang certificate na ito."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Ang certificate ay mayroong di-wastong petsa."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Di-wasto ang certificate na ito."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Hindi kilalang error ng certificate."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-tr/strings.xml b/packages/CaptivePortalLogin/res/values-tr/strings.xml index 73d2455dcf3a..cdedd3306a01 100644 --- a/packages/CaptivePortalLogin/res/values-tr/strings.xml +++ b/packages/CaptivePortalLogin/res/values-tr/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Katılmaya çalıştığınız ağda güvenlik sorunları var."</string> <string name="ssl_error_example" msgid="647898534624078900">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Yine de tarayıcıyla devam et"</string> + <string name="ok" msgid="1509280796718850364">"Tamam"</string> + <string name="page_info" msgid="4048529256302257195">"Sayfa bilgileri"</string> + <string name="page_info_address" msgid="2222306609532903254">"Adres:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Güvenlik uyarısı"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Sertifikayı görüntüle"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Bu sertifika güvenilir bir yetkiliden değil."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Sitenin adı sertifika üzerindeki adla eşleşmiyor."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Bu sertifikanın süresi dolmuş."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Bu sertifika henüz geçerli değil."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Bu sertifikanın tarihi geçersiz."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Bu sertifika geçersiz."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Bilinmeyen sertifika hatası."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-uk/strings.xml b/packages/CaptivePortalLogin/res/values-uk/strings.xml index 0e818d3e3ca2..0f4cd1672427 100644 --- a/packages/CaptivePortalLogin/res/values-uk/strings.xml +++ b/packages/CaptivePortalLogin/res/values-uk/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"У мережі, до якої ви намагаєтеся під’єднатись, є проблеми з безпекою."</string> <string name="ssl_error_example" msgid="647898534624078900">"Наприклад, сторінка входу може не належати вказаній організації."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Усе одно продовжити у веб-переглядачі"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Інфо про стор."</string> + <string name="page_info_address" msgid="2222306609532903254">"Адреса:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Застереж. про небезп."</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Переглянути сертиф."</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Сертифікат видано ненадійним центром сертифікації."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Назва сайту не збігається з назвою в сертифікаті."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Термін дії сертиф. завершився."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Цей сертифікат ще не дійсний."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Цей сертифікат має недійсну дату."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Цей сертифікат недійсний."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Помилка невідомого сертифіката."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-vi/strings.xml b/packages/CaptivePortalLogin/res/values-vi/strings.xml index e51d2aa6cf9e..9c702b953fd5 100644 --- a/packages/CaptivePortalLogin/res/values-vi/strings.xml +++ b/packages/CaptivePortalLogin/res/values-vi/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Mạng mà bạn đang cố gắng tham gia có vấn đề về bảo mật."</string> <string name="ssl_error_example" msgid="647898534624078900">"Ví dụ, trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Vẫn tiếp tục qua trình duyệt"</string> + <string name="ok" msgid="1509280796718850364">"OK"</string> + <string name="page_info" msgid="4048529256302257195">"Thông tin trang"</string> + <string name="page_info_address" msgid="2222306609532903254">"Địa chỉ:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Cảnh báo bảo mật"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Xem chứng chỉ"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Chứng chỉ này không xuất phát từ tổ chức phát hành đáng tin cậy."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Tên của trang web không khớp với tên trên chứng chỉ."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Chứng chỉ này đã hết hạn."</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Chứng chỉ này chưa hợp lệ."</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Chứng chỉ này có ngày không hợp lệ."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Chứng chỉ này không hợp lệ."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Lỗi chứng chỉ không xác định."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml index ce822e7f24bf..70c2a08682af 100644 --- a/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml +++ b/packages/CaptivePortalLogin/res/values-zh-rCN/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"您尝试加入的网络存在安全问题。"</string> <string name="ssl_error_example" msgid="647898534624078900">"例如,登录页面可能并不属于页面上显示的单位。"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"仍然通过浏览器继续操作"</string> + <string name="ok" msgid="1509280796718850364">"确定"</string> + <string name="page_info" msgid="4048529256302257195">"网页信息"</string> + <string name="page_info_address" msgid="2222306609532903254">"网址:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全警告"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"查看证书"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"该证书并非来自可信的授权中心。"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"网站的名称与证书上的名称不一致。"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"该证书已过期。"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"该证书尚未生效。"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"该证书的日期无效。"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"该证书无效。"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"未知证书错误。"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml index 9010e1eebbb6..df1c700582ff 100644 --- a/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml +++ b/packages/CaptivePortalLogin/res/values-zh-rHK/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"您正在嘗試加入的網絡有安全性問題。"</string> <string name="ssl_error_example" msgid="647898534624078900">"例如,登入頁面並不屬於所顯示的機構。"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"透過瀏覽器繼續"</string> + <string name="ok" msgid="1509280796718850364">"確定"</string> + <string name="page_info" msgid="4048529256302257195">"網頁資訊"</string> + <string name="page_info_address" msgid="2222306609532903254">"地址:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全性警告"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"查看憑證"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"這個憑證並非由受信任的權威機構發出。"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"網站名稱與憑證上的名稱不相符。"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"這個憑證已過期。"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"這個憑證尚未生效。"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"此憑證的日期無效。"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"此憑證是無效的。"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"不明的憑證錯誤。"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml b/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml index 5b535e2a62cf..2a2e39729f2e 100644 --- a/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml +++ b/packages/CaptivePortalLogin/res/values-zh-rTW/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"你嘗試加入的網路有安全問題。"</string> <string name="ssl_error_example" msgid="647898534624078900">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string> <string name="ssl_error_continue" msgid="6492718244923937110">"透過瀏覽器繼續"</string> + <string name="ok" msgid="1509280796718850364">"確定"</string> + <string name="page_info" msgid="4048529256302257195">"頁面資訊"</string> + <string name="page_info_address" msgid="2222306609532903254">"位址:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"安全性警告"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"檢視憑證"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"這個憑證並非來自信任的授權單位。"</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"網站名稱與憑證上的名稱不相符。"</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"此憑證已過期"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"這個憑證尚未生效。"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"這個憑證的日期無效。"</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"這個憑證無效。"</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"不明的憑證錯誤。"</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values-zu/strings.xml b/packages/CaptivePortalLogin/res/values-zu/strings.xml index 866ba187df16..794364588f94 100644 --- a/packages/CaptivePortalLogin/res/values-zu/strings.xml +++ b/packages/CaptivePortalLogin/res/values-zu/strings.xml @@ -9,4 +9,16 @@ <string name="ssl_error_warning" msgid="6653188881418638872">"Inethiwekhi ozama ukuyijoyina inezinkinga zokuvikela."</string> <string name="ssl_error_example" msgid="647898534624078900">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string> <string name="ssl_error_continue" msgid="6492718244923937110">"Qhubeka noma kunjalo ngesiphequluli"</string> + <string name="ok" msgid="1509280796718850364">"KULUNGILE"</string> + <string name="page_info" msgid="4048529256302257195">"Ulwazi lekhasi"</string> + <string name="page_info_address" msgid="2222306609532903254">"Ikheli:"</string> + <string name="ssl_security_warning_title" msgid="6607795404322797541">"Isexwayiso sokuvikeleka"</string> + <string name="ssl_error_view_certificate" msgid="1472768887529093862">"Buka isitifiketi"</string> + <string name="ssl_error_untrusted" msgid="7754507359360636447">"Lesi sitifiketi asiphumi embusweni othembekile."</string> + <string name="ssl_error_mismatch" msgid="3809794439740523641">"Igama lale ngosi alifani negama elikusitifiketi."</string> + <string name="ssl_error_expired" msgid="5739349389499575559">"Lesi sitifiketi siphelelwe yisikhathi"</string> + <string name="ssl_error_not_yet_valid" msgid="8193083327719048247">"Lesi sitifiketi asilungile okwamanje"</string> + <string name="ssl_error_date_invalid" msgid="3705563379257285534">"Lesi sitifiketi sinosuku olungalungile."</string> + <string name="ssl_error_invalid" msgid="9041704741505449967">"Lesi sitifiketi asilungile."</string> + <string name="ssl_error_unknown" msgid="5679243486524754571">"Iphutha lesitifiketi elingaziwa."</string> </resources> diff --git a/packages/CaptivePortalLogin/res/values/strings.xml b/packages/CaptivePortalLogin/res/values/strings.xml index f486fe4c5ddf..e9698dbbd784 100644 --- a/packages/CaptivePortalLogin/res/values/strings.xml +++ b/packages/CaptivePortalLogin/res/values/strings.xml @@ -9,5 +9,17 @@ <string name="ssl_error_warning">The network you’re trying to join has security issues.</string> <string name="ssl_error_example">For example, the login page may not belong to the organization shown.</string> <string name="ssl_error_continue">Continue anyway via browser</string> + <string name="ssl_error_untrusted">This certificate isn\'t from a trusted authority.</string> + <string name="ssl_error_mismatch">The name of the site doesn\'t match the name on the certificate.</string> + <string name="ssl_error_expired">This certificate has expired.</string> + <string name="ssl_error_not_yet_valid">This certificate isn\'t valid yet.</string> + <string name="ssl_error_date_invalid">This certificate has an invalid date.</string> + <string name="ssl_error_invalid">This certificate is invalid.</string> + <string name="ssl_error_unknown">Unknown certificate error.</string> + <string name="ssl_security_warning_title">Security warning</string> + <string name="ssl_error_view_certificate">View certificate</string> + <string name="ok">OK</string> + <string name="page_info_address">Address:</string> + <string name="page_info">Page info</string> </resources> diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 0ba37aedc8f7..83084c519f19 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -20,8 +20,10 @@ import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC; import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME; import android.app.Activity; +import android.app.AlertDialog; import android.app.LoadedApk; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.net.CaptivePortal; @@ -33,6 +35,7 @@ import android.net.NetworkRequest; import android.net.Proxy; import android.net.Uri; import android.net.captiveportal.CaptivePortalProbeSpec; +import android.net.http.SslCertificate; import android.net.http.SslError; import android.net.wifi.WifiInfo; import android.os.Build; @@ -42,8 +45,9 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; -import android.util.TypedValue; import android.util.SparseArray; +import android.util.TypedValue; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -52,8 +56,8 @@ import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; -import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -276,6 +280,13 @@ public class CaptivePortalLoginActivity extends Activity { @Override public void onDestroy() { super.onDestroy(); + final WebView webview = (WebView) findViewById(R.id.webview); + if (webview != null) { + webview.stopLoading(); + webview.setWebViewClient(null); + webview.setWebChromeClient(null); + webview.destroy(); + } if (mNetworkCallback != null) { // mNetworkCallback is not null if mUrl is not null. mCm.unregisterNetworkCallback(mNetworkCallback); @@ -382,6 +393,7 @@ public class CaptivePortalLoginActivity extends Activity { private static final String INTERNAL_ASSETS = "file:///android_asset/"; private final String mBrowserBailOutToken = Long.toString(new Random().nextLong()); + private final String mCertificateOutToken = Long.toString(new Random().nextLong()); // How many Android device-independent-pixels per scaled-pixel // dp/sp = (px/sp) / (px/dp) = (1/sp) / (1/dp) private final float mDpPerSp = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1, @@ -397,6 +409,10 @@ public class CaptivePortalLoginActivity extends Activity { return mPagesLoaded > 1; } + private String mSslErrorTitle = null; + private SslErrorHandler mSslErrorHandler = null; + private SslError mSslError = null; + @Override public void onPageStarted(WebView view, String urlString, Bitmap favicon) { if (urlString.contains(mBrowserBailOutToken)) { @@ -473,12 +489,16 @@ public class CaptivePortalLoginActivity extends Activity { logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR); final String sslErrorPage = makeSslErrorPage(); view.loadDataWithBaseURL(INTERNAL_ASSETS, sslErrorPage, "text/HTML", "UTF-8", null); + mSslErrorTitle = view.getTitle() == null ? "" : view.getTitle(); + mSslErrorHandler = handler; + mSslError = error; } private String makeSslErrorPage() { final String warningMsg = getString(R.string.ssl_error_warning); final String exampleMsg = getString(R.string.ssl_error_example); final String continueMsg = getString(R.string.ssl_error_continue); + final String certificateMsg = getString(R.string.ssl_error_view_certificate); return String.join("\n", "<html>", "<head>", @@ -516,13 +536,18 @@ public class CaptivePortalLoginActivity extends Activity { " text-decoration:none;", " text-transform:uppercase;", " }", + " a.certificate {", + " margin-top:0px;", + " }", " </style>", "</head>", "<body>", " <p><img src=quantum_ic_warning_amber_96.png><br>", " <div class=warn>" + warningMsg + "</div>", " <div class=example>" + exampleMsg + "</div>", - " <a href=" + mBrowserBailOutToken + ">" + continueMsg + "</a>", + " <a href=" + mBrowserBailOutToken + ">" + continueMsg + "</a><br>", + " <a class=certificate href=" + mCertificateOutToken + ">" + certificateMsg + + "</a>", "</body>", "</html>"); } @@ -533,8 +558,50 @@ public class CaptivePortalLoginActivity extends Activity { startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url))); return true; } + if (url.contains(mCertificateOutToken) && mSslError != null) { + showSslAlertDialog(mSslErrorHandler, mSslError, mSslErrorTitle); + return true; + } return false; } + private void showSslAlertDialog(SslErrorHandler handler, SslError error, String title) { + final LayoutInflater factory = LayoutInflater.from(CaptivePortalLoginActivity.this); + final View sslWarningView = factory.inflate(R.layout.ssl_warning, null); + + // Set Security certificate + setViewSecurityCertificate(sslWarningView.findViewById(R.id.certificate_layout), error); + ((TextView) sslWarningView.findViewById(R.id.ssl_error_type)) + .setText(sslErrorName(error)); + ((TextView) sslWarningView.findViewById(R.id.title)).setText(mSslErrorTitle); + ((TextView) sslWarningView.findViewById(R.id.address)).setText(error.getUrl()); + + AlertDialog sslAlertDialog = new AlertDialog.Builder(CaptivePortalLoginActivity.this) + .setTitle(R.string.ssl_security_warning_title) + .setView(sslWarningView) + .setPositiveButton(R.string.ok, (DialogInterface dialog, int whichButton) -> { + // handler.cancel is called via OnCancelListener. + dialog.cancel(); + }) + .setOnCancelListener((DialogInterface dialogInterface) -> handler.cancel()) + .create(); + sslAlertDialog.show(); + } + + private void setViewSecurityCertificate(LinearLayout certificateLayout, SslError error) { + SslCertificate cert = error.getCertificate(); + + View certificateView = cert.inflateCertificateView(CaptivePortalLoginActivity.this); + final LinearLayout placeholder = (LinearLayout) certificateView + .findViewById(com.android.internal.R.id.placeholder); + LayoutInflater factory = LayoutInflater.from(CaptivePortalLoginActivity.this); + + TextView textView = (TextView) factory.inflate( + R.layout.ssl_error_msg, placeholder, false); + textView.setText(sslErrorMessage(error)); + placeholder.addView(textView); + + certificateLayout.addView(certificateView); + } } private class MyWebChromeClient extends WebChromeClient { @@ -587,4 +654,18 @@ public class CaptivePortalLoginActivity extends Activity { private static String sslErrorName(SslError error) { return SSL_ERRORS.get(error.getPrimaryError(), "UNKNOWN"); } + + private static final SparseArray<Integer> SSL_ERROR_MSGS = new SparseArray<>(); + static { + SSL_ERROR_MSGS.put(SslError.SSL_NOTYETVALID, R.string.ssl_error_not_yet_valid); + SSL_ERROR_MSGS.put(SslError.SSL_EXPIRED, R.string.ssl_error_expired); + SSL_ERROR_MSGS.put(SslError.SSL_IDMISMATCH, R.string.ssl_error_mismatch); + SSL_ERROR_MSGS.put(SslError.SSL_UNTRUSTED, R.string.ssl_error_untrusted); + SSL_ERROR_MSGS.put(SslError.SSL_DATE_INVALID, R.string.ssl_error_date_invalid); + SSL_ERROR_MSGS.put(SslError.SSL_INVALID, R.string.ssl_error_invalid); + } + + private static Integer sslErrorMessage(SslError error) { + return SSL_ERROR_MSGS.get(error.getPrimaryError(), R.string.ssl_error_unknown); + } } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 4abcf73af109..c9ee5c87de0f 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -541,14 +541,14 @@ public class ExternalStorageProvider extends FileSystemProvider { } @Override - public Cursor querySearchDocuments(String rootId, String query, String[] projection) + public Cursor querySearchDocuments(String rootId, String[] projection, Bundle queryArgs) throws FileNotFoundException { final File parent; synchronized (mRootsLock) { parent = mRoots.get(rootId).path; } - return querySearchDocuments(parent, query, projection, Collections.emptySet()); + return querySearchDocuments(parent, projection, Collections.emptySet(), queryArgs); } @Override diff --git a/packages/SettingsLib/SettingsSpinner/res/values/styles.xml b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml index 8447b083b9e1..8af20e20ede9 100644 --- a/packages/SettingsLib/SettingsSpinner/res/values/styles.xml +++ b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml @@ -17,7 +17,7 @@ <resources> <style name="SettingsSpinnerTitleBar"> - <item name="android:textAppearance">?android:attr/textAppearance</item> + <item name="android:textAppearance">?android:attr/textAppearanceButton</item> <item name="android:paddingStart">16dp</item> <item name="android:paddingEnd">36dp</item> <item name="android:paddingTop">8dp</item> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 0dbc037f2298..2f082b959e68 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -152,7 +152,11 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro private boolean mNetworkScoringUiEnabled; private long mMaxSpeedLabelScoreCacheAge; - + private static final String WIFI_SECURITY_PSK = "PSK"; + private static final String WIFI_SECURITY_EAP = "EAP"; + private static final String WIFI_SECURITY_SAE = "SAE"; + private static final String WIFI_SECURITY_OWE = "OWE"; + private static final String WIFI_SECURITY_SUITE_B_192 = "SUITE_B_192"; @VisibleForTesting Scanner mScanner; @@ -505,13 +509,18 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro * {@link #updateAccessPoints(List, List)}. */ private void fetchScansAndConfigsAndUpdateAccessPoints() { - final List<ScanResult> newScanResults = mWifiManager.getScanResults(); + List<ScanResult> newScanResults = mWifiManager.getScanResults(); + + // Filter all unsupported networks from the scan result list + final List<ScanResult> filteredScanResults = + filterScanResultsByCapabilities(newScanResults); + if (isVerboseLoggingEnabled()) { - Log.i(TAG, "Fetched scan results: " + newScanResults); + Log.i(TAG, "Fetched scan results: " + filteredScanResults); } List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); - updateAccessPoints(newScanResults, configs); + updateAccessPoints(filteredScanResults, configs); } /** Update the internal list of access points. */ @@ -937,4 +946,49 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mListener.onAccessPointsChanged(); } + + /** + * Filters unsupported networks from scan results. New WPA3 networks and OWE networks + * may not be compatible with the device HW/SW. + * @param scanResults List of scan results + * @return List of filtered scan results based on local device capabilities + */ + private List<ScanResult> filterScanResultsByCapabilities(List<ScanResult> scanResults) { + if (scanResults == null) { + return null; + } + + // Get and cache advanced capabilities + final boolean isOweSupported = mWifiManager.isOweSupported(); + final boolean isSaeSupported = mWifiManager.isWpa3SaeSupported(); + final boolean isSuiteBSupported = mWifiManager.isWpa3SuiteBSupported(); + + List<ScanResult> filteredScanResultList = new ArrayList<>(); + + // Iterate through the list of scan results and filter out APs which are not + // compatible with our device. + for (ScanResult scanResult : scanResults) { + if (scanResult.capabilities.contains(WIFI_SECURITY_PSK)) { + // All devices (today) support RSN-PSK or WPA-PSK + // Add this here because some APs may support both PSK and SAE and the check + // below will filter it out. + filteredScanResultList.add(scanResult); + continue; + } + + if ((scanResult.capabilities.contains(WIFI_SECURITY_SUITE_B_192) && !isSuiteBSupported) + || (scanResult.capabilities.contains(WIFI_SECURITY_SAE) && !isSaeSupported) + || (scanResult.capabilities.contains(WIFI_SECURITY_OWE) && !isOweSupported)) { + if (isVerboseLoggingEnabled()) { + Log.v(TAG, "filterScanResultsByCapabilities: Filtering SSID " + + scanResult.SSID + " with capabilities: " + scanResult.capabilities); + } + } else { + // Safe to add + filteredScanResultList.add(scanResult); + } + } + + return filteredScanResultList; + } } diff --git a/packages/SystemUI/res/drawable/stat_sys_camera.xml b/packages/SystemUI/res/drawable/stat_sys_camera.xml new file mode 100644 index 000000000000..eb3e9632dd35 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_camera.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** 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. +*/ +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="3dp" + android:insetRight="3dp"> + <vector + android:width="17dp" + android:height="17dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFF" + android:pathData="M20,5h-3.17L15,3H9L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM20,19H4V7h16V19zM12,9c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C16,10.79 14.21,9 12,9z"/> + </vector> +</inset> diff --git a/packages/SystemUI/res/drawable/stat_sys_mic_none.xml b/packages/SystemUI/res/drawable/stat_sys_mic_none.xml new file mode 100644 index 000000000000..d6bdf9fbaa78 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_mic_none.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** 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. +*/ +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="18dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFF" + android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/> + <path + android:fillColor="#FFF" + android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/> +</vector> diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index f554150ab0d0..890bf5d8ac45 100644 --- a/packages/SystemUI/res/layout/qs_footer_impl.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -62,7 +62,7 @@ android:layout_weight="1" android:layout_marginEnd="32dp" android:ellipsize="marquee" - android:textAppearance="@style/TextAppearance.QS.TileLabel" + android:textAppearance="@style/TextAppearance.QS.CarrierInfo" android:textColor="?android:attr/textColorPrimary" android:textDirection="locale" android:singleLine="true" /> diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml index 980442c488f4..f34161e285da 100644 --- a/packages/SystemUI/res/layout/qs_tile_label.xml +++ b/packages/SystemUI/res/layout/qs_tile_label.xml @@ -79,7 +79,7 @@ android:padding="0dp" android:visibility="gone" android:gravity="center" - android:textAppearance="@style/TextAppearance.QS.TileLabel" + android:textAppearance="@style/TextAppearance.QS.TileLabel.Secondary" android:textColor="?android:attr/textColorSecondary"/> <View diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 0e41a7fd7d28..d4e698722662 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -369,6 +369,7 @@ <dimen name="qs_page_indicator_height">8dp</dimen> <dimen name="qs_tile_icon_size">24dp</dimen> <dimen name="qs_tile_text_size">12sp</dimen> + <dimen name="qs_carrier_info_text_size">14sp</dimen> <dimen name="qs_tile_divider_height">1dp</dimen> <dimen name="qs_panel_padding">16dp</dimen> <dimen name="qs_dual_tile_height">112dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 6244e1c4a509..95fd86fd2e95 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -125,7 +125,7 @@ <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon"> <item name="android:textSize">@dimen/status_bar_clock_size</item> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> <item name="android:textColor">@color/status_bar_clock_color</item> </style> @@ -135,7 +135,7 @@ <style name="TextAppearance.StatusBar.Expanded.Clock"> <item name="android:textSize">@dimen/qs_time_expanded_size</item> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textStyle">normal</item> </style> @@ -240,9 +240,19 @@ <style name="TextAppearance.QS.TileLabel"> <item name="android:textSize">@dimen/qs_tile_text_size</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + </style> + + <style name="TextAppearance.QS.TileLabel.Secondary"> + <item name="android:textSize">@dimen/qs_tile_text_size</item> <item name="android:fontFamily">sans-serif</item> </style> + <style name="TextAppearance.QS.CarrierInfo"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textSize">@dimen/qs_carrier_info_text_size</item> + </style> + <style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt index f4099021a0bd..3d9aa0ff083f 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt @@ -23,9 +23,9 @@ import com.android.systemui.R typealias Privacy = PrivacyType enum class PrivacyType(val nameId: Int, val iconId: Int) { - TYPE_CAMERA(R.string.privacy_type_camera, com.android.internal.R.drawable.ic_camera), + TYPE_CAMERA(R.string.privacy_type_camera, R.drawable.stat_sys_camera), TYPE_LOCATION(R.string.privacy_type_location, R.drawable.stat_sys_location), - TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.ic_mic_26dp); + TYPE_MICROPHONE(R.string.privacy_type_microphone, R.drawable.stat_sys_mic_none); fun getName(context: Context) = context.resources.getString(nameId) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index b838c9b5482d..37bf06edde4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -21,6 +21,8 @@ import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.service.notification.NotificationListenerService.Ranking .USER_SENTIMENT_NEGATIVE; +import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_NONE; + import android.app.INotificationManager; import android.app.NotificationChannel; import android.content.Context; @@ -189,7 +191,13 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } else if (gutsView instanceof AppOpsInfo) { initializeAppOpsInfo(row, (AppOpsInfo) gutsView); } else if (gutsView instanceof NotificationInfo) { - initializeNotificationInfo(row, (NotificationInfo) gutsView); + int action; + if (item instanceof NotificationMenuRow.NotificationInfoMenuItem) { + action = ((NotificationMenuRow.NotificationInfoMenuItem) item).mAction; + } else { + action = ACTION_NONE; + } + initializeNotificationInfo(row, (NotificationInfo) gutsView, action); } return true; } catch (Exception e) { @@ -246,14 +254,15 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx /** * Sets up the {@link NotificationInfo} inside the notification row's guts. - * * @param row view to set up the guts for * @param notificationInfoView view to set up/bind within {@code row} + * @param action The action to take immediately upon binding, if any. */ @VisibleForTesting void initializeNotificationInfo( final ExpandableNotificationRow row, - NotificationInfo notificationInfoView) throws Exception { + NotificationInfo notificationInfoView, + @NotificationInfo.NotificationInfoAction int action) throws Exception { NotificationGuts guts = row.getGuts(); StatusBarNotification sbn = row.getStatusBarNotification(); String packageName = sbn.getPackageName(); @@ -297,7 +306,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx isForBlockingHelper, row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE, row.getEntry().noisy, - row.getEntry().importance); + row.getEntry().importance, + action); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 522da4d51470..3a7091bb843a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -71,16 +71,19 @@ import java.util.List; public class NotificationInfo extends LinearLayout implements NotificationGuts.GutsContent { private static final String TAG = "InfoGuts"; - @IntDef(prefix = { "SWAP_CONTENT_" }, value = { - SWAP_CONTENT_UNDO, - SWAP_CONTENT_TOGGLE_SILENT, - SWAP_CONTENT_BLOCK, + @IntDef(prefix = { "ACTION_" }, value = { + ACTION_NONE, + ACTION_UNDO, + ACTION_TOGGLE_SILENT, + ACTION_BLOCK, }) - @interface SwapContentAction {} + public @interface NotificationInfoAction { + } - private static final int SWAP_CONTENT_UNDO = 0; - private static final int SWAP_CONTENT_TOGGLE_SILENT = 1; - private static final int SWAP_CONTENT_BLOCK = 2; + public static final int ACTION_NONE = 0; + public static final int ACTION_UNDO = 1; + public static final int ACTION_TOGGLE_SILENT = 2; + public static final int ACTION_BLOCK = 3; private INotificationManager mINotificationManager; private PackageManager mPm; @@ -123,8 +126,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnToggleSilent = v -> { Runnable saveImportance = () -> { - mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; - swapContent(SWAP_CONTENT_TOGGLE_SILENT); + swapContent(ACTION_TOGGLE_SILENT, true /* animate */); }; if (mCheckSaveListener != null) { mCheckSaveListener.checkSave(saveImportance, mSbn); @@ -135,8 +137,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnStopOrMinimizeNotifications = v -> { Runnable saveImportance = () -> { - mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS; - swapContent(SWAP_CONTENT_BLOCK); + swapContent(ACTION_BLOCK, true /* animate */); }; if (mCheckSaveListener != null) { mCheckSaveListener.checkSave(saveImportance, mSbn); @@ -149,7 +150,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G // Reset exit counter that we'll log and record an undo event separately (not an exit event) mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO); - swapContent(SWAP_CONTENT_UNDO); + swapContent(ACTION_UNDO, true /* animate */); }; public NotificationInfo(Context context, AttributeSet attrs) { @@ -185,13 +186,14 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean isDeviceProvisioned, boolean isNonblockable, boolean isNoisy, - int importance) + int importance, + @NotificationInfoAction int action) throws RemoteException { bindNotification(pm, iNotificationManager, pkg, notificationChannel, numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick, onAppSettingsClick, isDeviceProvisioned, isNonblockable, false /* isBlockingHelper */, false /* isUserSentimentNegative */, isNoisy, - importance); + importance, action); } public void bindNotification( @@ -209,7 +211,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean isForBlockingHelper, boolean isUserSentimentNegative, boolean isNoisy, - int importance) + int importance, + @NotificationInfoAction int action) throws RemoteException { mINotificationManager = iNotificationManager; mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -250,6 +253,10 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G bindHeader(); bindPrompt(); bindButtons(); + + if (action != ACTION_NONE) { + swapContent(action, false /* don't animate */); + } } private void bindHeader() throws RemoteException { @@ -351,7 +358,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } private void saveImportance() { - if (!mIsNonblockable) { + if (!mIsNonblockable + || mExitReason != NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS) { updateImportance(); } } @@ -421,7 +429,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - private void swapContent(@SwapContentAction int action) { + private void swapContent(@NotificationInfoAction int action, boolean animate) { if (mExpandAnimation != null) { mExpandAnimation.cancel(); } @@ -432,10 +440,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G View header = findViewById(R.id.header); switch (action) { - case SWAP_CONTENT_UNDO: + case ACTION_UNDO: mChosenImportance = mStartingChannelImportance; break; - case SWAP_CONTENT_TOGGLE_SILENT: + case ACTION_TOGGLE_SILENT: + mExitReason = NotificationCounters.BLOCKING_HELPER_TOGGLE_SILENT; if (mStartingChannelOrNotificationImportance >= IMPORTANCE_DEFAULT) { mChosenImportance = IMPORTANCE_LOW; confirmationText.setText(R.string.notification_channel_silenced); @@ -444,7 +453,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G confirmationText.setText(R.string.notification_channel_unsilenced); } break; - case SWAP_CONTENT_BLOCK: + case ACTION_BLOCK: + mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS; if (mIsForeground) { mChosenImportance = IMPORTANCE_MIN; confirmationText.setText(R.string.notification_channel_minimized); @@ -457,38 +467,41 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G throw new IllegalArgumentException(); } - boolean isUndo = action == SWAP_CONTENT_UNDO; - ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA, - prompt.getAlpha(), isUndo ? 1f : 0f); - promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT); - ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA, - confirmation.getAlpha(), isUndo ? 0f : 1f); - confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN); + boolean isUndo = action == ACTION_UNDO; prompt.setVisibility(isUndo ? VISIBLE : GONE); confirmation.setVisibility(isUndo ? GONE : VISIBLE); header.setVisibility(isUndo ? VISIBLE : GONE); - mExpandAnimation = new AnimatorSet(); - mExpandAnimation.playTogether(promptAnim, confirmAnim); - mExpandAnimation.setDuration(150); - mExpandAnimation.addListener(new AnimatorListenerAdapter() { - boolean cancelled = false; - - @Override - public void onAnimationCancel(Animator animation) { - cancelled = true; - } + if (animate) { + ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA, + prompt.getAlpha(), isUndo ? 1f : 0f); + promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT); + ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA, + confirmation.getAlpha(), isUndo ? 0f : 1f); + confirmAnim.setInterpolator(isUndo ? Interpolators.ALPHA_OUT : Interpolators.ALPHA_IN); + + mExpandAnimation = new AnimatorSet(); + mExpandAnimation.playTogether(promptAnim, confirmAnim); + mExpandAnimation.setDuration(150); + mExpandAnimation.addListener(new AnimatorListenerAdapter() { + boolean mCancelled = false; + + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } - @Override - public void onAnimationEnd(Animator animation) { - if (!cancelled) { - prompt.setVisibility(isUndo ? VISIBLE : GONE); - confirmation.setVisibility(isUndo ? GONE : VISIBLE); + @Override + public void onAnimationEnd(Animator animation) { + if (!mCancelled) { + prompt.setVisibility(isUndo ? VISIBLE : GONE); + confirmation.setVisibility(isUndo ? GONE : VISIBLE); + } } - } - }); - mExpandAnimation.start(); + }); + mExpandAnimation.start(); + } // Since we're swapping/update the content, reset the timeout so the UI can't close // immediately after the update. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index 674c8ee3f35c..2bc4f02be13e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.row; import static com.android.systemui.SwipeHelper.SWIPED_FAR_ENOUGH_SIZE_FRACTION; +import static com.android.systemui.statusbar.notification.row.NotificationInfo.ACTION_NONE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -41,6 +42,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.AlphaOptimizedImageView; import com.android.systemui.statusbar.notification.row.NotificationGuts.GutsContent; +import com.android.systemui.statusbar.notification.row.NotificationInfo.NotificationInfoAction; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.util.ArrayList; @@ -610,8 +612,8 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl String infoDescription = res.getString(R.string.notification_menu_gear_description); NotificationInfo infoContent = (NotificationInfo) LayoutInflater.from(context).inflate( R.layout.notification_info, null, false); - MenuItem info = new NotificationMenuItem(context, infoDescription, infoContent, - R.drawable.ic_settings); + MenuItem info = new NotificationInfoMenuItem(context, infoDescription, infoContent, + R.drawable.ic_settings, ACTION_NONE); return info; } @@ -737,4 +739,18 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl return mContentDescription; } } + + /** A {@link NotificationMenuItem} with an associated {@link NotificationInfoAction}. */ + public static class NotificationInfoMenuItem extends NotificationMenuItem { + + @NotificationInfoAction + int mAction; + + public NotificationInfoMenuItem(Context context, String s, + NotificationInfo content, int iconResId, + @NotificationInfoAction int action) { + super(context, s, content, iconResId); + this.mAction = action; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 0e6efc8472b6..c84f3db8acb0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -66,6 +66,8 @@ import com.android.systemui.DockedStackExistsListener; import com.android.systemui.R; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.UiOffloadThread; +import com.android.systemui.privacy.PrivacyItem; +import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -101,7 +103,8 @@ import java.util.Locale; */ public class PhoneStatusBarPolicy implements Callback, Callbacks, RotationLockControllerCallback, Listener, LocationChangeCallback, - ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback { + ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback, + PrivacyItemController.Callback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -120,6 +123,8 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, private final String mSlotHeadset; private final String mSlotDataSaver; private final String mSlotLocation; + private final String mSlotMicrophone; + private final String mSlotCamera; private final Context mContext; private final Handler mHandler = new Handler(); @@ -136,6 +141,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, private final DeviceProvisionedController mProvisionedController; private final KeyguardMonitor mKeyguardMonitor; private final LocationController mLocationController; + private final PrivacyItemController mPrivacyItemController; private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>(); private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); @@ -169,6 +175,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mProvisionedController = Dependency.get(DeviceProvisionedController.class); mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); mLocationController = Dependency.get(LocationController.class); + mPrivacyItemController = new PrivacyItemController(mContext, this); mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast); mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot); @@ -183,6 +190,8 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset); mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver); mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location); + mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone); + mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera); // listen for broadcasts IntentFilter filter = new IntentFilter(); @@ -241,6 +250,12 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, context.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); + // privacy items + mIconController.setIcon(mSlotMicrophone, R.drawable.stat_sys_mic_none, null); + mIconController.setIconVisibility(mSlotMicrophone, false); + mIconController.setIcon(mSlotCamera, R.drawable.stat_sys_camera, null); + mIconController.setIconVisibility(mSlotCamera, false); + mRotationLockController.addCallback(this); mBluetooth.addCallback(this); mProvisionedController.addCallback(this); @@ -251,6 +266,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mDataSaver.addCallback(this); mKeyguardMonitor.addCallback(this); mLocationController.addCallback(this); + mPrivacyItemController.setListening(true); SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this); ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener); @@ -279,6 +295,7 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mDataSaver.removeCallback(this); mKeyguardMonitor.removeCallback(this); mLocationController.removeCallback(this); + mPrivacyItemController.setListening(false); SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this); mContext.unregisterReceiver(mIntentReceiver); @@ -798,6 +815,34 @@ public class PhoneStatusBarPolicy implements Callback, Callbacks, mIconController.setIconVisibility(mSlotDataSaver, isDataSaving); } + @Override // PrivacyItemController.Callback + public void privacyChanged(List<PrivacyItem> privacyItems) { + updatePrivacyItems(privacyItems); + } + + private void updatePrivacyItems(List<PrivacyItem> items) { + boolean showCamera = false; + boolean showMicrophone = false; + boolean showLocation = false; + for (PrivacyItem item : items) { + switch (item.getPrivacyType()) { + case TYPE_CAMERA: + showCamera = true; + break; + case TYPE_LOCATION: + showLocation = true; + break; + case TYPE_MICROPHONE: + showMicrophone = true; + break; + } + } + + mIconController.setIconVisibility(mSlotCamera, showCamera); + mIconController.setIconVisibility(mSlotMicrophone, showMicrophone); + mIconController.setIconVisibility(mSlotLocation, showLocation); + } + private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() { @Override public void onTaskStackChanged() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 626726d4aa4f..3d2ea708e90e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -284,7 +284,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView); + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_NONE); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -301,7 +302,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0)); + eq(0), + eq(NotificationInfo.ACTION_NONE)); } @Test @@ -313,7 +315,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView); + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_NONE); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -330,7 +333,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0)); + eq(0), + eq(NotificationInfo.ACTION_NONE)); } @Test @@ -343,7 +347,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView); + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_NONE); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -360,7 +365,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(true) /*isNoisy */, - eq(0)); + eq(0), + eq(NotificationInfo.ACTION_NONE)); } @Test @@ -373,7 +379,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(row.getIsNonblockable()).thenReturn(false); StatusBarNotification statusBarNotification = row.getStatusBarNotification(); - mGutsManager.initializeNotificationInfo(row, notificationInfoView); + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_NONE); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -390,7 +397,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(IMPORTANCE_DEFAULT)); + eq(IMPORTANCE_DEFAULT), + eq(NotificationInfo.ACTION_NONE)); } @Test @@ -403,7 +411,8 @@ public class NotificationGutsManagerTest extends SysuiTestCase { StatusBarNotification statusBarNotification = row.getStatusBarNotification(); when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); - mGutsManager.initializeNotificationInfo(row, notificationInfoView); + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_NONE); verify(notificationInfoView).bindNotification( any(PackageManager.class), @@ -420,7 +429,39 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false) /* isForBlockingHelper */, eq(true) /* isUserSentimentNegative */, eq(false) /*isNoisy */, - eq(0)); + eq(0), + eq(NotificationInfo.ACTION_NONE)); + } + + @Test + public void testInitializeNotificationInfoView_withInitialAction() throws Exception { + NotificationInfo notificationInfoView = mock(NotificationInfo.class); + ExpandableNotificationRow row = spy(mHelper.createRow()); + row.setBlockingHelperShowing(true); + row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE; + when(row.getIsNonblockable()).thenReturn(false); + StatusBarNotification statusBarNotification = row.getStatusBarNotification(); + + mGutsManager.initializeNotificationInfo(row, notificationInfoView, + NotificationInfo.ACTION_BLOCK); + + verify(notificationInfoView).bindNotification( + any(PackageManager.class), + any(INotificationManager.class), + eq(statusBarNotification.getPackageName()), + any(NotificationChannel.class), + anyInt(), + eq(statusBarNotification), + any(NotificationInfo.CheckSaveListener.class), + any(NotificationInfo.OnSettingsClickListener.class), + any(NotificationInfo.OnAppSettingsClickListener.class), + eq(false), + eq(false), + eq(true) /* isForBlockingHelper */, + eq(true) /* isUserSentimentNegative */, + eq(false) /*isNoisy */, + eq(0), + eq(NotificationInfo.ACTION_BLOCK)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 37441963e32d..1cc1c637983b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -187,7 +187,7 @@ public class NotificationInfoTest extends SysuiTestCase { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView textView = mNotificationInfo.findViewById(R.id.pkgname); assertTrue(textView.getText().toString().contains("App Name")); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -200,7 +200,7 @@ public class NotificationInfoTest extends SysuiTestCase { .thenReturn(iconDrawable); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final ImageView iconView = mNotificationInfo.findViewById(R.id.pkgicon); assertEquals(iconDrawable, iconView.getDrawable()); } @@ -209,7 +209,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(GONE, groupNameView.getVisibility()); final TextView groupDividerView = mNotificationInfo.findViewById(R.id.pkg_group_divider); @@ -226,7 +226,7 @@ public class NotificationInfoTest extends SysuiTestCase { .thenReturn(notificationChannelGroup); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(View.VISIBLE, groupNameView.getVisibility()); assertEquals("Test Group Name", groupNameView.getText()); @@ -238,7 +238,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SetsTextChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(TEST_CHANNEL_NAME, textView.getText()); } @@ -247,7 +247,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true, - false, false, IMPORTANCE_DEFAULT); + false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, textView.getVisibility()); } @@ -260,7 +260,7 @@ public class NotificationInfoTest extends SysuiTestCase { eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, true, - false, false, IMPORTANCE_DEFAULT); + false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @@ -269,7 +269,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView textView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(VISIBLE, textView.getVisibility()); } @@ -278,7 +278,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_BlockButton() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View block = mNotificationInfo.findViewById(R.id.block); final View toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); final View minimize = mNotificationInfo.findViewById(R.id.minimize); @@ -292,7 +292,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -304,7 +304,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_LOW); + true, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -316,7 +316,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -329,7 +329,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_LOW); + true, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); final TextView toggleSilent = mNotificationInfo.findViewById(R.id.toggle_silent); assertEquals(VISIBLE, toggleSilent.getVisibility()); assertEquals( @@ -341,7 +341,7 @@ public class NotificationInfoTest extends SysuiTestCase { mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View block = mNotificationInfo.findViewById(R.id.block); final View minimize = mNotificationInfo.findViewById(R.id.minimize); assertEquals(GONE, block.getVisibility()); @@ -356,7 +356,7 @@ public class NotificationInfoTest extends SysuiTestCase { (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); latch.countDown(); - }, null, true, false, false, IMPORTANCE_DEFAULT); + }, null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View settingsButton = mNotificationInfo.findViewById(R.id.info); settingsButton.performClick(); @@ -368,7 +368,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -380,7 +380,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, (View v, NotificationChannel c, int appUid) -> { assertEquals(mNotificationChannel, c); - }, null, false, false, false, IMPORTANCE_DEFAULT); + }, null, false, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -389,11 +389,11 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_SettingsButtonReappearsAfterSecondBind() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, (View v, NotificationChannel c, int appUid) -> { - }, null, true, false, false, IMPORTANCE_DEFAULT); + }, null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertEquals(View.VISIBLE, settingsButton.getVisibility()); } @@ -402,7 +402,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testLogBlockingHelperCounter_doesntLogForNormalGutsView() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger, times(0)).count(anyString(), anyInt()); } @@ -411,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true, - true, true, false, IMPORTANCE_DEFAULT); + true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger, times(1)).count(anyString(), anyInt()); } @@ -424,7 +424,7 @@ public class NotificationInfoTest extends SysuiTestCase { (View v, NotificationChannel c, int appUid) -> { assertEquals(null, c); latch.countDown(); - }, null, true, true, false, IMPORTANCE_DEFAULT); + }, null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.info).performClick(); // Verify that listener was triggered. @@ -437,7 +437,7 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, false, IMPORTANCE_DEFAULT); + null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView channelNameView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, channelNameView.getVisibility()); @@ -448,7 +448,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, false, IMPORTANCE_DEFAULT); + null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView blockView = mNotificationInfo.findViewById(R.id.block); assertEquals(GONE, blockView.getVisibility()); } @@ -457,7 +457,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testbindNotification_BlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, false, - true, true, false, IMPORTANCE_DEFAULT); + true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.inline_blocking_helper), view.getText()); @@ -467,7 +467,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.notification_unblockable_desc), @@ -478,7 +478,7 @@ public class NotificationInfoTest extends SysuiTestCase { public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), any()); @@ -489,7 +489,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -503,7 +503,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); mTestableLooper.processAllMessages(); @@ -517,7 +517,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); mTestableLooper.processAllMessages(); @@ -531,7 +531,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); mTestableLooper.processAllMessages(); @@ -545,7 +545,7 @@ public class NotificationInfoTest extends SysuiTestCase { int originalImportance = mNotificationChannel.getImportance(); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -560,7 +560,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.handleCloseControls(true, false); @@ -578,7 +578,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */ , - true, false /* isNonblockable */, false, /* isNoisy */IMPORTANCE_DEFAULT); + true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -598,8 +599,9 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */ , - true, false /* isNonblockable */, false, /* isNoisy */IMPORTANCE_DEFAULT); + null /* onSettingsClick */, null /* onAppSettingsClick */, + true, false /* isNonblockable */, false /* isNoisy */, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -620,7 +622,8 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -648,7 +651,8 @@ public class NotificationInfoTest extends SysuiTestCase { 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -676,8 +680,8 @@ public class NotificationInfoTest extends SysuiTestCase { 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */ , false /* isNonblockable */, true /* isForBlockingHelper */, - true, true /* isUserSentimentNegative */, false, /* isNoisy */ - IMPORTANCE_DEFAULT); + true, true /* isUserSentimentNegative */, false /* isNoisy */, + IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.handleCloseControls(true /* save */, false /* force */); @@ -696,7 +700,8 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, false, /* isNoisy */IMPORTANCE_DEFAULT); + true /* isUserSentimentNegative */, false /* isNoisy */, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -719,7 +724,7 @@ public class NotificationInfoTest extends SysuiTestCase { true /* isForBlockingHelper */, true, false /* isUserSentimentNegative */, - false, /* isNoisy */IMPORTANCE_DEFAULT); + false /* isNoisy */, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); NotificationGuts guts = mock(NotificationGuts.class); doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean()); mNotificationInfo.setGutsParent(guts); @@ -734,7 +739,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -748,7 +753,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -781,7 +786,7 @@ public class NotificationInfoTest extends SysuiTestCase { false /* isNonblockable */, true /* isForBlockingHelper */, true /* isUserSentimentNegative */, - false, /* isNoisy */IMPORTANCE_DEFAULT); + false/* isNoisy */, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -803,7 +808,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -818,7 +823,7 @@ public class NotificationInfoTest extends SysuiTestCase { mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -839,7 +844,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.handleCloseControls(true, false); @@ -857,7 +862,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -879,7 +884,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -901,7 +906,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -922,7 +927,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -944,7 +949,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -966,7 +971,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_UNSPECIFIED); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - false, IMPORTANCE_LOW); + false, IMPORTANCE_LOW, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -987,7 +992,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1003,7 +1008,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1020,7 +1025,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { - }, null, null, true, true, false, IMPORTANCE_DEFAULT); + }, null, null, true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -1038,7 +1043,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, false, IMPORTANCE_DEFAULT); + }, null, null, true, false, false, IMPORTANCE_DEFAULT, + NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); mTestableLooper.processAllMessages(); @@ -1074,7 +1080,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, (View v, Intent intent) -> { latch.countDown(); - }, true, false, false, IMPORTANCE_DEFAULT); + }, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(View.VISIBLE, settingsLink.getVisibility()); settingsLink.performClick(); @@ -1102,7 +1108,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null, (View v, Intent intent) -> { latch.countDown(); - }, true, false, false, IMPORTANCE_DEFAULT); + }, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(View.VISIBLE, settingsLink.getVisibility()); settingsLink.performClick(); @@ -1121,7 +1127,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, sbn, null, null, - null, true, false, false, IMPORTANCE_DEFAULT); + null, true, false, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1142,7 +1148,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, true, false, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1165,7 +1171,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, sbn, null, null, null, false, true, - true, true, false, IMPORTANCE_DEFAULT); + true, true, false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); assertEquals(GONE, settingsLink.getVisibility()); } @@ -1182,7 +1188,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); @@ -1195,7 +1201,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1208,7 +1214,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1222,7 +1228,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, IMPORTANCE_DEFAULT); + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.toggle_silent).performClick(); waitForUndoButton(); @@ -1236,7 +1242,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1248,7 +1254,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - false, IMPORTANCE_DEFAULT); + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE); mNotificationInfo.findViewById(R.id.block).performClick(); waitForUndoButton(); @@ -1256,4 +1262,60 @@ public class NotificationInfoTest extends SysuiTestCase { waitForStopButton(); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); } + + @Test + public void testBindNotificationWithInitialBlockAction() throws Exception { + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_BLOCK); + waitForUndoButton(); + mNotificationInfo.handleCloseControls(true, false); + + mTestableLooper.processAllMessages(); + ArgumentCaptor<NotificationChannel> updated = + ArgumentCaptor.forClass(NotificationChannel.class); + verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( + anyString(), eq(TEST_UID), updated.capture()); + assertTrue((updated.getValue().getUserLockedFields() + & USER_LOCKED_IMPORTANCE) != 0); + assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance()); + } + + @Test + public void testBindNotificationWithInitialSilenceAction() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + true, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_TOGGLE_SILENT); + waitForUndoButton(); + mNotificationInfo.handleCloseControls(true, false); + + mTestableLooper.processAllMessages(); + ArgumentCaptor<NotificationChannel> updated = + ArgumentCaptor.forClass(NotificationChannel.class); + verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( + anyString(), eq(TEST_UID), updated.capture()); + assertTrue((updated.getValue().getUserLockedFields() + & USER_LOCKED_IMPORTANCE) != 0); + assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); + } + + @Test + public void testBindNotificationWithInitialUnSilenceAction() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_LOW); + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + true, IMPORTANCE_LOW, NotificationInfo.ACTION_TOGGLE_SILENT); + waitForUndoButton(); + mNotificationInfo.handleCloseControls(true, false); + + mTestableLooper.processAllMessages(); + ArgumentCaptor<NotificationChannel> updated = + ArgumentCaptor.forClass(NotificationChannel.class); + verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( + anyString(), eq(TEST_UID), updated.capture()); + assertTrue((updated.getValue().getUserLockedFields() + & USER_LOCKED_IMPORTANCE) != 0); + assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance()); + } } diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 8ae587296d45..3e07d12b9a99 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -844,6 +844,8 @@ message MetricsEvent { // PACKAGE: App that posted the notification // DETAIL: Notification is expanded by user. // PACKAGE: App that posted the notification + // COLLAPSE: Notification is collapsed by user. + // PACKAGE: App that posted the notification // DISMISS: Notification is dismissed. // PACKAGE: App that posted the notification // SUBTYPE: Dismiss reason from NotificationManagerService.java @@ -6596,6 +6598,12 @@ message MetricsEvent { // OS: Q NOTIFICATION_ZEN_MODE_OVERRIDING_APP = 1589; + // ACTION: User sent a direct reply + // PACKAGE: App that posted the notification + // CATEGORY: NOTIFICATION + // OS: Q + NOTIFICATION_DIRECT_REPLY_ACTION = 1590; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 4205ac7d9f86..31238df6ea10 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -166,12 +166,12 @@ public final class AutofillManagerService context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler()); } - @Override // from MasterSystemService + @Override // from AbstractMasterSystemService protected String getServiceSettingsProperty() { return Settings.Secure.AUTOFILL_SERVICE; } - @Override // from MasterSystemService + @Override // from AbstractMasterSystemService protected void registerForExtraSettingsChanges(@NonNull ContentResolver resolver, @NonNull ContentObserver observer) { resolver.registerContentObserver(Settings.Global.getUriFor( @@ -188,7 +188,7 @@ public final class AutofillManagerService UserHandle.USER_ALL); } - @Override // from MasterSystemService + @Override // from AbstractMasterSystemService protected void onSettingsChanged(int userId, @NonNull String property) { switch (property) { case Settings.Global.AUTOFILL_LOGGING_LEVEL: @@ -210,25 +210,24 @@ public final class AutofillManagerService } } - @Override // from MasterSystemService - protected AutofillManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) { + @Override // from AbstractMasterSystemService + protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId, + boolean disabled) { return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory, mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled); } - @Override // MasterSystemService - protected AutofillManagerServiceImpl removeCachedServiceLocked(int userId) { - final AutofillManagerServiceImpl service = super.removeCachedServiceLocked(userId); - if (service != null) { - service.destroyLocked(); - mAutofillCompatState.removeCompatibilityModeRequests(userId); - } - return service; + @Override // AbstractMasterSystemService + protected void onServiceRemoved(@NonNull AutofillManagerServiceImpl service, + @UserIdInt int userId) { + service.destroyLocked(); + mAutofillCompatState.removeCompatibilityModeRequests(userId); } - @Override // from MasterSystemService - protected void onServiceEnabledLocked(@NonNull AutofillManagerServiceImpl service, int userId) { + @Override // from AbstractMasterSystemService + protected void onServiceEnabledLocked(@NonNull AutofillManagerServiceImpl service, + @UserIdInt int userId) { addCompatibilityModeRequestsLocked(service, userId); } @@ -245,7 +244,7 @@ public final class AutofillManagerService } // Called by Shell command. - void destroySessions(int userId, IResultReceiver receiver) { + void destroySessions(@UserIdInt int userId, IResultReceiver receiver) { Slog.i(TAG, "destroySessions() for userId " + userId); getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG); diff --git a/services/core/Android.bp b/services/core/Android.bp index 888ad1da3fcc..617430090998 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -3,6 +3,7 @@ java_library_static { aidl: { include_dirs: [ + "frameworks/base/cmds/idmap2/idmap2d/aidl", "frameworks/native/aidl/binder", "frameworks/native/cmds/dumpstate/binder", "system/core/storaged/binder", @@ -13,6 +14,7 @@ java_library_static { srcs: [ "java/**/*.java", ":dumpstate_aidl", + ":idmap2_aidl", ":netd_aidl", ":netd_metrics_aidl", ":installd_aidl", diff --git a/services/core/java/com/android/server/AbstractMasterSystemService.java b/services/core/java/com/android/server/AbstractMasterSystemService.java index c955daf2fae4..6cae887d3ffc 100644 --- a/services/core/java/com/android/server/AbstractMasterSystemService.java +++ b/services/core/java/com/android/server/AbstractMasterSystemService.java @@ -244,7 +244,7 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste */ @GuardedBy("mLock") @Nullable - protected S peekServiceForUserLocked(int userId) { + protected S peekServiceForUserLocked(@UserIdInt int userId) { final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, null, null); return mServicesCache.get(resolvedUserId); @@ -254,7 +254,7 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste * Updates a cached service for a given user. */ @GuardedBy("mLock") - protected void updateCachedServiceLocked(int userId) { + protected void updateCachedServiceLocked(@UserIdInt int userId) { updateCachedServiceLocked(userId, isDisabledLocked(userId)); } @@ -262,7 +262,7 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste * Checks whether the service is disabled (through {@link UserManager} restrictions) for the * given user. */ - protected boolean isDisabledLocked(int userId) { + protected boolean isDisabledLocked(@UserIdInt int userId) { return mDisabledUsers == null ? false : mDisabledUsers.get(userId); } @@ -274,7 +274,7 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste * @return service for the user. */ @GuardedBy("mLock") - protected S updateCachedServiceLocked(int userId, boolean disabled) { + protected S updateCachedServiceLocked(@UserIdInt int userId, boolean disabled) { final S service = getServiceForUserLocked(userId); if (service != null) { service.updateLocked(disabled); @@ -304,7 +304,7 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste * <p>By default doesn't do anything, but can be overridden by subclasses. */ @SuppressWarnings("unused") - protected void onServiceEnabledLocked(S service, @UserIdInt int userId) { + protected void onServiceEnabledLocked(@NonNull S service, @UserIdInt int userId) { } /** @@ -314,15 +314,23 @@ public abstract class AbstractMasterSystemService<S extends AbstractPerUserSyste */ @GuardedBy("mLock") @NonNull - protected S removeCachedServiceLocked(@UserIdInt int userId) { + private S removeCachedServiceLocked(@UserIdInt int userId) { final S service = peekServiceForUserLocked(userId); if (service != null) { mServicesCache.delete(userId); + onServiceRemoved(service, userId); } return service; } /** + * Called after the service is removed from the cache. + */ + @SuppressWarnings("unused") + protected void onServiceRemoved(@NonNull S service, @UserIdInt int userId) { + } + + /** * Visits all services in the cache. */ @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 5814064e5fbd..fa98da541e57 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -80,6 +80,7 @@ import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsActiveCallback; import com.android.internal.app.IAppOpsCallback; @@ -219,6 +220,7 @@ public class AppOpsService extends IAppOpsService.Stub { SparseIntArray mProfileOwners; + @GuardedBy("this") private CheckOpsDelegate mCheckOpsDelegate; /** @@ -1589,24 +1591,28 @@ public class AppOpsService extends IAppOpsService.Stub { public int checkOperation(int code, int uid, String packageName) { final CheckOpsDelegate delegate; synchronized (this) { - if (mCheckOpsDelegate == null) { - return checkOperationImpl(code, uid, packageName); - } delegate = mCheckOpsDelegate; } + if (delegate == null) { + return checkOperationImpl(code, uid, packageName); + } return delegate.checkOperation(code, uid, packageName, AppOpsService.this::checkOperationImpl); } private int checkOperationImpl(int code, int uid, String packageName) { + verifyIncomingUid(uid); + verifyIncomingOp(code); + String resolvedPackageName = resolvePackageName(uid, packageName); + if (resolvedPackageName == null) { + return AppOpsManager.MODE_IGNORED; + } + return checkOperationUnchecked(code, uid, resolvedPackageName); + } + + private int checkOperationUnchecked(int code, int uid, String packageName) { synchronized (this) { - verifyIncomingUid(uid); - verifyIncomingOp(code); - String resolvedPackageName = resolvePackageName(uid, packageName); - if (resolvedPackageName == null) { - return AppOpsManager.MODE_IGNORED; - } - if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, packageName)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1615,7 +1621,7 @@ public class AppOpsService extends IAppOpsService.Stub { && uidState.opModes.indexOfKey(code) >= 0) { return uidState.opModes.get(code); } - Op op = getOpLocked(code, uid, resolvedPackageName, false, true, false); + Op op = getOpLocked(code, uid, packageName, false, true, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -1627,31 +1633,31 @@ public class AppOpsService extends IAppOpsService.Stub { public int checkAudioOperation(int code, int usage, int uid, String packageName) { final CheckOpsDelegate delegate; synchronized (this) { - if (mCheckOpsDelegate == null) { - return checkAudioOperationImpl(code, usage, uid, packageName); - } delegate = mCheckOpsDelegate; } + if (delegate == null) { + return checkAudioOperationImpl(code, usage, uid, packageName); + } return delegate.checkAudioOperation(code, usage, uid, packageName, AppOpsService.this::checkAudioOperationImpl); } private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) { - synchronized (this) { - boolean suspended; - try { - suspended = isPackageSuspendedForUser(packageName, uid); - } catch (IllegalArgumentException ex) { - // Package not found. - suspended = false; - } + boolean suspended; + try { + suspended = isPackageSuspendedForUser(packageName, uid); + } catch (IllegalArgumentException ex) { + // Package not found. + suspended = false; + } - if (suspended) { - Slog.i(TAG, "Audio disabled for suspended package=" + packageName - + " for uid=" + uid); - return AppOpsManager.MODE_IGNORED; - } + if (suspended) { + Slog.i(TAG, "Audio disabled for suspended package=" + packageName + + " for uid=" + uid); + return AppOpsManager.MODE_IGNORED; + } + synchronized (this) { final int mode = checkRestrictionLocked(code, usage, uid, packageName); if (mode != AppOpsManager.MODE_ALLOWED) { return mode; @@ -1754,11 +1760,11 @@ public class AppOpsService extends IAppOpsService.Stub { public int noteOperation(int code, int uid, String packageName) { final CheckOpsDelegate delegate; synchronized (this) { - if (mCheckOpsDelegate == null) { - return noteOperationImpl(code, uid, packageName); - } delegate = mCheckOpsDelegate; } + if (delegate == null) { + return noteOperationImpl(code, uid, packageName); + } return delegate.noteOperation(code, uid, packageName, AppOpsService.this::noteOperationImpl); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 771d3765d902..aa960828b15c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4820,6 +4820,10 @@ public class ActivityManagerService extends IActivityManager.Stub String packageName, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bOptions, int userId) { + + // NOTE: The service lock isn't held in this method because nothing in the method requires + // the service lock to be held. + enforceNotIsolatedCaller("getIntentSender"); // Refuse possible leaked file descriptors if (intents != null) { @@ -4851,43 +4855,41 @@ public class ActivityManagerService extends IActivityManager.Stub } } - synchronized(this) { - int callingUid = Binder.getCallingUid(); - int origUserId = userId; - userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, - type == ActivityManager.INTENT_SENDER_BROADCAST, - ALLOW_NON_FULL, "getIntentSender", null); - if (origUserId == UserHandle.USER_CURRENT) { - // We don't want to evaluate this until the pending intent is - // actually executed. However, we do want to always do the - // security checking for it above. - userId = UserHandle.USER_CURRENT; - } - try { - if (callingUid != 0 && callingUid != SYSTEM_UID) { - final int uid = AppGlobals.getPackageManager().getPackageUid(packageName, - MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); - if (!UserHandle.isSameApp(callingUid, uid)) { - String msg = "Permission Denial: getIntentSender() from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid() - + ", (need uid=" + uid + ")" - + " is not allowed to send as package " + packageName; - Slog.w(TAG, msg); - throw new SecurityException(msg); - } + int callingUid = Binder.getCallingUid(); + int origUserId = userId; + userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, + type == ActivityManager.INTENT_SENDER_BROADCAST, + ALLOW_NON_FULL, "getIntentSender", null); + if (origUserId == UserHandle.USER_CURRENT) { + // We don't want to evaluate this until the pending intent is + // actually executed. However, we do want to always do the + // security checking for it above. + userId = UserHandle.USER_CURRENT; + } + try { + if (callingUid != 0 && callingUid != SYSTEM_UID) { + final int uid = AppGlobals.getPackageManager().getPackageUid(packageName, + MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid)); + if (!UserHandle.isSameApp(callingUid, uid)) { + String msg = "Permission Denial: getIntentSender() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + ", (need uid=" + uid + ")" + + " is not allowed to send as package " + packageName; + Slog.w(TAG, msg); + throw new SecurityException(msg); } + } - if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { - return mAtmInternal.getIntentSender(type, packageName, callingUid, userId, - token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); - } - return mPendingIntentController.getIntentSender(type, packageName, callingUid, - userId, token, resultWho, requestCode, intents, resolvedTypes, flags, - bOptions); - } catch (RemoteException e) { - throw new SecurityException(e); + if (type == ActivityManager.INTENT_SENDER_ACTIVITY_RESULT) { + return mAtmInternal.getIntentSender(type, packageName, callingUid, userId, + token, resultWho, requestCode, intents, resolvedTypes, flags, bOptions); } + return mPendingIntentController.getIntentSender(type, packageName, callingUid, + userId, token, resultWho, requestCode, intents, resolvedTypes, flags, + bOptions); + } catch (RemoteException e) { + throw new SecurityException(e); } } @@ -7002,7 +7004,7 @@ public class ActivityManagerService extends IActivityManager.Stub mCoreSettingsObserver = new CoreSettingsObserver(this); mActivityTaskManager.installSystemProviders(); mDevelopmentSettingsObserver = new DevelopmentSettingsObserver(); - GlobalSettingsToPropertiesMapper.start(mContext.getContentResolver()); + SettingsToPropertiesMapper.start(mContext.getContentResolver()); // Now that the settings provider is published we can consider sending // in a rescue party. diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java deleted file mode 100644 index 1366c218299e..000000000000 --- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.server.am; - -import android.content.ContentResolver; -import android.database.ContentObserver; -import android.net.Uri; -import android.os.Build; -import android.os.SystemProperties; -import android.provider.Settings; -import android.text.TextUtils; -import android.util.Slog; -import android.view.ThreadedRenderer; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; - -/** - * Maps global system settings to system properties. - * <p>The properties are dynamically updated when settings change. - */ -class GlobalSettingsToPropertiesMapper { - - private static final String TAG = "GlobalSettingsToPropertiesMapper"; - - // List mapping entries in the following format: - // {Settings.Global.SETTING_NAME, "system_property_name"} - // Important: Property being added should be whitelisted by SELinux policy or have one of the - // already whitelisted prefixes in system_server.te, e.g. sys. - private static final String[][] sGlobalSettingsMapping = new String[][] { - {Settings.Global.SYS_VDSO, "sys.vdso"}, - {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR}, - {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"}, - {Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"}, - {Settings.Global.SYS_TRACED, "sys.traced.enable_override"}, - }; - - - private final ContentResolver mContentResolver; - private final String[][] mGlobalSettingsMapping; - - @VisibleForTesting - GlobalSettingsToPropertiesMapper(ContentResolver contentResolver, - String[][] globalSettingsMapping) { - mContentResolver = contentResolver; - mGlobalSettingsMapping = globalSettingsMapping; - } - - void updatePropertiesFromGlobalSettings() { - for (String[] entry : mGlobalSettingsMapping) { - final String settingName = entry[0]; - final String propName = entry[1]; - Uri settingUri = Settings.Global.getUriFor(settingName); - Preconditions.checkNotNull(settingUri, "Setting " + settingName + " not found"); - ContentObserver co = new ContentObserver(null) { - @Override - public void onChange(boolean selfChange) { - updatePropertyFromSetting(settingName, propName); - } - }; - updatePropertyFromSetting(settingName, propName); - mContentResolver.registerContentObserver(settingUri, false, co); - } - } - - public static void start(ContentResolver contentResolver) { - new GlobalSettingsToPropertiesMapper(contentResolver, sGlobalSettingsMapping) - .updatePropertiesFromGlobalSettings(); - } - - private String getGlobalSetting(String name) { - return Settings.Global.getString(mContentResolver, name); - } - - private void setProperty(String key, String value) { - // Check if need to clear the property - if (value == null) { - // It's impossible to remove system property, therefore we check previous value to - // avoid setting an empty string if the property wasn't set. - if (TextUtils.isEmpty(systemPropertiesGet(key))) { - return; - } - value = ""; - } - try { - systemPropertiesSet(key, value); - } catch (Exception e) { - // Failure to set a property can be caused by SELinux denial. This usually indicates - // that the property wasn't whitelisted in sepolicy. - // No need to report it on all user devices, only on debug builds. - if (Build.IS_DEBUGGABLE) { - Slog.wtf(TAG, "Unable to set property " + key + " value '" + value + "'", e); - } else { - Slog.e(TAG, "Unable to set property " + key + " value '" + value + "'", e); - } - } - } - - @VisibleForTesting - protected String systemPropertiesGet(String key) { - return SystemProperties.get(key); - } - - @VisibleForTesting - protected void systemPropertiesSet(String key, String value) { - SystemProperties.set(key, value); - } - - @VisibleForTesting - void updatePropertyFromSetting(String settingName, String propName) { - String settingValue = getGlobalSetting(settingName); - setProperty(propName, settingValue); - } -} diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 79c98e550774..5208ca5eb0db 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -27,4 +27,4 @@ toddke@google.com michaelwr@google.com narayan@google.com -per-file GlobalSettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com +per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java new file mode 100644 index 000000000000..a5848ca0235a --- /dev/null +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -0,0 +1,265 @@ +/* + * 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.am; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.net.Uri; +import android.os.Build; +import android.os.SystemProperties; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashSet; + +/** + * Maps system settings to system properties. + * <p>The properties are dynamically updated when settings change. + */ +class SettingsToPropertiesMapper { + + private static final String TAG = "SettingsToPropertiesMapper"; + + private static final String SYSTEM_PROPERTY_PREFIX = "persist.device_config."; + + private static final String RESET_PERFORMED_PROPERTY = "device_config.reset_performed"; + + private static final String RESET_RECORD_FILE_PATH = + "/data/server_configurable_flags/reset_flags"; + + private static final String SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX = "^[\\w\\.\\-@:]*$"; + + private static final String SYSTEM_PROPERTY_INVALID_SUBSTRING = ".."; + + private static final int SYSTEM_PROPERTY_MAX_LENGTH = 92; + + // experiment flags added to Global.Settings(before new "Config" provider table is available) + // will be added under this category. + private static final String GLOBAL_SETTINGS_CATEGORY = "global_settings"; + + // Add the global setting you want to push to native level as experiment flag into this list. + // + // NOTE: please grant write permission system property prefix + // with format persist.experiment.[experiment_category_name]. in system_server.te and grant read + // permission in the corresponding .te file your feature belongs to. + @VisibleForTesting + static final String[] sGlobalSettings = new String[] { + }; + + @VisibleForTesting + static final String[] sDeviceConfigScopes = new String[] { + }; + + private final String[] mGlobalSettings; + + private final String[] mDeviceConfigScopes; + + private final ContentResolver mContentResolver; + + @VisibleForTesting + protected SettingsToPropertiesMapper(ContentResolver contentResolver, + String[] globalSettings, + String[] deviceConfigScopes) { + mContentResolver = contentResolver; + mGlobalSettings = globalSettings; + mDeviceConfigScopes = deviceConfigScopes; + } + + @VisibleForTesting + void updatePropertiesFromSettings() { + for (String globalSetting : mGlobalSettings) { + Uri settingUri = Settings.Global.getUriFor(globalSetting); + String propName = makePropertyName(GLOBAL_SETTINGS_CATEGORY, globalSetting); + if (settingUri == null) { + log("setting uri is null for globalSetting " + globalSetting); + continue; + } + if (propName == null) { + log("invalid prop name for globalSetting " + globalSetting); + continue; + } + + ContentObserver co = new ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { + updatePropertyFromSetting(globalSetting, propName, true); + } + }; + + // only updating on starting up when no native flags reset is performed during current + // booting. + if (!isNativeFlagsResetPerformed()) { + updatePropertyFromSetting(globalSetting, propName, true); + } + mContentResolver.registerContentObserver(settingUri, false, co); + } + + // TODO: address sDeviceConfigScopes after DeviceConfig APIs are available. + } + + public static SettingsToPropertiesMapper start(ContentResolver contentResolver) { + SettingsToPropertiesMapper mapper = new SettingsToPropertiesMapper( + contentResolver, sGlobalSettings, sDeviceConfigScopes); + mapper.updatePropertiesFromSettings(); + return mapper; + } + + /** + * If native level flags reset has been performed as an attempt to recover from a crash loop + * during current device booting. + * @return + */ + public boolean isNativeFlagsResetPerformed() { + String value = systemPropertiesGet(RESET_PERFORMED_PROPERTY); + return "true".equals(value); + } + + /** + * return an array of native flag categories under which flags got reset during current device + * booting. + * @return + */ + public String[] getResetNativeCategories() { + if (!isNativeFlagsResetPerformed()) { + return new String[0]; + } + + String content = getResetFlagsFileContent(); + if (TextUtils.isEmpty(content)) { + return new String[0]; + } + + String[] property_names = content.split(";"); + HashSet<String> categories = new HashSet<>(); + for (String property_name : property_names) { + String[] segments = property_name.split("\\."); + if (segments.length < 3) { + log("failed to extract category name from property " + property_name); + continue; + } + categories.add(segments[2]); + } + return categories.toArray(new String[0]); + } + + /** + * system property name constructing rule: "persist.device_config.[category_name].[flag_name]". + * If the name contains invalid characters or substrings for system property name, + * will return null. + * @param categoryName + * @param flagName + * @return + */ + @VisibleForTesting + static String makePropertyName(String categoryName, String flagName) { + String propertyName = SYSTEM_PROPERTY_PREFIX + categoryName + "." + flagName; + + if (!propertyName.matches(SYSTEM_PROPERTY_VALID_CHARACTERS_REGEX) + || propertyName.contains(SYSTEM_PROPERTY_INVALID_SUBSTRING)) { + return null; + } + + return propertyName; + } + + private String getSetting(String name, boolean isGlobalSetting) { + if (isGlobalSetting) { + return Settings.Global.getString(mContentResolver, name); + } else { + // TODO: complete the code after DeviceConfig APIs implemented. + return null; + } + } + + private void setProperty(String key, String value) { + // Check if need to clear the property + if (value == null) { + // It's impossible to remove system property, therefore we check previous value to + // avoid setting an empty string if the property wasn't set. + if (TextUtils.isEmpty(systemPropertiesGet(key))) { + return; + } + value = ""; + } else if (value.length() > SYSTEM_PROPERTY_MAX_LENGTH) { + log(value + " exceeds system property max length."); + return; + } + + try { + systemPropertiesSet(key, value); + } catch (Exception e) { + // Failure to set a property can be caused by SELinux denial. This usually indicates + // that the property wasn't whitelisted in sepolicy. + // No need to report it on all user devices, only on debug builds. + log("Unable to set property " + key + " value '" + value + "'", e); + } + } + + private static void log(String msg, Exception e) { + if (Build.IS_DEBUGGABLE) { + Slog.wtf(TAG, msg, e); + } else { + Slog.e(TAG, msg, e); + } + } + + private static void log(String msg) { + if (Build.IS_DEBUGGABLE) { + Slog.wtf(TAG, msg); + } else { + Slog.e(TAG, msg); + } + } + + @VisibleForTesting + protected String systemPropertiesGet(String key) { + return SystemProperties.get(key); + } + + @VisibleForTesting + protected void systemPropertiesSet(String key, String value) { + SystemProperties.set(key, value); + } + + @VisibleForTesting + protected String getResetFlagsFileContent() { + String content = null; + try { + File reset_flag_file = new File(RESET_RECORD_FILE_PATH); + BufferedReader br = new BufferedReader(new FileReader(reset_flag_file)); + content = br.readLine(); + + br.close(); + } catch (IOException ioe) { + log("failed to read file " + RESET_RECORD_FILE_PATH, ioe); + } + return content; + } + + @VisibleForTesting + void updatePropertyFromSetting(String settingName, String propName, boolean isGlobalSetting) { + String settingValue = getSetting(settingName, isGlobalSetting); + setProperty(propName, settingValue); + } +} diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index c20079e8a685..3a31c9c5e05f 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -72,6 +72,8 @@ import android.view.IInputFilter; import android.view.IInputFilterHost; import android.view.IWindow; import android.view.InputChannel; +import android.view.InputApplicationHandle; +import android.view.InputWindowHandle; import android.view.InputDevice; import android.view.InputEvent; import android.view.KeyEvent; @@ -197,7 +199,7 @@ public class InputManagerService extends IInputManager.Stub private static native boolean nativeHasKeys(long ptr, int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists); private static native void nativeRegisterInputChannel(long ptr, InputChannel inputChannel, - InputWindowHandle inputWindowHandle, int displayId); + int displayId); private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel); private static native void nativeSetInputFilterEnabled(long ptr, boolean enable); private static native int nativeInjectInputEvent(long ptr, InputEvent event, @@ -486,8 +488,7 @@ public class InputManagerService extends IInputManager.Stub } InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName); - // Register channel for monitor. - nativeRegisterInputChannel(mPtr, inputChannels[0], null, displayId); + nativeRegisterInputChannel(mPtr, inputChannels[0], displayId); inputChannels[0].dispose(); // don't need to retain the Java object reference return inputChannels[1]; } @@ -498,14 +499,17 @@ public class InputManagerService extends IInputManager.Stub * @param inputWindowHandle The handle of the input window associated with the * input channel, or null if none. */ - public void registerInputChannel(InputChannel inputChannel, - InputWindowHandle inputWindowHandle) { + public void registerInputChannel(InputChannel inputChannel, IBinder token) { if (inputChannel == null) { throw new IllegalArgumentException("inputChannel must not be null."); } - // Register channel for normal. - nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, Display.INVALID_DISPLAY); + if (token == null) { + token = new Binder(); + } + inputChannel.setToken(token); + + nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY); } /** @@ -1791,15 +1795,15 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { - mWindowManagerCallbacks.notifyInputChannelBroken(inputWindowHandle); + private void notifyInputChannelBroken(IBinder token) { + mWindowManagerCallbacks.notifyInputChannelBroken(token); } // Native callback. private long notifyANR(InputApplicationHandle inputApplicationHandle, - InputWindowHandle inputWindowHandle, String reason) { + IBinder token, String reason) { return mWindowManagerCallbacks.notifyANR( - inputApplicationHandle, inputWindowHandle, reason); + inputApplicationHandle, token, reason); } // Native callback. @@ -1830,13 +1834,13 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private long interceptKeyBeforeDispatching(InputWindowHandle focus, + private long interceptKeyBeforeDispatching(IBinder focus, KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags); } // Native callback. - private KeyEvent dispatchUnhandledKey(InputWindowHandle focus, + private KeyEvent dispatchUnhandledKey(IBinder focus, KeyEvent event, int policyFlags) { return mWindowManagerCallbacks.dispatchUnhandledKey(focus, event, policyFlags); } @@ -1987,19 +1991,19 @@ public class InputManagerService extends IInputManager.Stub public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered); - public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle); + public void notifyInputChannelBroken(IBinder token); public long notifyANR(InputApplicationHandle inputApplicationHandle, - InputWindowHandle inputWindowHandle, String reason); + IBinder token, String reason); public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags); public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags); - public long interceptKeyBeforeDispatching(InputWindowHandle focus, + public long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags); - public KeyEvent dispatchUnhandledKey(InputWindowHandle focus, + public KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags); public int getPointerLayer(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1c7572ee4e2c..cfbe83d67e21 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -885,6 +885,9 @@ public class NotificationManagerService extends SystemService { NotificationRecord r = mNotificationsByKey.get(key); if (r != null) { r.recordDirectReplied(); + mMetricsLogger.write(r.getLogMaker() + .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION) + .setType(MetricsEvent.TYPE_ACTION)); reportUserInteraction(r); } } @@ -1160,6 +1163,7 @@ public class NotificationManagerService extends SystemService { mConditionProviders.onUserSwitched(userId); mListeners.onUserSwitched(userId); mZenModeHelper.onUserSwitched(userId); + mPreferencesHelper.onUserSwitched(userId); } // assistant is the only thing that cares about managed profiles specifically mAssistants.onUserSwitched(userId); @@ -1188,6 +1192,7 @@ public class NotificationManagerService extends SystemService { mConditionProviders.onUserUnlocked(userId); mListeners.onUserUnlocked(userId); mZenModeHelper.onUserUnlocked(userId); + mPreferencesHelper.onUserUnlocked(userId); } } } @@ -2525,6 +2530,19 @@ public class NotificationManagerService extends SystemService { } @Override + public int getAppsBypassingDndCount(int userId) { + checkCallerIsSystem(); + return mPreferencesHelper.getAppsBypassingDndCount(userId); + } + + @Override + public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd( + String pkg, int userId) { + checkCallerIsSystem(); + return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId); + } + + @Override public boolean areChannelsBypassingDnd() { return mPreferencesHelper.areChannelsBypassingDnd(); } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 8fce5e3acdc2..fd65ebe102ac 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -111,7 +111,6 @@ public class PreferencesHelper implements RankingConfig { // pkg => PackagePreferences private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>(); - private final Context mContext; private final PackageManager mPm; private final RankingHandler mRankingHandler; @@ -120,7 +119,6 @@ public class PreferencesHelper implements RankingConfig { private SparseBooleanArray mBadgingEnabled; private boolean mAreChannelsBypassingDnd; - public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper) { mContext = context; @@ -129,11 +127,7 @@ public class PreferencesHelper implements RankingConfig { mPm = pm; updateBadgingEnabled(); - - mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state & - NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; - updateChannelsBypassingDnd(); - + syncChannelsBypassingDnd(mContext.getUserId()); } public void readXml(XmlPullParser parser, boolean forRestore) @@ -525,6 +519,7 @@ public class PreferencesHelper implements RankingConfig { // but the system can if (group.isBlocked() != oldGroup.isBlocked()) { group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); + updateChannelsBypassingDnd(mContext.getUserId()); } if (group.canOverlayApps() != oldGroup.canOverlayApps()) { group.lockFields(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY); @@ -571,6 +566,7 @@ public class PreferencesHelper implements RankingConfig { // Apps are allowed to downgrade channel importance if the user has not changed any // fields on this channel yet. + final int previousExistingImportance = existing.getImportance(); if (existing.getUserLockedFields() == 0 && channel.getImportance() < existing.getImportance()) { existing.setImportance(channel.getImportance()); @@ -582,8 +578,9 @@ public class PreferencesHelper implements RankingConfig { boolean bypassDnd = channel.canBypassDnd(); existing.setBypassDnd(bypassDnd); - if (bypassDnd != mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(); + if (bypassDnd != mAreChannelsBypassingDnd + || previousExistingImportance != existing.getImportance()) { + updateChannelsBypassingDnd(mContext.getUserId()); } } @@ -613,7 +610,7 @@ public class PreferencesHelper implements RankingConfig { r.channels.put(channel.getId(), channel); if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(mContext.getUserId()); } MetricsLogger.action(getChannelLog(channel, pkg).setType( com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); @@ -663,8 +660,9 @@ public class PreferencesHelper implements RankingConfig { MetricsLogger.action(getChannelLog(updatedChannel, pkg)); } - if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(); + if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd + || channel.getImportance() != updatedChannel.getImportance()) { + updateChannelsBypassingDnd(mContext.getUserId()); } updateConfig(); } @@ -701,7 +699,7 @@ public class PreferencesHelper implements RankingConfig { MetricsLogger.action(lm); if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { - updateChannelsBypassingDnd(); + updateChannelsBypassingDnd(mContext.getUserId()); } } } @@ -859,6 +857,27 @@ public class PreferencesHelper implements RankingConfig { } /** + * Gets all notification channels associated with the given pkg and userId that can bypass dnd + */ + public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(String pkg, + int userId) { + List<NotificationChannel> channels = new ArrayList<>(); + synchronized (mPackagePreferences) { + final PackagePreferences r = mPackagePreferences.get( + packagePreferencesKey(pkg, userId)); + // notifications from this package aren't blocked + if (r != null && r.importance != IMPORTANCE_NONE) { + for (NotificationChannel channel : r.channels.values()) { + if (channelIsLive(r, channel) && channel.canBypassDnd()) { + channels.add(channel); + } + } + } + } + return new ParceledListSlice<>(channels); + } + + /** * True for pre-O apps that only have the default channel, or pre O apps that have no * channels yet. This method will create the default channel for pre-O apps that don't have it. * Should never be true for O+ targeting apps, but that's enforced on boot/when an app @@ -922,18 +941,62 @@ public class PreferencesHelper implements RankingConfig { return count; } - public void updateChannelsBypassingDnd() { + /** + * Returns the number of apps that have at least one notification channel that can bypass DND + * for given particular user + */ + public int getAppsBypassingDndCount(int userId) { + int count = 0; + synchronized (mPackagePreferences) { + final int numPackagePreferences = mPackagePreferences.size(); + for (int i = 0; i < numPackagePreferences; i++) { + final PackagePreferences r = mPackagePreferences.valueAt(i); + // Package isn't associated with this userId or notifications from this package are + // blocked + if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { + continue; + } + + for (NotificationChannel channel : r.channels.values()) { + if (channelIsLive(r, channel) && channel.canBypassDnd()) { + count++; + break; + } + } + } + } + return count; + } + + /** + * Syncs {@link #mAreChannelsBypassingDnd} with the user's notification policy before + * updating + * @param userId + */ + private void syncChannelsBypassingDnd(int userId) { + mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state + & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; + updateChannelsBypassingDnd(userId); + } + + /** + * Updates the user's NotificationPolicy based on whether the given userId + * has channels bypassing DND + * @param userId + */ + private void updateChannelsBypassingDnd(int userId) { synchronized (mPackagePreferences) { - final int numPackagePreferencess = mPackagePreferences.size(); - for (int PackagePreferencesIndex = 0; PackagePreferencesIndex < numPackagePreferencess; - PackagePreferencesIndex++) { - final PackagePreferences r = mPackagePreferences.valueAt(PackagePreferencesIndex); - final int numChannels = r.channels.size(); - - for (int channelIndex = 0; channelIndex < numChannels; channelIndex++) { - NotificationChannel channel = r.channels.valueAt(channelIndex); - if (!channel.isDeleted() && channel.canBypassDnd()) { - // If any channel bypasses DND, synchronize state and return early. + final int numPackagePreferences = mPackagePreferences.size(); + for (int i = 0; i < numPackagePreferences; i++) { + final PackagePreferences r = mPackagePreferences.valueAt(i); + // Package isn't associated with this userId or notifications from this package are + // blocked + if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { + continue; + } + + for (NotificationChannel channel : r.channels.values()) { + if (channelIsLive(r, channel) && channel.canBypassDnd()) { if (!mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = true; updateZenPolicy(true); @@ -943,7 +1006,6 @@ public class PreferencesHelper implements RankingConfig { } } } - // If no channels bypass DND, update the zen policy once to disable DND bypass. if (mAreChannelsBypassingDnd) { mAreChannelsBypassingDnd = false; @@ -951,6 +1013,22 @@ public class PreferencesHelper implements RankingConfig { } } + private boolean channelIsLive(PackagePreferences pkgPref, NotificationChannel channel) { + // Channel is in a group that's blocked + if (!TextUtils.isEmpty(channel.getGroup())) { + if (pkgPref.groups.get(channel.getGroup()).isBlocked()) { + return false; + } + } + + // Channel is deleted or is blocked + if (channel.isDeleted() || channel.getImportance() == IMPORTANCE_NONE) { + return false; + } + + return true; + } + public void updateZenPolicy(boolean areChannelsBypassingDnd) { NotificationManager.Policy policy = mZenModeHelper.getNotificationPolicy(); mZenModeHelper.setNotificationPolicy(new NotificationManager.Policy( @@ -1329,6 +1407,20 @@ public class PreferencesHelper implements RankingConfig { return packageChannels; } + /** + * Called when user switches + */ + public void onUserSwitched(int userId) { + syncChannelsBypassingDnd(userId); + } + + /** + * Called when user is unlocked + */ + public void onUserUnlocked(int userId) { + syncChannelsBypassingDnd(userId); + } + public void onUserRemoved(int userId) { synchronized (mPackagePreferences) { int N = mPackagePreferences.size(); diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 807c343d0d10..731e6bcfb074 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -16,36 +16,46 @@ package com.android.server.om; +import static android.content.Context.IDMAP_SERVICE; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; + import static com.android.server.om.OverlayManagerService.DEBUG; import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.content.om.OverlayInfo; import android.content.pm.PackageInfo; +import android.os.IBinder; +import android.os.IIdmap2; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.util.Slog; -import com.android.server.pm.Installer.InstallerException; +import com.android.internal.os.BackgroundThread; import com.android.server.pm.Installer; -import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; /** * Handle the creation and deletion of idmap files. * * The actual work is performed by the idmap binary, launched through Installer - * and installd. + * and installd (or idmap2). * * Note: this class is subclassed in the OMS unit tests, and hence not marked as final. */ class IdmapManager { + private static final boolean FEATURE_FLAG_IDMAP2 = false; + private final Installer mInstaller; + private IIdmap2 mIdmap2Service; IdmapManager(final Installer installer) { mInstaller = installer; + if (FEATURE_FLAG_IDMAP2) { + connectToIdmap2d(); + } } boolean createIdmap(@NonNull final PackageInfo targetPackage, @@ -59,8 +69,12 @@ class IdmapManager { final String targetPath = targetPackage.applicationInfo.getBaseCodePath(); final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); try { - mInstaller.idmap(targetPath, overlayPath, sharedGid); - } catch (InstallerException e) { + if (FEATURE_FLAG_IDMAP2) { + mIdmap2Service.createIdmap(targetPath, overlayPath, userId); + } else { + mInstaller.idmap(targetPath, overlayPath, sharedGid); + } + } catch (Exception e) { Slog.w(TAG, "failed to generate idmap for " + targetPath + " and " + overlayPath + ": " + e.getMessage()); return false; @@ -69,13 +83,16 @@ class IdmapManager { } boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) { - // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible if (DEBUG) { Slog.d(TAG, "remove idmap for " + oi.baseCodePath); } try { - mInstaller.removeIdmap(oi.baseCodePath); - } catch (InstallerException e) { + if (FEATURE_FLAG_IDMAP2) { + mIdmap2Service.removeIdmap(oi.baseCodePath, userId); + } else { + mInstaller.removeIdmap(oi.baseCodePath); + } + } catch (Exception e) { Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage()); return false; } @@ -83,19 +100,58 @@ class IdmapManager { } boolean idmapExists(@NonNull final OverlayInfo oi) { - // unused OverlayInfo.userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible - return new File(getIdmapPath(oi.baseCodePath)).isFile(); + return new File(getIdmapPath(oi.baseCodePath, oi.userId)).isFile(); } boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { - // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible - return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile(); + return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath(), userId)) + .isFile(); } - private String getIdmapPath(@NonNull final String baseCodePath) { - final StringBuilder sb = new StringBuilder("/data/resource-cache/"); - sb.append(baseCodePath.substring(1).replace('/', '@')); - sb.append("@idmap"); - return sb.toString(); + private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath, + final int userId) { + if (FEATURE_FLAG_IDMAP2) { + try { + return mIdmap2Service.getIdmapPath(overlayPackagePath, userId); + } catch (Exception e) { + Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": " + + e.getMessage()); + return ""; + } + } else { + final StringBuilder sb = new StringBuilder("/data/resource-cache/"); + sb.append(overlayPackagePath.substring(1).replace('/', '@')); + sb.append("@idmap"); + return sb.toString(); + } + } + + private void connectToIdmap2d() { + IBinder binder = ServiceManager.getService(IDMAP_SERVICE); + if (binder != null) { + try { + binder.linkToDeath(new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Slog.w(TAG, "service '" + IDMAP_SERVICE + "' died; reconnecting..."); + connectToIdmap2d(); + } + + }, 0); + } catch (RemoteException e) { + binder = null; + } + } + if (binder != null) { + mIdmap2Service = IIdmap2.Stub.asInterface(binder); + if (DEBUG) { + Slog.d(TAG, "service '" + IDMAP_SERVICE + "' connected"); + } + } else { + Slog.w(TAG, "service '" + IDMAP_SERVICE + "' not found; trying again..."); + BackgroundThread.getHandler().postDelayed(() -> { + connectToIdmap2d(); + }, SECOND_IN_MILLIS); + } } } diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index 36bf83dfe92c..572d36897040 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -179,19 +179,13 @@ final class OverlayManagerSettings { List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName, final int userId) { - // Static RROs targeting "android" are loaded from AssetManager, and so they should be - // ignored in OverlayManagerService. return selectWhereTarget(targetPackageName, userId) - .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName()))) .map(SettingsItem::getOverlayInfo) .collect(Collectors.toList()); } ArrayMap<String, List<OverlayInfo>> getOverlaysForUser(final int userId) { - // Static RROs targeting "android" are loaded from AssetManager, and so they should be - // ignored in OverlayManagerService. return selectWhereUser(userId) - .filter((i) -> !(i.isStatic() && "android".equals(i.getTargetPackageName()))) .map(SettingsItem::getOverlayInfo) .collect(Collectors.groupingBy(info -> info.targetPackageName, ArrayMap::new, Collectors.toList())); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 275f3dcdb6d2..b4903817f787 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -362,7 +362,7 @@ public class LauncherAppsService extends SystemService { } private static boolean shouldShowHiddenApp(ApplicationInfo appInfo) { - if (appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) { + if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) { return false; } return true; diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java index a55b49fe028d..f78d2639df1a 100644 --- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java +++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java @@ -20,7 +20,7 @@ import android.app.ActivityManager; import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; -import android.security.IKeystoreService; +import android.security.keystore.IKeystoreService; import android.util.Slog; import com.android.internal.policy.IKeyguardService; diff --git a/services/core/java/com/android/server/role/RemoteRoleControllerService.java b/services/core/java/com/android/server/role/RemoteRoleControllerService.java index b670291ba94b..7d34270734df 100644 --- a/services/core/java/com/android/server/role/RemoteRoleControllerService.java +++ b/services/core/java/com/android/server/role/RemoteRoleControllerService.java @@ -16,10 +16,10 @@ package com.android.server.role; -import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.annotation.WorkerThread; import android.app.role.IRoleManagerCallback; import android.app.role.RoleManagerCallback; import android.content.ComponentName; @@ -34,6 +34,7 @@ import android.rolecontrollerservice.IRoleControllerService; import android.rolecontrollerservice.RoleControllerService; import android.util.Slog; +import com.android.internal.os.BackgroundThread; import com.android.internal.util.function.pooled.PooledLambda; import java.util.ArrayDeque; @@ -44,9 +45,13 @@ import java.util.Queue; */ public class RemoteRoleControllerService { + static final boolean DEBUG = false; private static final String LOG_TAG = RemoteRoleControllerService.class.getSimpleName(); @NonNull + private static final Handler sCallbackHandler = BackgroundThread.getHandler(); + + @NonNull private final Connection mConnection; public RemoteRoleControllerService(@UserIdInt int userId, @NonNull Context context) { @@ -87,6 +92,16 @@ public class RemoteRoleControllerService { service.onClearRoleHolders(roleName, callbackDelegate), callback)); } + /** + * Performs granting of default roles and permissions and appops + * + * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback) + */ + public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) { + mConnection.enqueueCall( + new Connection.Call(IRoleControllerService::onGrantDefaultRoles, callback)); + } + private static final class Connection implements ServiceConnection { private static final long UNBIND_DELAY_MILLIS = 15 * 1000; @@ -106,9 +121,6 @@ public class RemoteRoleControllerService { private final Queue<Call> mPendingCalls = new ArrayDeque<>(); @NonNull - private final Handler mMainHandler = Handler.getMain(); - - @NonNull private final Runnable mUnbindRunnable = this::unbind; Connection(@UserIdInt int userId, @NonNull Context context) { @@ -116,14 +128,14 @@ public class RemoteRoleControllerService { mContext = context; } - @MainThread @Override + @WorkerThread public void onServiceConnected(@NonNull ComponentName name, @NonNull IBinder service) { mService = IRoleControllerService.Stub.asInterface(service); executePendingCalls(); } - @MainThread + @WorkerThread private void executePendingCalls() { while (!mPendingCalls.isEmpty()) { Call call = mPendingCalls.poll(); @@ -132,26 +144,33 @@ public class RemoteRoleControllerService { scheduleUnbind(); } - @MainThread @Override + @WorkerThread public void onServiceDisconnected(@NonNull ComponentName name) { mService = null; } - @MainThread @Override + @WorkerThread public void onBindingDied(@NonNull ComponentName name) { unbind(); } public void enqueueCall(@NonNull Call call) { - mMainHandler.post(PooledLambda.obtainRunnable(this::executeCall, call)); + if (DEBUG) { + Slog.i(LOG_TAG, "Enqueue " + call); + } + sCallbackHandler.executeOrSendMessage(PooledLambda.obtainMessage( + Connection::executeCall, this, call)); } - @MainThread + @WorkerThread private void executeCall(@NonNull Call call) { ensureBound(); if (mService == null) { + if (DEBUG) { + Slog.i(LOG_TAG, "Delaying until service connected: " + call); + } mPendingCalls.offer(call); return; } @@ -159,24 +178,28 @@ public class RemoteRoleControllerService { scheduleUnbind(); } - @MainThread + @WorkerThread private void ensureBound() { - mMainHandler.removeCallbacks(mUnbindRunnable); + sCallbackHandler.removeCallbacks(mUnbindRunnable); if (!mBound) { Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE); intent.setPackage(mContext.getPackageManager() .getPermissionControllerPackageName()); + // Use direct handler to ensure onServiceConnected callback happens in the same + // call frame, as required by onGrantDefaultRoles + // + // Note that as a result, onServiceConnected may happen not on main thread! mBound = mContext.bindServiceAsUser(intent, this, Context.BIND_AUTO_CREATE, - UserHandle.of(mUserId)); + sCallbackHandler, UserHandle.of(mUserId)); } } private void scheduleUnbind() { - mMainHandler.removeCallbacks(mUnbindRunnable); - mMainHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS); + sCallbackHandler.removeCallbacks(mUnbindRunnable); + sCallbackHandler.postDelayed(mUnbindRunnable, UNBIND_DELAY_MILLIS); } - @MainThread + @WorkerThread private void unbind() { if (mBound) { mService = null; @@ -196,9 +219,6 @@ public class RemoteRoleControllerService { private final IRoleManagerCallback mCallback; @NonNull - private final Handler mMainHandler = Handler.getMain(); - - @NonNull private final Runnable mTimeoutRunnable = () -> notifyCallback(false); private boolean mCallbackNotified; @@ -209,10 +229,13 @@ public class RemoteRoleControllerService { mCallback = callback; } - @MainThread + @WorkerThread public void execute(IRoleControllerService service) { + if (DEBUG) { + Slog.i(LOG_TAG, "Executing " + this); + } try { - mMainHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS); + sCallbackHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MILLIS); mCallExecutor.execute(service, new CallbackDelegate()); } catch (RemoteException e) { Slog.e(LOG_TAG, "Error calling RoleControllerService", e); @@ -220,13 +243,13 @@ public class RemoteRoleControllerService { } } - @MainThread + @WorkerThread private void notifyCallback(boolean success) { if (mCallbackNotified) { return; } mCallbackNotified = true; - mMainHandler.removeCallbacks(mTimeoutRunnable); + sCallbackHandler.removeCallbacks(mTimeoutRunnable); try { if (success) { mCallback.onSuccess(); @@ -239,10 +262,15 @@ public class RemoteRoleControllerService { } } + @Override + public String toString() { + return "Call with callback: " + mCallback; + } + @FunctionalInterface public interface CallExecutor { - @MainThread + @WorkerThread void execute(IRoleControllerService service, IRoleManagerCallback callbackDelegate) throws RemoteException; } @@ -251,13 +279,14 @@ public class RemoteRoleControllerService { @Override public void onSuccess() throws RemoteException { - mMainHandler.post(PooledLambda.obtainRunnable(Call.this::notifyCallback, true)); + sCallbackHandler.sendMessage(PooledLambda.obtainMessage( + Call::notifyCallback, Call.this, true)); } @Override public void onFailure() throws RemoteException { - mMainHandler.post(PooledLambda.obtainRunnable(Call.this::notifyCallback, - false)); + sCallbackHandler.sendMessage(PooledLambda.obtainMessage( + Call::notifyCallback, Call.this, false)); } } } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index ded075d5742c..d01e7621dd39 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -45,6 +45,10 @@ import com.android.server.SystemService; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Service for role management. @@ -105,17 +109,37 @@ public class RoleManagerService extends SystemService { public void onStart() { publishBinderService(Context.ROLE_SERVICE, new Stub()); //TODO add watch for new user creation and run default grants for them + //TODO add package update watch to detect PermissionController upgrade and run def. grants } @Override public void onStartUser(@UserIdInt int userId) { synchronized (mLock) { //TODO only call into PermissionController if it or system upgreaded (for boot time) - // (add package changes watch; - // we can detect upgrade using build fingerprint and app version) getUserStateLocked(userId); - //TODO call permission grant policy here + } + //TODO consider calling grants only when certain conditions are met + // such as OS or PermissionController upgrade + if (RemoteRoleControllerService.DEBUG) { Slog.i(LOG_TAG, "Granting default permissions..."); + CompletableFuture<Void> result = new CompletableFuture<>(); + getControllerService(userId).onGrantDefaultRoles( + new IRoleManagerCallback.Stub() { + @Override + public void onSuccess() { + result.complete(null); + } + + @Override + public void onFailure() { + result.completeExceptionally(new RuntimeException()); + } + }); + try { + result.get(5, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e); + } } } diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 01d02d61cc83..3050409e67f9 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -47,6 +47,7 @@ import android.net.NetworkRequest; import android.net.NetworkStats; import android.net.wifi.IWifiManager; import android.net.wifi.WifiActivityEnergyInfo; +import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.Binder; import android.os.Bundle; @@ -87,6 +88,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.IProcessStats; import com.android.internal.app.procstats.ProcessStats; import com.android.internal.net.NetworkStatsFactory; +import com.android.internal.os.BatterySipper; +import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BinderCallsStats.ExportedCallStat; import com.android.internal.os.KernelCpuSpeedReader; import com.android.internal.os.KernelCpuThreadReader; @@ -205,6 +208,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { @Nullable private final KernelCpuThreadReader mKernelCpuThreadReader; + private BatteryStatsHelper mBatteryStatsHelper = null; + private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000; + private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS; + private static IThermalService sThermalService; private File mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_companion"); @@ -366,6 +373,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { List<Integer> uids = new ArrayList<>(); List<Long> versions = new ArrayList<>(); List<String> apps = new ArrayList<>(); + List<String> versionStrings = new ArrayList<>(); + List<String> installers = new ArrayList<>(); // Add in all the apps for every user/profile. for (UserInfo profile : users) { @@ -373,14 +382,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES, profile.id); for (int j = 0; j < pi.size(); j++) { if (pi.get(j).applicationInfo != null) { + String installer; + try { + installer = pm.getInstallerPackageName(pi.get(j).packageName); + } catch (IllegalArgumentException e) { + installer = ""; + } + installers.add(installer == null ? "" : installer); uids.add(pi.get(j).applicationInfo.uid); versions.add(pi.get(j).getLongVersionCode()); + versionStrings.add(pi.get(j).versionName); apps.add(pi.get(j).packageName); } } } - sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new - String[apps.size()])); + sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), + versionStrings.toArray(new String[versionStrings.size()]), + apps.toArray(new String[apps.size()]), + installers.toArray(new String[installers.size()])); if (DEBUG) { Slog.d(TAG, "Sent data for " + uids.size() + " apps"); } @@ -422,7 +441,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int uid = b.getInt(Intent.EXTRA_UID); String app = intent.getData().getSchemeSpecificPart(); PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); - sStatsd.informOnePackage(app, uid, pi.getLongVersionCode()); + String installer; + try { + installer = pm.getInstallerPackageName(app); + } catch (IllegalArgumentException e) { + installer = ""; + } + sStatsd.informOnePackage(app, uid, pi.getLongVersionCode(), pi.versionName, + installer == null ? "" : installer); } } catch (Exception e) { Slog.w(TAG, "Failed to inform statsd of an app update", e); @@ -1430,6 +1456,73 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } + private BatteryStatsHelper getBatteryStatsHelper() { + if (mBatteryStatsHelper == null) { + final long callingToken = Binder.clearCallingIdentity(); + try { + // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly(). + mBatteryStatsHelper = new BatteryStatsHelper(mContext, false); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + mBatteryStatsHelper.create((Bundle) null); + } + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) { + // Load BatteryStats and do all the calculations. + mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL); + // Calculations are done so we don't need to save the raw BatteryStats data in RAM. + mBatteryStatsHelper.clearStats(); + mBatteryStatsHelperTimestampMs = currentTime; + } + return mBatteryStatsHelper; + } + + private void pullDeviceCalculatedPowerUse(int tagId, + long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { + BatteryStatsHelper bsHelper = getBatteryStatsHelper(); + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeFloat((float) bsHelper.getComputedPower()); + pulledData.add(e); + } + + private void pullDeviceCalculatedPowerBlameUid(int tagId, + long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { + final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList(); + if (sippers == null) { + return; + } + for (BatterySipper bs : sippers) { + if (bs.drainType != bs.drainType.APP) { + continue; + } + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeInt(bs.uidObj.getUid()); + e.writeFloat((float) bs.totalPowerMah); + pulledData.add(e); + } + } + + private void pullDeviceCalculatedPowerBlameOther(int tagId, + long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { + final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList(); + if (sippers == null) { + return; + } + for (BatterySipper bs : sippers) { + if (bs.drainType == bs.drainType.APP) { + continue; // This is a separate atom; see pullDeviceCalculatedPowerBlameUid(). + } + if (bs.drainType == bs.drainType.USER) { + continue; // This is not supported. We purposefully calculate over USER_ALL. + } + StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos); + e.writeInt(bs.drainType.ordinal()); + e.writeFloat((float) bs.totalPowerMah); + pulledData.add(e); + } + } + private void pullDiskIo(int tagId, long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead, @@ -1655,6 +1748,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullCpuTimePerThreadFreq(tagId, elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.DEVICE_CALCULATED_POWER_USE: { + pullDeviceCalculatedPowerUse(tagId, elapsedNanos, wallClockNanos, ret); + break; + } + case StatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: { + pullDeviceCalculatedPowerBlameUid(tagId, elapsedNanos, wallClockNanos, ret); + break; + } + case StatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: { + pullDeviceCalculatedPowerBlameOther(tagId, elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 111c921e409c..92944a02f77a 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -95,6 +95,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.IApplicationToken; +import android.view.InputApplicationHandle; import android.view.RemoteAnimationDefinition; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -105,7 +106,6 @@ import android.view.animation.Animation; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; -import com.android.server.input.InputApplicationHandle; import com.android.server.policy.WindowManagerPolicy.StartingSurface; import com.android.server.wm.WindowManagerService.H; diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index ce8c979d3f87..7ed078a93375 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -36,7 +36,7 @@ import android.view.SurfaceSession; import android.view.View; import com.android.internal.util.Preconditions; -import com.android.server.input.InputWindowHandle; +import android.view.InputWindowHandle; import com.android.server.wm.WindowManagerInternal.IDragDropCallback; import java.util.concurrent.atomic.AtomicReference; diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 5483602487a2..a379266fe533 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -57,8 +57,8 @@ import android.view.animation.Interpolator; import com.android.internal.view.IDragAndDropPermissions; import com.android.server.LocalServices; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; +import android.view.InputApplicationHandle; +import android.view.InputWindowHandle; import java.util.ArrayList; @@ -223,7 +223,7 @@ class DragState { mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null, + mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, display.getDisplayId()); mDragWindowHandle.name = "drag"; mDragWindowHandle.inputChannel = mServerChannel; diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java index 585a4f55c9c2..49bedc97a38a 100644 --- a/services/core/java/com/android/server/wm/InputConsumerImpl.java +++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java @@ -23,8 +23,8 @@ import android.os.UserHandle; import android.view.InputChannel; import android.view.WindowManager; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; +import android.view.InputApplicationHandle; +import android.view.InputWindowHandle; import java.io.PrintWriter; @@ -63,7 +63,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient { mApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - mWindowHandle = new InputWindowHandle(mApplicationHandle, null, null, displayId); + mWindowHandle = new InputWindowHandle(mApplicationHandle, null, displayId); mWindowHandle.name = name; mWindowHandle.inputChannel = mServerChannel; mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index f823caadad79..92ea1a90735c 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -8,16 +8,19 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.app.ActivityManager; import android.os.Debug; +import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; import android.view.KeyEvent; import android.view.WindowManager; -import com.android.server.input.InputApplicationHandle; +import android.view.InputApplicationHandle; import com.android.server.input.InputManagerService; -import com.android.server.input.InputWindowHandle; +import android.view.InputWindowHandle; +import android.view.InputChannel; import java.io.PrintWriter; +import java.util.HashMap; final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks { private final WindowManagerService mService; @@ -48,13 +51,13 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal * Called by the InputManager. */ @Override - public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle) { - if (inputWindowHandle == null) { + public void notifyInputChannelBroken(IBinder token) { + if (token == null) { return; } synchronized (mService.mGlobalLock) { - WindowState windowState = (WindowState) inputWindowHandle.windowState; + WindowState windowState = mService.windowForClientLocked(null, token, false); if (windowState != null) { Slog.i(TAG_WM, "WINDOW DIED " + windowState); windowState.removeIfPossible(); @@ -70,13 +73,13 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal */ @Override public long notifyANR(InputApplicationHandle inputApplicationHandle, - InputWindowHandle inputWindowHandle, String reason) { + IBinder token, String reason) { AppWindowToken appWindowToken = null; WindowState windowState = null; boolean aboveSystem = false; synchronized (mService.mGlobalLock) { - if (inputWindowHandle != null) { - windowState = (WindowState) inputWindowHandle.windowState; + if (token != null) { + windowState = mService.windowForClientLocked(null, token, false); if (windowState != null) { appWindowToken = windowState.mAppToken; } @@ -188,8 +191,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal */ @Override public long interceptKeyBeforeDispatching( - InputWindowHandle focus, KeyEvent event, int policyFlags) { - WindowState windowState = focus != null ? (WindowState) focus.windowState : null; + IBinder focus, KeyEvent event, int policyFlags) { + WindowState windowState = mService.windowForClientLocked(null, focus, false); return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); } @@ -199,8 +202,8 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal */ @Override public KeyEvent dispatchUnhandledKey( - InputWindowHandle focus, KeyEvent event, int policyFlags) { - WindowState windowState = focus != null ? (WindowState) focus.windowState : null; + IBinder focus, KeyEvent event, int policyFlags) { + WindowState windowState = mService.windowForClientLocked(null, focus, false); return mService.mPolicy.dispatchUnhandledKey(windowState, event, policyFlags); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 0e4ab53e5c56..61bc4e405385 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -42,9 +42,12 @@ import android.util.Log; import android.util.Slog; import android.view.InputChannel; import android.view.InputEventReceiver; +import android.view.KeyEvent; +import android.view.WindowManager; +import android.view.InputApplicationHandle; +import android.view.InputWindowHandle; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; +import com.android.server.input.InputManagerService; import com.android.server.policy.WindowManagerPolicy; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index c4fbee931df3..6627c2dc5cc3 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -43,6 +43,7 @@ import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; +import android.view.InputWindowHandle; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; @@ -50,7 +51,6 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; -import com.android.server.input.InputWindowHandle; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.InsetUtils; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 66ebc9b27358..7182ad6fccfe 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -49,8 +49,9 @@ import android.view.MotionEvent; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.input.InputApplicationHandle; -import com.android.server.input.InputWindowHandle; +import android.view.InputApplicationHandle; +import android.view.InputWindowHandle; +import com.android.server.wm.WindowManagerService.H; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -265,7 +266,7 @@ class TaskPositioner { mDragApplicationHandle.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; - mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null, + mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, display.getDisplayId()); mDragWindowHandle.name = TAG; mDragWindowHandle.inputChannel = mServerChannel; diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java index f2d3dca27cf9..51567a0d6ad0 100644 --- a/services/core/java/com/android/server/wm/TaskPositioningController.java +++ b/services/core/java/com/android/server/wm/TaskPositioningController.java @@ -29,7 +29,7 @@ import android.view.IWindow; import com.android.internal.annotations.GuardedBy; import com.android.server.input.InputManagerService; -import com.android.server.input.InputWindowHandle; +import android.view.InputWindowHandle; /** * Controller for task positioning by drag. diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2b5076a2cf1d..a117cf33e596 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -191,7 +191,7 @@ import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ToBooleanFunction; -import com.android.server.input.InputWindowHandle; +import android.view.InputWindowHandle; import com.android.server.policy.WindowManagerPolicy; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.utils.InsetUtils; @@ -718,7 +718,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLastRequestedHeight = 0; mLayer = 0; mInputWindowHandle = new InputWindowHandle( - mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c, + mAppToken != null ? mAppToken.mInputApplicationHandle : null, c, getDisplayId()); } @@ -2047,7 +2047,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // Create dummy event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } - mService.mInputManager.registerInputChannel(mInputChannel, mInputWindowHandle); + mService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder()); } void disposeInputChannel() { @@ -2059,6 +2059,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // unregister server channel first otherwise it complains about broken channel if (mInputChannel != null) { mService.mInputManager.unregisterInputChannel(mInputChannel); + mInputChannel.dispose(); mInputChannel = null; } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 3943dba7092e..e2db80744294 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -42,6 +42,8 @@ #include <utils/Trace.h> #include <utils/SortedVector.h> +#include <binder/IServiceManager.h> + #include <input/PointerController.h> #include <input/SpriteController.h> @@ -63,6 +65,7 @@ #include "android_hardware_input_InputApplicationHandle.h" #include "android_hardware_input_InputWindowHandle.h" #include "android_hardware_display_DisplayViewport.h" +#include "android_util_Binder.h" #include <vector> @@ -153,15 +156,6 @@ static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env, getInputApplicationHandleObjLocalRef(env); } -static jobject getInputWindowHandleObjLocalRef(JNIEnv* env, - const sp<InputWindowHandle>& inputWindowHandle) { - if (inputWindowHandle == nullptr) { - return nullptr; - } - return static_cast<NativeInputWindowHandle*>(inputWindowHandle.get())-> - getInputWindowHandleObjLocalRef(env); -} - static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextObj, int32_t style, PointerIcon* outPointerIcon, SpriteIcon* outSpriteIcon) { status_t status = android_view_PointerIcon_loadSystemIcon(env, @@ -216,8 +210,7 @@ public: void setDisplayViewports(JNIEnv* env, jobjectArray viewportObjArray); - status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId); + status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel, int32_t displayId); status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel); void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId); @@ -253,17 +246,17 @@ public: uint32_t policyFlags); virtual void notifyConfigurationChanged(nsecs_t when); virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, + const sp<IBinder>& token, const std::string& reason); - virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle); + virtual void notifyInputChannelBroken(const sp<IBinder>& token); virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags); virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); virtual nsecs_t interceptKeyBeforeDispatching( - const sp<InputWindowHandle>& inputWindowHandle, + const sp<IBinder>& token, const KeyEvent* keyEvent, uint32_t policyFlags); - virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, + virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent); virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType); virtual bool checkInjectEventsPermissionNonReentrant( @@ -442,11 +435,10 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO } status_t NativeInputManager::registerInputChannel(JNIEnv* /* env */, - const sp<InputChannel>& inputChannel, const sp<InputWindowHandle>& inputWindowHandle, - int32_t displayId) { + const sp<InputChannel>& inputChannel, int32_t displayId) { ATRACE_CALL(); - return mInputManager->getDispatcher()->registerInputChannel(inputChannel, inputWindowHandle, - displayId); + return mInputManager->getDispatcher()->registerInputChannel( + inputChannel, displayId); } status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */, @@ -657,7 +649,7 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) { } nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle, const std::string& reason) { + const sp<IBinder>& token, const std::string& reason) { #if DEBUG_INPUT_DISPATCHER_POLICY ALOGD("notifyANR"); #endif @@ -667,12 +659,11 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp jobject inputApplicationHandleObj = getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); - jobject inputWindowHandleObj = - getInputWindowHandleObjLocalRef(env, inputWindowHandle); + jobject tokenObj = javaObjectForIBinder(env, token); jstring reasonObj = env->NewStringUTF(reason.c_str()); jlong newTimeout = env->CallLongMethod(mServiceObj, - gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj, + gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj, reasonObj); if (checkAndClearExceptionFromCallback(env, "notifyANR")) { newTimeout = 0; // abort dispatch @@ -681,12 +672,11 @@ nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApp } env->DeleteLocalRef(reasonObj); - env->DeleteLocalRef(inputWindowHandleObj); env->DeleteLocalRef(inputApplicationHandleObj); return newTimeout; } -void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) { +void NativeInputManager::notifyInputChannelBroken(const sp<IBinder>& token) { #if DEBUG_INPUT_DISPATCHER_POLICY ALOGD("notifyInputChannelBroken"); #endif @@ -694,14 +684,11 @@ void NativeInputManager::notifyInputChannelBroken(const sp<InputWindowHandle>& i JNIEnv* env = jniEnv(); - jobject inputWindowHandleObj = - getInputWindowHandleObjLocalRef(env, inputWindowHandle); - if (inputWindowHandleObj) { + jobject tokenObj = javaObjectForIBinder(env, token); + if (tokenObj) { env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyInputChannelBroken, - inputWindowHandleObj); + tokenObj); checkAndClearExceptionFromCallback(env, "notifyInputChannelBroken"); - - env->DeleteLocalRef(inputWindowHandleObj); } } @@ -1061,7 +1048,7 @@ void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, } nsecs_t NativeInputManager::interceptKeyBeforeDispatching( - const sp<InputWindowHandle>& inputWindowHandle, + const sp<IBinder>& token, const KeyEvent* keyEvent, uint32_t policyFlags) { ATRACE_CALL(); // Policy: @@ -1072,13 +1059,14 @@ nsecs_t NativeInputManager::interceptKeyBeforeDispatching( if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputWindowHandle may be null. - jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); + // Token may be null + jobject tokenObj = javaObjectForIBinder(env, token); + jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jlong delayMillis = env->CallLongMethod(mServiceObj, gServiceClassInfo.interceptKeyBeforeDispatching, - inputWindowHandleObj, keyEventObj, policyFlags); + tokenObj, keyEventObj, policyFlags); bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); @@ -1092,12 +1080,11 @@ nsecs_t NativeInputManager::interceptKeyBeforeDispatching( } else { ALOGE("Failed to obtain key event object for interceptKeyBeforeDispatching."); } - env->DeleteLocalRef(inputWindowHandleObj); } return result; } -bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, +bool NativeInputManager::dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) { ATRACE_CALL(); // Policy: @@ -1106,13 +1093,13 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& input if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); - // Note: inputWindowHandle may be null. - jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); + // Note: tokenObj may be null. + jobject tokenObj = javaObjectForIBinder(env, token); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { jobject fallbackKeyEventObj = env->CallObjectMethod(mServiceObj, gServiceClassInfo.dispatchUnhandledKey, - inputWindowHandleObj, keyEventObj, policyFlags); + tokenObj, keyEventObj, policyFlags); if (checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey")) { fallbackKeyEventObj = nullptr; } @@ -1131,7 +1118,6 @@ bool NativeInputManager::dispatchUnhandledKey(const sp<InputWindowHandle>& input } else { ALOGE("Failed to obtain key event object for dispatchUnhandledKey."); } - env->DeleteLocalRef(inputWindowHandleObj); } return result; } @@ -1316,7 +1302,7 @@ static void handleInputChannelDisposed(JNIEnv* env, } static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, - jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jint displayId) { + jlong ptr, jobject inputChannelObj, jint displayId) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, @@ -1325,12 +1311,10 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, throwInputChannelNotInitialized(env); return; } + bool monitor = inputChannel->getToken() == nullptr && displayId != ADISPLAY_ID_NONE; - sp<InputWindowHandle> inputWindowHandle = - android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj); + status_t status = im->registerInputChannel(env, inputChannel, displayId); - status_t status = im->registerInputChannel( - env, inputChannel, inputWindowHandle, displayId); if (status) { std::string message; message += StringPrintf("Failed to register input channel. status=%d", status); @@ -1339,7 +1323,7 @@ static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */, } // If inputWindowHandle is null and displayId >= 0, treat inputChannel as monitor. - if (inputWindowHandle != nullptr || displayId == ADISPLAY_ID_NONE) { + if (!monitor) { android_view_InputChannel_setDisposeCallback(env, inputChannelObj, handleInputChannelDisposed, im); } @@ -1640,7 +1624,7 @@ static const JNINativeMethod gInputManagerMethods[] = { { "nativeHasKeys", "(JII[I[Z)Z", (void*) nativeHasKeys }, { "nativeRegisterInputChannel", - "(JLandroid/view/InputChannel;Lcom/android/server/input/InputWindowHandle;I)V", + "(JLandroid/view/InputChannel;I)V", (void*) nativeRegisterInputChannel }, { "nativeUnregisterInputChannel", "(JLandroid/view/InputChannel;)V", (void*) nativeUnregisterInputChannel }, @@ -1650,9 +1634,9 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*) nativeInjectInputEvent }, { "nativeToggleCapsLock", "(JI)V", (void*) nativeToggleCapsLock }, - { "nativeSetInputWindows", "(J[Lcom/android/server/input/InputWindowHandle;I)V", + { "nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V", (void*) nativeSetInputWindows }, - { "nativeSetFocusedApplication", "(JILcom/android/server/input/InputApplicationHandle;)V", + { "nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V", (void*) nativeSetFocusedApplication }, { "nativeSetFocusedDisplay", "(JI)V", (void*) nativeSetFocusedDisplay }, @@ -1731,11 +1715,11 @@ int register_android_server_InputManager(JNIEnv* env) { "notifySwitch", "(JII)V"); GET_METHOD_ID(gServiceClassInfo.notifyInputChannelBroken, clazz, - "notifyInputChannelBroken", "(Lcom/android/server/input/InputWindowHandle;)V"); + "notifyInputChannelBroken", "(Landroid/os/IBinder;)V"); GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz, "notifyANR", - "(Lcom/android/server/input/InputApplicationHandle;Lcom/android/server/input/InputWindowHandle;Ljava/lang/String;)J"); + "(Landroid/view/InputApplicationHandle;Landroid/os/IBinder;Ljava/lang/String;)J"); GET_METHOD_ID(gServiceClassInfo.filterInputEvent, clazz, "filterInputEvent", "(Landroid/view/InputEvent;I)Z"); @@ -1748,11 +1732,11 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz, "interceptKeyBeforeDispatching", - "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)J"); + "(Landroid/os/IBinder;Landroid/view/KeyEvent;I)J"); GET_METHOD_ID(gServiceClassInfo.dispatchUnhandledKey, clazz, "dispatchUnhandledKey", - "(Lcom/android/server/input/InputWindowHandle;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); + "(Landroid/os/IBinder;Landroid/view/KeyEvent;I)Landroid/view/KeyEvent;"); GET_METHOD_ID(gServiceClassInfo.checkInjectEventsPermission, clazz, "checkInjectEventsPermission", "(II)Z"); diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java index dc3cd62dc78b..fcfd24625161 100644 --- a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java +++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java @@ -19,6 +19,7 @@ package com.android.server.intelligence; import static android.content.Context.INTELLIGENCE_MANAGER_SERVICE; import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.app.ActivityManagerInternal; import android.content.ComponentName; import android.content.Context; @@ -59,14 +60,14 @@ public final class IntelligenceManagerService super(context, UserManager.DISALLOW_INTELLIGENCE_CAPTURE); } - @Override // from MasterSystemService + @Override // from AbstractMasterSystemService protected String getServiceSettingsProperty() { // TODO(b/111276913): STOPSHIP temporary settings, until it's set by resourcs + cmd return "intel_service"; } - @Override // from MasterSystemService - protected IntelligencePerUserService newServiceLocked(int resolvedUserId, + @Override // from AbstractMasterSystemService + protected IntelligencePerUserService newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled) { return new IntelligencePerUserService(this, mLock, resolvedUserId); } @@ -79,12 +80,9 @@ public final class IntelligenceManagerService } @Override // from AbstractMasterSystemService - protected IntelligencePerUserService removeCachedServiceLocked(int userId) { - final IntelligencePerUserService service = super.removeCachedServiceLocked(userId); - if (service != null) { - service.destroyLocked(); - } - return service; + protected void onServiceRemoved(@NonNull IntelligencePerUserService service, + @UserIdInt int userId) { + service.destroyLocked(); } private ActivityManagerInternal getAmInternal() { diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk index 9ab06a129d88..565152c31448 100644 --- a/services/robotests/Android.mk +++ b/services/robotests/Android.mk @@ -27,7 +27,8 @@ LOCAL_PRIVILEGED_MODULE := true LOCAL_STATIC_JAVA_LIBRARIES := \ services.backup \ - services.core + services.core \ + services.net include $(BUILD_PACKAGE) diff --git a/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java b/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java deleted file mode 100644 index c162c3b9cc42..000000000000 --- a/services/tests/servicestests/src/com/android/server/am/GlobalSettingsToPropertiesMapperTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.am; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import android.content.ContentResolver; -import android.provider.Settings; -import android.test.mock.MockContentResolver; - -import androidx.test.filters.SmallTest; - -import com.android.internal.util.Preconditions; -import com.android.internal.util.test.FakeSettingsProvider; - -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -/** - * Tests for {@link GlobalSettingsToPropertiesMapper} - * - * Build/Install/Run: - * atest FrameworksServicesTests:GlobalSettingsToPropertiesMapperTest - */ -@SmallTest -public class GlobalSettingsToPropertiesMapperTest { - private static final String[][] TEST_MAPPING = new String[][] { - {Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "TestProperty"} - }; - - private TestMapper mTestMapper; - private MockContentResolver mMockContentResolver; - - @Before - public void setup() { - // Use FakeSettingsProvider to not affect global state - mMockContentResolver = new MockContentResolver(getInstrumentation().getTargetContext()); - mMockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); - mTestMapper = new TestMapper(mMockContentResolver); - } - - @Test - public void testUpdatePropertiesFromGlobalSettings() { - Settings.Global.putString(mMockContentResolver, - Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue"); - - mTestMapper.updatePropertiesFromGlobalSettings(); - String propValue = mTestMapper.systemPropertiesGet("TestProperty"); - assertEquals("testValue", propValue); - - Settings.Global.putString(mMockContentResolver, - Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2"); - mTestMapper.updatePropertyFromSetting(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, - "TestProperty"); - propValue = mTestMapper.systemPropertiesGet("TestProperty"); - assertEquals("testValue2", propValue); - - Settings.Global.putString(mMockContentResolver, - Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null); - mTestMapper.updatePropertyFromSetting(Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, - "TestProperty"); - propValue = mTestMapper.systemPropertiesGet("TestProperty"); - assertEquals("", propValue); - } - - @Test - public void testUpdatePropertiesFromGlobalSettings_PropertyAndSettingNotPresent() { - // Test that empty property will not not be set if setting is not set - mTestMapper.updatePropertiesFromGlobalSettings(); - String propValue = mTestMapper.systemPropertiesGet("TestProperty"); - assertNull("Property should not be set if setting is null", propValue); - } - - private static class TestMapper extends GlobalSettingsToPropertiesMapper { - private final Map<String, String> mProps = new HashMap<>(); - - TestMapper(ContentResolver contentResolver) { - super(contentResolver, TEST_MAPPING); - } - - @Override - protected String systemPropertiesGet(String key) { - Preconditions.checkNotNull(key); - return mProps.get(key); - } - - @Override - protected void systemPropertiesSet(String key, String value) { - Preconditions.checkNotNull(value); - Preconditions.checkNotNull(key); - mProps.put(key, value); - } - } -} - diff --git a/services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java b/services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java new file mode 100644 index 000000000000..d965f8a34fa4 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/SettingsToPropertiesMapperTest.java @@ -0,0 +1,211 @@ +/* + * 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.am; + +import android.content.ContentResolver; +import android.provider.Settings; +import android.test.mock.MockContentResolver; +import android.text.TextUtils; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.util.Preconditions; +import com.android.internal.util.test.FakeSettingsProvider; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +/** + * Tests for {@link SettingsToPropertiesMapper} + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SettingsToPropertiesMapperTest { + private static final String NAME_VALID_CHARACTERS_REGEX = "^[\\w\\.\\-@:]*$"; + private static final String[] TEST_MAPPING = new String[] { + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS + }; + + private TestMapper mTestMapper; + private MockContentResolver mMockContentResolver; + + @Before + public void setupForEach() { + // Use FakeSettingsProvider to not affect global state + mMockContentResolver = new MockContentResolver(InstrumentationRegistry.getContext()); + mMockContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + mTestMapper = new TestMapper(mMockContentResolver); + } + + @Test + public void validateRegisteredGlobalSettings() { + HashSet<String> hashSet = new HashSet<>(); + for (String globalSetting : SettingsToPropertiesMapper.sGlobalSettings) { + if (hashSet.contains(globalSetting)) { + Assert.fail("globalSetting " + + globalSetting + + " is registered more than once in " + + "SettingsToPropertiesMapper.sGlobalSettings."); + } + hashSet.add(globalSetting); + if (TextUtils.isEmpty(globalSetting)) { + Assert.fail("empty globalSetting registered."); + } + if (!globalSetting.matches(NAME_VALID_CHARACTERS_REGEX)) { + Assert.fail(globalSetting + " contains invalid characters. " + + "Only alphanumeric characters, '.', '-', '@', ':' and '_' are valid."); + } + } + } + + @Test + public void testUpdatePropertiesFromSettings() { + Settings.Global.putString(mMockContentResolver, + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue"); + + String systemPropertyName = "persist.device_config.global_settings." + + "sqlite_compatibility_wal_flags"; + + mTestMapper.updatePropertiesFromSettings(); + String propValue = mTestMapper.systemPropertiesGet(systemPropertyName); + Assert.assertEquals("testValue", propValue); + + Settings.Global.putString(mMockContentResolver, + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, "testValue2"); + mTestMapper.updatePropertyFromSetting( + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, + systemPropertyName, + true); + propValue = mTestMapper.systemPropertiesGet(systemPropertyName); + Assert.assertEquals("testValue2", propValue); + + Settings.Global.putString(mMockContentResolver, + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, null); + mTestMapper.updatePropertyFromSetting( + Settings.Global.SQLITE_COMPATIBILITY_WAL_FLAGS, + systemPropertyName, + true); + propValue = mTestMapper.systemPropertiesGet(systemPropertyName); + Assert.assertEquals("", propValue); + } + + @Test + public void testMakePropertyName() { + try { + Assert.assertEquals("persist.device_config.test_category.test_flag", + SettingsToPropertiesMapper.makePropertyName("test_category", "test_flag")); + } catch (Exception e) { + Assert.fail("Unexpected exception: " + e.getMessage()); + } + + try { + Assert.assertEquals(null, + SettingsToPropertiesMapper.makePropertyName("test_category!!!", "test_flag")); + } catch (Exception e) { + Assert.fail("Unexpected exception: " + e.getMessage()); + } + + try { + Assert.assertEquals(null, + SettingsToPropertiesMapper.makePropertyName("test_category", ".test_flag")); + } catch (Exception e) { + Assert.fail("Unexpected exception: " + e.getMessage()); + } + } + + @Test + public void testUpdatePropertiesFromSettings_PropertyAndSettingNotPresent() { + // Test that empty property will not not be set if setting is not set + mTestMapper.updatePropertiesFromSettings(); + String propValue = mTestMapper.systemPropertiesGet("TestProperty"); + Assert.assertNull("Property should not be set if setting is null", propValue); + } + + @Test + public void testIsNativeFlagsResetPerformed() { + mTestMapper.systemPropertiesSet("device_config.reset_performed", "true"); + Assert.assertTrue(mTestMapper.isNativeFlagsResetPerformed()); + + mTestMapper.systemPropertiesSet("device_config.reset_performed", "false"); + Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed()); + + mTestMapper.systemPropertiesSet("device_config.reset_performed", ""); + Assert.assertFalse(mTestMapper.isNativeFlagsResetPerformed()); + } + + @Test + public void testGetResetNativeCategories() { + mTestMapper.systemPropertiesSet("device_config.reset_performed", ""); + Assert.assertEquals(mTestMapper.getResetNativeCategories().length, 0); + + mTestMapper.systemPropertiesSet("device_config.reset_performed", "true"); + mTestMapper.setFileContent(""); + Assert.assertEquals(mTestMapper.getResetNativeCategories().length, 0); + + mTestMapper.systemPropertiesSet("device_config.reset_performed", "true"); + mTestMapper.setFileContent("persist.device_config.category1.flag;" + + "persist.device_config.category2.flag;persist.device_config.category3.flag;" + + "persist.device_config.category3.flag2"); + List<String> categories = Arrays.asList(mTestMapper.getResetNativeCategories()); + Assert.assertEquals(3, categories.size()); + Assert.assertTrue(categories.contains("category1")); + Assert.assertTrue(categories.contains("category2")); + Assert.assertTrue(categories.contains("category3")); + } + + private static class TestMapper extends SettingsToPropertiesMapper { + private final Map<String, String> mProps = new HashMap<>(); + + private String mFileContent = ""; + + TestMapper(ContentResolver contentResolver) { + super(contentResolver, TEST_MAPPING, new String[] {}); + } + + @Override + protected String systemPropertiesGet(String key) { + Preconditions.checkNotNull(key); + return mProps.get(key); + } + + @Override + protected void systemPropertiesSet(String key, String value) { + Preconditions.checkNotNull(value); + Preconditions.checkNotNull(key); + mProps.put(key, value); + } + + protected void setFileContent(String fileContent) { + mFileContent = fileContent; + } + + @Override + protected String getResetFlagsFileContent() { + return mFileContent; + } + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 3fe381b0abe2..1a218b23368d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -27,7 +27,6 @@ import static junit.framework.Assert.fail; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -98,7 +97,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { private static final UserHandle USER = UserHandle.of(0); private static final int UID_O = 1111; private static final String SYSTEM_PKG = "android"; - private static final int SYSTEM_UID= 1000; + private static final int SYSTEM_UID = 1000; private static final UserHandle USER2 = UserHandle.of(10); private static final String TEST_CHANNEL_ID = "test_channel_id"; private static final String TEST_AUTHORITY = "test"; @@ -1091,6 +1090,158 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void testGetChannelsBypassingDndCount_noChannelsBypassing() throws Exception { + assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + USER.getIdentifier()).getList().size()); + } + + @Test + public void testGetChannelsBypassingDnd_noChannelsForUserIdBypassing() + throws Exception { + int user = 9; + NotificationChannel channel = new NotificationChannel("id", "name", + NotificationManager.IMPORTANCE_MAX); + channel.setBypassDnd(true); + mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true); + + assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + } + + @Test + public void testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked() { + int user = USER.getIdentifier(); + NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel1.setGroup(ncg.getId()); + mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true); + + assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + + // disable group + ncg.setBlocked(true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ false); + assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + } + + @Test + public void testGetChannelsBypassingDndCount_multipleChannelsBypassing() { + int user = USER.getIdentifier(); + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel2 = new NotificationChannel("id2", "name2", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel3 = new NotificationChannel("id3", "name3", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel2.setBypassDnd(true); + channel3.setBypassDnd(true); + // has DND access, so can set bypassDnd attribute + mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel3, true, true); + assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + + // block notifications from this app + mHelper.setEnabled(PKG_N_MR1, user, false); + assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + + // re-enable notifications from this app + mHelper.setEnabled(PKG_N_MR1, user, true); + assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + + // setBypassDnd false for some channels + channel1.setBypassDnd(false); + channel2.setBypassDnd(false); + assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + + // setBypassDnd false for rest of the channels + channel3.setBypassDnd(false); + assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, + user).getList().size()); + } + + @Test + public void testGetAppsBypassingDndCount_noAppsBypassing() throws Exception { + assertEquals(0, mHelper.getAppsBypassingDndCount(USER.getIdentifier())); + } + + @Test + public void testGetAppsBypassingDndCount_noAppsForUserIdBypassing() throws Exception { + int user = 9; + NotificationChannel channel = new NotificationChannel("id", "name", + NotificationManager.IMPORTANCE_MAX); + channel.setBypassDnd(true); + mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true); + + assertEquals(0, mHelper.getAppsBypassingDndCount(user)); + } + + @Test + public void testGetAppsBypassingDndCount_oneChannelBypassing_groupBlocked() { + int user = USER.getIdentifier(); + NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel1.setGroup(ncg.getId()); + mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true); + + assertEquals(1, mHelper.getAppsBypassingDndCount(user)); + + // disable group + ncg.setBlocked(true); + mHelper.createNotificationChannelGroup(PKG_N_MR1, user, ncg, /* fromTargetApp */ false); + assertEquals(0, mHelper.getAppsBypassingDndCount(user)); + } + + @Test + public void testGetAppsBypassingDndCount_oneAppBypassing() { + int user = USER.getIdentifier(); + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel2 = new NotificationChannel("id2", "name2", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel3 = new NotificationChannel("id3", "name3", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel2.setBypassDnd(true); + channel3.setBypassDnd(true); + // has DND access, so can set bypassDnd attribute + mHelper.createNotificationChannel(PKG_N_MR1, user, channel1, true, /*has DND access*/ true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel2, true, true); + mHelper.createNotificationChannel(PKG_N_MR1, user, channel3, true, true); + assertEquals(1, mHelper.getAppsBypassingDndCount(user)); + + // block notifications from this app + mHelper.setEnabled(PKG_N_MR1, user, false); + assertEquals(0, mHelper.getAppsBypassingDndCount(user)); // no apps can bypass dnd + + // re-enable notifications from this app + mHelper.setEnabled(PKG_N_MR1, user, true); + assertEquals(1, mHelper.getAppsBypassingDndCount(user)); + + // setBypassDnd false for some channels + channel1.setBypassDnd(false); + channel2.setBypassDnd(false); + assertEquals(1, mHelper.getAppsBypassingDndCount(user)); + + // setBypassDnd false for rest of the channels + channel3.setBypassDnd(false); + assertEquals(0, mHelper.getAppsBypassingDndCount(user)); + } + + @Test public void testCreateAndDeleteCanChannelsBypassDnd() throws Exception { // create notification channel that can't bypass dnd // expected result: areChannelsBypassingDnd = false diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc index 33df6f9c37d7..906d64c1f619 100644 --- a/startop/view_compiler/dex_builder.cc +++ b/startop/view_compiler/dex_builder.cc @@ -49,18 +49,27 @@ std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) { case Instruction::Op::kReturn: out << "kReturn"; return out; + case Instruction::Op::kReturnObject: + out << "kReturnObject"; + return out; case Instruction::Op::kMove: out << "kMove"; return out; case Instruction::Op::kInvokeVirtual: out << "kInvokeVirtual"; return out; + case Instruction::Op::kInvokeDirect: + out << "kInvokeDirect"; + return out; case Instruction::Op::kBindLabel: out << "kBindLabel"; return out; case Instruction::Op::kBranchEqz: out << "kBranchEqz"; return out; + case Instruction::Op::kNew: + out << "kNew"; + return out; } } @@ -137,6 +146,9 @@ ir::String* DexBuilder::GetOrAddString(const std::string& string) { entry = Alloc<ir::String>(); // +1 for null terminator entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1}; + ::dex::u4 const new_index = dex_file_->strings_indexes.AllocateIndex(); + dex_file_->strings_map[new_index] = entry; + entry->orig_index = new_index; string_data_.push_back(std::move(buffer)); } return entry; @@ -161,6 +173,8 @@ ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) { ir::Type* type = Alloc<ir::Type>(); type->descriptor = GetOrAddString(descriptor); types_by_descriptor_[descriptor] = type; + type->orig_index = dex_file_->types_indexes.AllocateIndex(); + dex_file_->types_map[type->orig_index] = type; return type; } @@ -217,9 +231,10 @@ ir::EncodedMethod* MethodBuilder::Encode() { decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0; code->registers = num_registers_ + num_args; code->ins_count = num_args; - code->outs_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1; EncodeInstructions(); code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size()); + size_t const return_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1; + code->outs_count = std::max(return_count, max_args_); method->code = code; class_->direct_methods.push_back(method); @@ -240,8 +255,9 @@ void MethodBuilder::AddInstruction(Instruction instruction) { void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); } -void MethodBuilder::BuildReturn(Value src) { - AddInstruction(Instruction::OpWithArgs(Op::kReturn, /*destination=*/{}, src)); +void MethodBuilder::BuildReturn(Value src, bool is_object) { + AddInstruction(Instruction::OpWithArgs( + is_object ? Op::kReturnObject : Op::kReturn, /*destination=*/{}, src)); } void MethodBuilder::BuildConst4(Value target, int value) { @@ -249,6 +265,11 @@ void MethodBuilder::BuildConst4(Value target, int value) { AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value))); } +void MethodBuilder::BuildConstString(Value target, const std::string& value) { + const ir::String* const dex_string = dex_->GetOrAddString(value); + AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::String(dex_string->orig_index))); +} + void MethodBuilder::EncodeInstructions() { buffer_.clear(); for (const auto& instruction : instructions_) { @@ -259,27 +280,32 @@ void MethodBuilder::EncodeInstructions() { void MethodBuilder::EncodeInstruction(const Instruction& instruction) { switch (instruction.opcode()) { case Instruction::Op::kReturn: - return EncodeReturn(instruction); + return EncodeReturn(instruction, ::art::Instruction::RETURN); + case Instruction::Op::kReturnObject: + return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT); case Instruction::Op::kMove: return EncodeMove(instruction); case Instruction::Op::kInvokeVirtual: - return EncodeInvokeVirtual(instruction); + return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL); + case Instruction::Op::kInvokeDirect: + return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT); case Instruction::Op::kBindLabel: return BindLabel(instruction.args()[0]); case Instruction::Op::kBranchEqz: return EncodeBranch(art::Instruction::IF_EQZ, instruction); + case Instruction::Op::kNew: + return EncodeNew(instruction); } } -void MethodBuilder::EncodeReturn(const Instruction& instruction) { - DCHECK_EQ(Instruction::Op::kReturn, instruction.opcode()); +void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) { DCHECK(!instruction.dest().has_value()); if (instruction.args().size() == 0) { - buffer_.push_back(art::Instruction::RETURN_VOID); + Encode10x(art::Instruction::RETURN_VOID); } else { - DCHECK(instruction.args().size() == 1); + DCHECK_EQ(1, instruction.args().size()); size_t source = RegisterValue(instruction.args()[0]); - buffer_.push_back(art::Instruction::RETURN | source << 8); + Encode11x(opcode, source); } } @@ -294,31 +320,43 @@ void MethodBuilder::EncodeMove(const Instruction& instruction) { if (source.is_immediate()) { // TODO: support more registers DCHECK_LT(RegisterValue(*instruction.dest()), 16); - DCHECK_LT(source.value(), 16); - buffer_.push_back(art::Instruction::CONST_4 | (source.value() << 12) | - (RegisterValue(*instruction.dest()) << 8)); + Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value()); + } else if (source.is_string()) { + constexpr size_t kMaxRegisters = 256; + DCHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters); + DCHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string + Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value()); } else { UNIMPLEMENTED(FATAL); } } -void MethodBuilder::EncodeInvokeVirtual(const Instruction& instruction) { - DCHECK_EQ(Instruction::Op::kInvokeVirtual, instruction.opcode()); +void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) { + constexpr size_t kMaxArgs = 5; - // TODO: support more than one argument (i.e. the this argument) and change this to DCHECK_GE - DCHECK_EQ(1, instruction.args().size()); + CHECK_LE(instruction.args().size(), kMaxArgs); - const Value& this_arg = instruction.args()[0]; + uint8_t arguments[kMaxArgs]{}; + for (size_t i = 0; i < instruction.args().size(); ++i) { + CHECK(instruction.args()[i].is_variable()); + arguments[i] = RegisterValue(instruction.args()[i]); + } - size_t real_reg = RegisterValue(this_arg) & 0xf; - buffer_.push_back(1 << 12 | art::Instruction::INVOKE_VIRTUAL); - buffer_.push_back(instruction.method_id()); - buffer_.push_back(real_reg); + Encode35c(opcode, + instruction.args().size(), + instruction.method_id(), + arguments[0], + arguments[1], + arguments[2], + arguments[3], + arguments[4]); + // If there is a return value, add a move-result instruction if (instruction.dest().has_value()) { - real_reg = RegisterValue(*instruction.dest()); - buffer_.push_back(real_reg << 8 | art::Instruction::MOVE_RESULT); + Encode11x(art::Instruction::MOVE_RESULT, RegisterValue(*instruction.dest())); } + + max_args_ = std::max(max_args_, instruction.args().size()); } // Encodes a conditional branch that tests a single argument. @@ -331,9 +369,21 @@ void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& i CHECK(branch_target.is_label()); size_t instruction_offset = buffer_.size(); - buffer_.push_back(op | (RegisterValue(test_value) << 8)); - size_t field_offset = buffer_.size(); - buffer_.push_back(LabelValue(branch_target, instruction_offset, field_offset)); + size_t field_offset = buffer_.size() + 1; + Encode21c( + op, RegisterValue(test_value), LabelValue(branch_target, instruction_offset, field_offset)); +} + +void MethodBuilder::EncodeNew(const Instruction& instruction) { + DCHECK_EQ(Instruction::Op::kNew, instruction.opcode()); + DCHECK(instruction.dest().has_value()); + DCHECK(instruction.dest()->is_variable()); + DCHECK_EQ(1, instruction.args().size()); + + const Value& type = instruction.args()[0]; + DCHECK_LT(RegisterValue(*instruction.dest()), 256); + DCHECK(type.is_type()); + Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value()); } size_t MethodBuilder::RegisterValue(const Value& value) const { diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h index 07441518ea32..adf82bf9a01a 100644 --- a/startop/view_compiler/dex_builder.h +++ b/startop/view_compiler/dex_builder.h @@ -110,18 +110,22 @@ class Value { static constexpr Value Local(size_t id) { return Value{id, Kind::kLocalRegister}; } static constexpr Value Parameter(size_t id) { return Value{id, Kind::kParameter}; } static constexpr Value Immediate(size_t value) { return Value{value, Kind::kImmediate}; } + static constexpr Value String(size_t value) { return Value{value, Kind::kString}; } static constexpr Value Label(size_t id) { return Value{id, Kind::kLabel}; } + static constexpr Value Type(size_t id) { return Value{id, Kind::kType}; } bool is_register() const { return kind_ == Kind::kLocalRegister; } bool is_parameter() const { return kind_ == Kind::kParameter; } bool is_variable() const { return is_register() || is_parameter(); } bool is_immediate() const { return kind_ == Kind::kImmediate; } + bool is_string() const { return kind_ == Kind::kString; } bool is_label() const { return kind_ == Kind::kLabel; } + bool is_type() const { return kind_ == Kind::kType; } size_t value() const { return value_; } private: - enum class Kind { kLocalRegister, kParameter, kImmediate, kLabel }; + enum class Kind { kLocalRegister, kParameter, kImmediate, kString, kLabel, kType }; const size_t value_; const Kind kind_; @@ -137,7 +141,16 @@ class Instruction { public: // The operation performed by this instruction. These are virtual instructions that do not // correspond exactly to DEX instructions. - enum class Op { kReturn, kMove, kInvokeVirtual, kBindLabel, kBranchEqz }; + enum class Op { + kReturn, + kReturnObject, + kMove, + kInvokeVirtual, + kInvokeDirect, + kBindLabel, + kBranchEqz, + kNew + }; //////////////////////// // Named Constructors // @@ -158,6 +171,12 @@ class Instruction { Value this_arg, T... args) { return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...}; } + // For direct calls (basically, constructors). + template <typename... T> + static inline Instruction InvokeDirect(size_t method_id, std::optional<const Value> dest, + Value this_arg, T... args) { + return Instruction{Op::kInvokeDirect, method_id, dest, this_arg, args...}; + } /////////////// // Accessors // @@ -187,6 +206,12 @@ class Instruction { // Needed for CHECK_EQ, DCHECK_EQ, etc. std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode); +// Keeps track of information needed to manipulate or call a method. +struct MethodDeclData { + size_t id; + ir::MethodDecl* decl; +}; + // Tools to help build methods and their bodies. class MethodBuilder { public: @@ -210,19 +235,74 @@ class MethodBuilder { // return-void void BuildReturn(); - void BuildReturn(Value src); + void BuildReturn(Value src, bool is_object = false); // const/4 void BuildConst4(Value target, int value); + void BuildConstString(Value target, const std::string& value); + template <typename... T> + void BuildNew(Value target, TypeDescriptor type, Prototype constructor, T... args); // TODO: add builders for more instructions private: void EncodeInstructions(); void EncodeInstruction(const Instruction& instruction); - void EncodeReturn(const Instruction& instruction); + + // Encodes a return instruction. For instructions with no return value, the opcode field is + // ignored. Otherwise, this specifies which return instruction will be used (return, + // return-object, etc.) + void EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode); + void EncodeMove(const Instruction& instruction); - void EncodeInvokeVirtual(const Instruction& instruction); + void EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode); void EncodeBranch(art::Instruction::Code op, const Instruction& instruction); + void EncodeNew(const Instruction& instruction); + + // Low-level instruction format encoding. See + // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of + // formats. + + inline void Encode10x(art::Instruction::Code opcode) { + // 00|op + buffer_.push_back(opcode); + } + + inline void Encode11x(art::Instruction::Code opcode, uint8_t a) { + // aa|op + buffer_.push_back((a << 8) | opcode); + } + + inline void Encode11n(art::Instruction::Code opcode, uint8_t a, int8_t b) { + // b|a|op + + // Make sure the fields are in bounds (4 bits for a, 4 bits for b). + CHECK_LT(a, 16); + CHECK_LE(-8, b); + CHECK_LT(b, 8); + + buffer_.push_back(((b & 0xf) << 12) | (a << 8) | opcode); + } + + inline void Encode21c(art::Instruction::Code opcode, uint8_t a, uint16_t b) { + // aa|op|bbbb + buffer_.push_back((a << 8) | opcode); + buffer_.push_back(b); + } + + inline void Encode35c(art::Instruction::Code opcode, size_t a, uint16_t b, uint8_t c, uint8_t d, + uint8_t e, uint8_t f, uint8_t g) { + // a|g|op|bbbb|f|e|d|c + + CHECK_LE(a, 5); + CHECK_LT(c, 16); + CHECK_LT(d, 16); + CHECK_LT(e, 16); + CHECK_LT(f, 16); + CHECK_LT(g, 16); + buffer_.push_back((a << 12) | (g << 8) | opcode); + buffer_.push_back(b); + buffer_.push_back((f << 12) | (e << 8) | (d << 4) | c); + } // Converts a register or parameter to its DEX register number. size_t RegisterValue(const Value& value) const; @@ -262,6 +342,10 @@ class MethodBuilder { }; std::vector<LabelData> labels_; + + // During encoding, keep track of the largest number of arguments needed, so we can use it for our + // outs count + size_t max_args_{0}; }; // A helper to build class definitions. @@ -281,12 +365,6 @@ class ClassBuilder { ir::Class* const class_; }; -// Keeps track of information needed to manipulate or call a method. -struct MethodDeclData { - size_t id; - ir::MethodDecl* decl; -}; - // Builds Dex files from scratch. class DexBuilder { public: @@ -355,6 +433,17 @@ class DexBuilder { std::map<Prototype, ir::Proto*> proto_map_; }; +template <typename... T> +void MethodBuilder::BuildNew(Value target, TypeDescriptor type, Prototype constructor, T... args) { + MethodDeclData constructor_data{dex_->GetOrDeclareMethod(type, "<init>", constructor)}; + // allocate the object + ir::Type* type_def = dex_->GetOrAddType(type.descriptor()); + AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kNew, target, Value::Type(type_def->orig_index))); + // call the constructor + AddInstruction(Instruction::InvokeDirect(constructor_data.id, /*dest=*/{}, target, args...)); +}; + } // namespace dex } // namespace startop diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java index 169c63374cb7..e20f3a9406c0 100644 --- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java @@ -50,6 +50,14 @@ public class DexBuilderTest { } @Test + public void returnInteger5() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnInteger5"); + Assert.assertEquals(5, method.invoke(null)); + } + + @Test public void returnParam() throws Exception { ClassLoader loader = loadDexFile("simple.dex"); Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); @@ -82,4 +90,38 @@ public class DexBuilderTest { Method method = clazz.getMethod("backwardsBranch"); Assert.assertEquals(2, method.invoke(null)); } + + @Test + public void returnNull() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnNull"); + Assert.assertEquals(null, method.invoke(null)); + } + + @Test + public void makeString() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("makeString"); + Assert.assertEquals("Hello, World!", method.invoke(null)); + } + + @Test + public void returnStringIfZeroAB() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnStringIfZeroAB", int.class); + Assert.assertEquals("a", method.invoke(null, 0)); + Assert.assertEquals("b", method.invoke(null, 1)); + } + + @Test + public void returnStringIfZeroBA() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnStringIfZeroBA", int.class); + Assert.assertEquals("b", method.invoke(null, 0)); + Assert.assertEquals("a", method.invoke(null, 1)); + } } diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc index c521bf2b8ccf..e2bf43bc1d0c 100644 --- a/startop/view_compiler/dex_testcase_generator.cc +++ b/startop/view_compiler/dex_testcase_generator.cc @@ -53,6 +53,19 @@ void GenerateSimpleTestCases(const string& outdir) { } return5.Encode(); + // int return5() { return 5; } + auto integer_type{TypeDescriptor::FromClassname("java.lang.Integer")}; + auto returnInteger5{cbuilder.CreateMethod("returnInteger5", Prototype{integer_type})}; + [&](MethodBuilder& method) { + Value five{method.MakeRegister()}; + method.BuildConst4(five, 5); + Value object{method.MakeRegister()}; + method.BuildNew( + object, integer_type, Prototype{TypeDescriptor::Void(), TypeDescriptor::Int()}, five); + method.BuildReturn(object, /*is_object=*/true); + }(returnInteger5); + returnInteger5.Encode(); + // // int returnParam(int x) { return x; } auto returnParam{cbuilder.CreateMethod("returnParam", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})}; @@ -138,6 +151,71 @@ void GenerateSimpleTestCases(const string& outdir) { }(backwardsBranch); backwardsBranch.Encode(); + // Test that we can make a null value. Basically: + // + // public static String returnNull() { return null; } + MethodBuilder returnNull{cbuilder.CreateMethod("returnNull", Prototype{string_type})}; + [](MethodBuilder& method) { + Value zero = method.MakeRegister(); + method.BuildConst4(zero, 0); + method.BuildReturn(zero, /*is_object=*/true); + }(returnNull); + returnNull.Encode(); + + // Test that we can make String literals. Basically: + // + // public static String makeString() { return "Hello, World!"; } + MethodBuilder makeString{cbuilder.CreateMethod("makeString", Prototype{string_type})}; + [](MethodBuilder& method) { + Value string = method.MakeRegister(); + method.BuildConstString(string, "Hello, World!"); + method.BuildReturn(string, /*is_object=*/true); + }(makeString); + makeString.Encode(); + + // Make sure strings are sorted correctly. + // + // int returnStringIfZeroAB(int x) { if (x == 0) { return "a"; } else { return "b"; } } + MethodBuilder returnStringIfZeroAB{ + cbuilder.CreateMethod("returnStringIfZeroAB", Prototype{string_type, TypeDescriptor::Int()})}; + [&](MethodBuilder& method) { + Value resultIfZero{method.MakeRegister()}; + Value else_target{method.MakeLabel()}; + method.AddInstruction(Instruction::OpWithArgs( + Instruction::Op::kBranchEqz, /*dest=*/{}, Value::Parameter(0), else_target)); + // else branch + method.BuildConstString(resultIfZero, "b"); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturnObject, /*dest=*/{}, resultIfZero)); + // then branch + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, else_target)); + method.BuildConstString(resultIfZero, "a"); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturnObject, /*dest=*/{}, resultIfZero)); + method.Encode(); + }(returnStringIfZeroAB); + // int returnStringIfZeroAB(int x) { if (x == 0) { return "b"; } else { return "a"; } } + MethodBuilder returnStringIfZeroBA{ + cbuilder.CreateMethod("returnStringIfZeroBA", Prototype{string_type, TypeDescriptor::Int()})}; + [&](MethodBuilder& method) { + Value resultIfZero{method.MakeRegister()}; + Value else_target{method.MakeLabel()}; + method.AddInstruction(Instruction::OpWithArgs( + Instruction::Op::kBranchEqz, /*dest=*/{}, Value::Parameter(0), else_target)); + // else branch + method.BuildConstString(resultIfZero, "a"); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturnObject, /*dest=*/{}, resultIfZero)); + // then branch + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, else_target)); + method.BuildConstString(resultIfZero, "b"); + method.AddInstruction( + Instruction::OpWithArgs(Instruction::Op::kReturnObject, /*dest=*/{}, resultIfZero)); + method.Encode(); + }(returnStringIfZeroBA); + slicer::MemView image{dex_file.CreateImage()}; std::ofstream out_file(outdir + "/simple.dex"); out_file.write(image.ptr<const char>(), image.size()); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index fbc54ae6a857..b74477043893 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1320,18 +1320,13 @@ public class CarrierConfigManager { public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection"; /** - * If carriers require differentiate un-provisioned status: cold sim or out of credit sim - * a package name and activity name can be provided to launch a supported carrier application - * that check the sim provisioning status - * The first element is the package name and the second element is the activity name - * of the provisioning app - * example: - * <item>com.google.android.carrierPackageName</item> - * <item>com.google.android.carrierPackageName.CarrierActivityName</item> - * The ComponentName of the carrier activity that can setup the device and activate with the - * network as part of the Setup Wizard flow. + * The flatten {@link android.content.ComponentName componentName} of the activity that can + * setup the device and activate with the network per carrier requirements. + * + * e.g, com.google.android.carrierPackageName/.CarrierActivityName * @hide */ + @SystemApi public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; /** diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index f5dff20eedf2..3c5ad84a62b0 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -21,16 +21,18 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; -import android.os.Message; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.IPhoneStateListener; import java.lang.ref.WeakReference; import java.util.List; +import java.util.concurrent.Executor; /** * A listener class for monitoring changes in specific telephony states @@ -231,34 +233,35 @@ public class PhoneStateListener { public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000; /** - * Listen for changes to the sim voice activation state - * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING - * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED - * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED - * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED - * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN - * {@more} - * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been - * fully activated + * Listen for changes to the sim voice activation state + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED + * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN + * {@more} + * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been + * fully activated * - * @see #onVoiceActivationStateChanged - * @hide + * @see #onVoiceActivationStateChanged + * @hide */ + @SystemApi public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000; /** - * Listen for changes to the sim data activation state - * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING - * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED - * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED - * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED - * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN - * {@more} - * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been - * fully activated + * Listen for changes to the sim data activation state + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING + * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED + * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED + * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN + * {@more} + * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been + * fully activated * - * @see #onDataActivationStateChanged - * @hide + * @see #onDataActivationStateChanged + * @hide */ public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000; @@ -320,7 +323,12 @@ public class PhoneStateListener { @UnsupportedAppUsage protected Integer mSubId; - private final Handler mHandler; + /** + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + @UnsupportedAppUsage + public final IPhoneStateListener callback; /** * Create a PhoneStateListener for the Phone with the default subscription. @@ -358,95 +366,27 @@ public class PhoneStateListener { */ @UnsupportedAppUsage public PhoneStateListener(Integer subId, Looper looper) { - if (DBG) log("ctor: subId=" + subId + " looper=" + looper); + this(subId, new HandlerExecutor(new Handler(looper))); + } + + /** + * Create a PhoneStateListener for the Phone using the specified Executor + * + * <p>Create a PhoneStateListener with a specified Executor for handling necessary callbacks. + * The Executor must not be null. + * + * @param executor a non-null Executor that will execute callbacks for the PhoneStateListener. + */ + public PhoneStateListener(@NonNull Executor executor) { + this(null, executor); + } + + private PhoneStateListener(Integer subId, Executor e) { + if (e == null) { + throw new IllegalArgumentException("PhoneStateListener Executor must be non-null"); + } mSubId = subId; - mHandler = new Handler(looper) { - public void handleMessage(Message msg) { - if (DBG) { - log("mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what) - + " msg=" + msg); - } - switch (msg.what) { - case LISTEN_SERVICE_STATE: - PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj); - break; - case LISTEN_SIGNAL_STRENGTH: - PhoneStateListener.this.onSignalStrengthChanged(msg.arg1); - break; - case LISTEN_MESSAGE_WAITING_INDICATOR: - PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0); - break; - case LISTEN_CALL_FORWARDING_INDICATOR: - PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0); - break; - case LISTEN_CELL_LOCATION: - PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj); - break; - case LISTEN_CALL_STATE: - PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj); - break; - case LISTEN_DATA_CONNECTION_STATE: - PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2); - PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1); - break; - case LISTEN_DATA_ACTIVITY: - PhoneStateListener.this.onDataActivity(msg.arg1); - break; - case LISTEN_SIGNAL_STRENGTHS: - PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj); - break; - case LISTEN_OTASP_CHANGED: - PhoneStateListener.this.onOtaspChanged(msg.arg1); - break; - case LISTEN_CELL_INFO: - PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj); - break; - case LISTEN_PRECISE_CALL_STATE: - PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj); - break; - case LISTEN_PRECISE_DATA_CONNECTION_STATE: - PhoneStateListener.this.onPreciseDataConnectionStateChanged( - (PreciseDataConnectionState)msg.obj); - break; - case LISTEN_DATA_CONNECTION_REAL_TIME_INFO: - PhoneStateListener.this.onDataConnectionRealTimeInfoChanged( - (DataConnectionRealTimeInfo)msg.obj); - break; - case LISTEN_SRVCC_STATE_CHANGED: - PhoneStateListener.this.onSrvccStateChanged((int) msg.obj); - break; - case LISTEN_VOICE_ACTIVATION_STATE: - PhoneStateListener.this.onVoiceActivationStateChanged((int)msg.obj); - break; - case LISTEN_DATA_ACTIVATION_STATE: - PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj); - break; - case LISTEN_USER_MOBILE_DATA_STATE: - PhoneStateListener.this.onUserMobileDataStateChanged((boolean)msg.obj); - break; - case LISTEN_OEM_HOOK_RAW_EVENT: - PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj); - break; - case LISTEN_CARRIER_NETWORK_CHANGE: - PhoneStateListener.this.onCarrierNetworkChange((boolean)msg.obj); - break; - case LISTEN_PHYSICAL_CHANNEL_CONFIGURATION: - PhoneStateListener.this.onPhysicalChannelConfigurationChanged( - (List<PhysicalChannelConfig>)msg.obj); - break; - case LISTEN_PHONE_CAPABILITY_CHANGE: - PhoneStateListener.this.onPhoneCapabilityChanged( - (PhoneCapability) msg.obj); - break; - case LISTEN_PREFERRED_DATA_SUBID_CHANGE: - PhoneStateListener.this.onPreferredDataSubIdChanged((int) msg.obj); - break; - case LISTEN_RADIO_POWER_STATE_CHANGED: - PhoneStateListener.this.onRadioPowerStateChanged((int) msg.obj); - break; - } - } - }; + callback = new IPhoneStateListenerStub(this, e); } /** @@ -630,8 +570,8 @@ public class PhoneStateListener { * @param state is the current SIM voice activation state * @hide */ - public void onVoiceActivationStateChanged(int state) { - + @SystemApi + public void onVoiceActivationStateChanged(@TelephonyManager.SimActivationState int state) { } /** @@ -639,8 +579,7 @@ public class PhoneStateListener { * @param state is the current SIM data activation state * @hide */ - public void onDataActivationStateChanged(int state) { - + public void onDataActivationStateChanged(@TelephonyManager.SimActivationState int state) { } /** @@ -735,127 +674,217 @@ public class PhoneStateListener { */ private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub { private WeakReference<PhoneStateListener> mPhoneStateListenerWeakRef; + private Executor mExecutor; - public IPhoneStateListenerStub(PhoneStateListener phoneStateListener) { + IPhoneStateListenerStub(PhoneStateListener phoneStateListener, Executor executor) { mPhoneStateListenerWeakRef = new WeakReference<PhoneStateListener>(phoneStateListener); - } - - private void send(int what, int arg1, int arg2, Object obj) { - PhoneStateListener listener = mPhoneStateListenerWeakRef.get(); - if (listener != null) { - Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget(); - } + mExecutor = executor; } public void onServiceStateChanged(ServiceState serviceState) { - send(LISTEN_SERVICE_STATE, 0, 0, serviceState); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onServiceStateChanged(serviceState))); } public void onSignalStrengthChanged(int asu) { - send(LISTEN_SIGNAL_STRENGTH, asu, 0, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onSignalStrengthChanged(asu))); } public void onMessageWaitingIndicatorChanged(boolean mwi) { - send(LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onMessageWaitingIndicatorChanged(mwi))); } public void onCallForwardingIndicatorChanged(boolean cfi) { - send(LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onCallForwardingIndicatorChanged(cfi))); } public void onCellLocationChanged(Bundle bundle) { CellLocation location = CellLocation.newFromBundle(bundle); - send(LISTEN_CELL_LOCATION, 0, 0, location); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onCellLocationChanged(location))); } public void onCallStateChanged(int state, String incomingNumber) { - send(LISTEN_CALL_STATE, state, 0, incomingNumber); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onCallStateChanged(state, incomingNumber))); } public void onDataConnectionStateChanged(int state, int networkType) { - send(LISTEN_DATA_CONNECTION_STATE, state, networkType, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onDataConnectionStateChanged(state, networkType))); } public void onDataActivity(int direction) { - send(LISTEN_DATA_ACTIVITY, direction, 0, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onDataActivity(direction))); } public void onSignalStrengthsChanged(SignalStrength signalStrength) { - send(LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onSignalStrengthsChanged(signalStrength))); } public void onOtaspChanged(int otaspMode) { - send(LISTEN_OTASP_CHANGED, otaspMode, 0, null); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onOtaspChanged(otaspMode))); } public void onCellInfoChanged(List<CellInfo> cellInfo) { - send(LISTEN_CELL_INFO, 0, 0, cellInfo); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onCellInfoChanged(cellInfo))); } public void onPreciseCallStateChanged(PreciseCallState callState) { - send(LISTEN_PRECISE_CALL_STATE, 0, 0, callState); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onPreciseCallStateChanged(callState))); } public void onPreciseDataConnectionStateChanged( PreciseDataConnectionState dataConnectionState) { - send(LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0, dataConnectionState); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onPreciseDataConnectionStateChanged(dataConnectionState))); } - public void onDataConnectionRealTimeInfoChanged( - DataConnectionRealTimeInfo dcRtInfo) { - send(LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo); + public void onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo dcRtInfo) { + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onDataConnectionRealTimeInfoChanged(dcRtInfo))); } public void onSrvccStateChanged(int state) { - send(LISTEN_SRVCC_STATE_CHANGED, 0, 0, state); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onSrvccStateChanged(state))); } public void onVoiceActivationStateChanged(int activationState) { - send(LISTEN_VOICE_ACTIVATION_STATE, 0, 0, activationState); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onVoiceActivationStateChanged(activationState))); } public void onDataActivationStateChanged(int activationState) { - send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onDataActivationStateChanged(activationState))); } public void onUserMobileDataStateChanged(boolean enabled) { - send(LISTEN_USER_MOBILE_DATA_STATE, 0, 0, enabled); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onUserMobileDataStateChanged(enabled))); } public void onOemHookRawEvent(byte[] rawData) { - send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onOemHookRawEvent(rawData))); } public void onCarrierNetworkChange(boolean active) { - send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onCarrierNetworkChange(active))); } public void onPhysicalChannelConfigurationChanged(List<PhysicalChannelConfig> configs) { - send(LISTEN_PHYSICAL_CHANNEL_CONFIGURATION, 0, 0, configs); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> psl.onPhysicalChannelConfigurationChanged(configs))); } public void onPhoneCapabilityChanged(PhoneCapability capability) { - send(LISTEN_PHONE_CAPABILITY_CHANGE, 0, 0, capability); - } + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; - public void onPreferredDataSubIdChanged(int subId) { - send(LISTEN_PREFERRED_DATA_SUBID_CHANGE, 0, 0, subId); + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onPhoneCapabilityChanged(capability))); } public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) { - send(LISTEN_RADIO_POWER_STATE_CHANGED, 0, 0, state); + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state))); } + public void onPreferredDataSubIdChanged(int subId) { + PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); + if (psl == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> psl.onPreferredDataSubIdChanged(subId))); + } } - /** - * @hide - */ - @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - @UnsupportedAppUsage - public final IPhoneStateListener callback = new IPhoneStateListenerStub(this); private void log(String s) { Rlog.d(LOG_TAG, s); } -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 31770ec1dce2..b5cbf3b0d466 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2290,7 +2290,7 @@ public class SubscriptionManager { * subscription dynamically in multi-SIM devices. * * @param subId which subscription is preferred to for cellular data. If it's - * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}, it means + * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means * it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()} * is used to determine which modem is preferred. * @hide diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index c9cf473bb482..e06c3728836c 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -292,7 +292,7 @@ public class ImsMmTelManager { * Create an instance of ImsManager for the subscription id specified. * * @param context - * @param subId The ID of the subscription that this ImsManager will use. + * @param subId The ID of the subscription that this ImsMmTelManager will use. * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() * @throws IllegalArgumentException if the subscription is invalid or * the subscription ID is not an active subscription. diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java new file mode 100644 index 000000000000..916e282f642e --- /dev/null +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -0,0 +1,252 @@ +/* + * 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.telephony.ims; + +import android.Manifest; +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.Binder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.telephony.SubscriptionManager; +import android.telephony.ims.aidl.IImsConfigCallback; +import android.telephony.ims.stub.ImsConfigImplBase; + +import com.android.internal.telephony.ITelephony; + +import java.util.concurrent.Executor; + +/** + * Manages IMS provisioning and configuration parameters, as well as callbacks for apps to listen + * to changes in these configurations. + * + * Note: IMS provisioning keys are defined per carrier or OEM using OMA-DM or other provisioning + * applications and may vary. + * @hide + */ +@SystemApi +public class ProvisioningManager { + + /** + * Callback for IMS provisioning changes. + */ + public static class Callback { + + private static class CallbackBinder extends IImsConfigCallback.Stub { + + private final Callback mLocalConfigurationCallback; + private Executor mExecutor; + + private CallbackBinder(Callback localConfigurationCallback) { + mLocalConfigurationCallback = localConfigurationCallback; + } + + @Override + public final void onIntConfigChanged(int item, int value) { + Binder.withCleanCallingIdentity(() -> + mExecutor.execute(() -> + mLocalConfigurationCallback.onProvisioningIntChanged(item, value))); + } + + @Override + public final void onStringConfigChanged(int item, String value) { + Binder.withCleanCallingIdentity(() -> + mExecutor.execute(() -> + mLocalConfigurationCallback.onProvisioningStringChanged(item, + value))); + } + + private void setExecutor(Executor executor) { + mExecutor = executor; + } + } + + private final CallbackBinder mBinder = new CallbackBinder(this); + + /** + * Called when a provisioning item has changed. + * @param item the IMS provisioning key constant, as defined by the OEM. + * @param value the new integer value of the IMS provisioning key. + */ + public void onProvisioningIntChanged(int item, int value) { + // Base Implementation + } + + /** + * Called when a provisioning item has changed. + * @param item the IMS provisioning key constant, as defined by the OEM. + * @param value the new String value of the IMS configuration constant. + */ + public void onProvisioningStringChanged(int item, String value) { + // Base Implementation + } + + /**@hide*/ + public final IImsConfigCallback getBinder() { + return mBinder; + } + + /**@hide*/ + public void setExecutor(Executor executor) { + mBinder.setExecutor(executor); + } + } + + private int mSubId; + + /** + * Create a new {@link ProvisioningManager} for the subscription specified. + * @param context The context that this manager will use. + * @param subId The ID of the subscription that this ProvisioningManager will use. + * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() + * @throws IllegalArgumentException if the subscription is invalid or + * the subscription ID is not an active subscription. + */ + public static ProvisioningManager createForSubscriptionId(Context context, int subId) { + if (!SubscriptionManager.isValidSubscriptionId(subId) + || !getSubscriptionManager(context).isActiveSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid subscription ID"); + } + + return new ProvisioningManager(subId); + } + + private ProvisioningManager(int subId) { + mSubId = subId; + } + + /** + * Register a new {@link Callback} to listen to changes to changes in + * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to + * Subscription changed events and call + * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a + * subscription is removed. + * @param executor The {@link Executor} to call the callback methods on + * @param callback The provisioning callbackto be registered. + * @see #unregisterProvisioningChangedCallback(Callback) + * @see SubscriptionManager.OnSubscriptionsChangedListener + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor, + @NonNull Callback callback) { + callback.setExecutor(executor); + try { + getITelephony().registerImsProvisioningChangedCallback(mSubId, + callback.getBinder()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Unregister an existing {@link Callback}. Ensure to call this method when cleaning + * up to avoid memory leaks or when the subscription is removed. + * @param callback The existing {@link Callback} to be removed. + * @see #registerProvisioningChangedCallback(Executor, Callback) + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public void unregisterProvisioningChangedCallback(@NonNull Callback callback) { + try { + getITelephony().unregisterImsProvisioningChangedCallback(mSubId, + callback.getBinder()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Query for the integer value associated with the provided key. + * @param key An integer that represents the provisioning key, which is defined by the OEM. + * @return an integer value for the provided key. + * @throws IllegalArgumentException if the key provided was invalid. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public int getProvisioningIntValue(int key) { + try { + return getITelephony().getImsProvisioningInt(mSubId, key); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Query for the String value associated with the provided key. + * @param key An integer that represents the provisioning key, which is defined by the OEM. + * @return a String value for the provided key, or {@code null} if the key doesn't exist. + * @throws IllegalArgumentException if the key provided was invalid. + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public String getProvisioningStringValue(int key) { + try { + return getITelephony().getImsProvisioningString(mSubId, key); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Set the integer value associated with the provided key. + * @param key An integer that represents the provisioning key, which is defined by the OEM. + * @param value a integer value for the provided key. + * @return the result of setting the configuration value. + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public @ImsConfigImplBase.SetConfigResult int setProvisioningIntValue(int key, int value) { + try { + return getITelephony().setImsProvisioningInt(mSubId, key, value); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + /** + * Set the String value associated with the provided key. + * + * @param key An integer that represents the provisioning key, which is defined by the OEM. + * @param value a String value for the provided key. + * @return the result of setting the configuration value. + */ + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public @ImsConfigImplBase.SetConfigResult int setProvisioningStringValue(int key, + String value) { + try { + return getITelephony().setImsProvisioningString(mSubId, key, value); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + + private static SubscriptionManager getSubscriptionManager(Context context) { + SubscriptionManager manager = context.getSystemService(SubscriptionManager.class); + if (manager == null) { + throw new RuntimeException("Could not find SubscriptionManager."); + } + return manager; + } + + private static ITelephony getITelephony() { + ITelephony binder = ITelephony.Stub.asInterface( + ServiceManager.getService(Context.TELEPHONY_SERVICE)); + if (binder == null) { + throw new RuntimeException("Could not find Telephony Service."); + } + return binder; + } +} diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index dcd7ea714f8c..321bfff40652 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -16,9 +16,9 @@ package android.telephony.ims.stub; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.content.Context; -import android.content.Intent; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.telephony.ims.aidl.IImsConfig; @@ -28,6 +28,8 @@ import android.util.Log; import com.android.ims.ImsConfig; import com.android.internal.annotations.VisibleForTesting; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.util.HashMap; @@ -215,41 +217,6 @@ public class ImsConfigImplBase { } /** - * Callback that the framework uses for receiving Configuration change updates. - * {@hide} - */ - public static class Callback extends IImsConfigCallback.Stub { - - @Override - public final void onIntConfigChanged(int item, int value) throws RemoteException { - onConfigChanged(item, value); - } - - @Override - public final void onStringConfigChanged(int item, String value) throws RemoteException { - onConfigChanged(item, value); - } - - /** - * Called when the IMS configuration has changed. - * @param item the IMS configuration key constant, as defined in ImsConfig. - * @param value the new integer value of the IMS configuration constant. - */ - public void onConfigChanged(int item, int value) { - // Base Implementation - } - - /** - * Called when the IMS configuration has changed. - * @param item the IMS configuration key constant, as defined in ImsConfig. - * @param value the new String value of the IMS configuration constant. - */ - public void onConfigChanged(int item, String value) { - // Base Implementation - } - } - - /** * The configuration requested resulted in an unknown result. This may happen if the * IMS configurations are unavailable. */ @@ -263,6 +230,16 @@ public class ImsConfigImplBase { */ public static final int CONFIG_RESULT_FAILED = 1; + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CONFIG_RESULT_", value = { + CONFIG_RESULT_SUCCESS, + CONFIG_RESULT_FAILED + }) + public @interface SetConfigResult {} + private final RemoteCallbackList<IImsConfigCallback> mCallbacks = new RemoteCallbackList<>(); ImsConfigStub mImsConfigStub; @@ -279,17 +256,16 @@ public class ImsConfigImplBase { } /** - * Adds a {@link Callback} to the list of callbacks notified when a value in the configuration - * changes. + * Adds a {@link android.telephony.ims.ProvisioningManager.Callback} to the list of callbacks + * notified when a value in the configuration changes. * @param c callback to add. */ private void addImsConfigCallback(IImsConfigCallback c) { mCallbacks.register(c); } /** - * Removes a {@link Callback} to the list of callbacks notified when a value in the - * configuration changes. - * + * Removes a {@link android.telephony.ims.ProvisioningManager.Callback} to the list of callbacks + * notified when a value in the configuration changes. * @param c callback to remove. */ private void removeImsConfigCallback(IImsConfigCallback c) { @@ -370,10 +346,9 @@ public class ImsConfigImplBase { * * @param item an integer key. * @param value an integer containing the configuration value. - * @return the result of setting the configuration value, defined as either - * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. + * @return the result of setting the configuration value. */ - public int setConfig(int item, int value) { + public @SetConfigResult int setConfig(int item, int value) { // Base Implementation - To be overridden. return CONFIG_RESULT_FAILED; } @@ -383,10 +358,9 @@ public class ImsConfigImplBase { * * @param item an integer key. * @param value a String containing the new configuration value. - * @return Result of setting the configuration value, defined as either - * {@link #CONFIG_RESULT_FAILED} or {@link #CONFIG_RESULT_SUCCESS}. + * @return Result of setting the configuration value. */ - public int setConfig(int item, String value) { + public @SetConfigResult int setConfig(int item, String value) { // Base Implementation - To be overridden. return CONFIG_RESULT_FAILED; } diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java index 90e9880bd03e..71a21743a449 100644 --- a/telephony/java/com/android/ims/ImsConfig.java +++ b/telephony/java/com/android/ims/ImsConfig.java @@ -16,12 +16,17 @@ package com.android.ims; -import android.content.Context; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.Looper; import android.os.RemoteException; import android.telephony.Rlog; import android.telephony.ims.ImsReasonInfo; +import android.telephony.ims.ProvisioningManager; import android.telephony.ims.aidl.IImsConfig; -import android.telephony.ims.stub.ImsConfigImplBase; +import android.telephony.ims.aidl.IImsConfigCallback; + +import java.util.concurrent.Executor; /** * Provides APIs to get/set the IMS service feature/capability/parameters. @@ -29,8 +34,10 @@ import android.telephony.ims.stub.ImsConfigImplBase; * 1) Items provisioned by the operator. * 2) Items configured by user. Mainly service feature class. * + * @deprecated Use {@link ProvisioningManager} to change these configurations in the ImsService. * @hide */ +@Deprecated public class ImsConfig { private static final String TAG = "ImsConfig"; private boolean DBG = true; @@ -46,7 +53,7 @@ public class ImsConfig { /** * Broadcast action: the configuration was changed - * @deprecated Use {@link ImsConfig#addConfigCallback(ImsConfigImplBase.Callback)} instead. + * @deprecated Use {@link android.telephony.ims.ProvisioningManager.Callback} instead. * @hide */ public static final String ACTION_IMS_CONFIG_CHANGED = @@ -673,13 +680,25 @@ public class ImsConfig { } /** - * Adds a {@link ImsConfigImplBase.Callback} to the ImsService to notify when a Configuration + * Adds a {@link ProvisioningManager.Callback} to the ImsService to notify when a Configuration * item has changed. * - * Make sure to call {@link #removeConfigCallback(ImsConfigImplBase.Callback)} when finished + * Make sure to call {@link #removeConfigCallback(IImsConfigCallback)} when finished * using this callback. */ - public void addConfigCallback(ImsConfigImplBase.Callback callback) throws ImsException { + public void addConfigCallback(ProvisioningManager.Callback callback) throws ImsException { + callback.setExecutor(getThreadExecutor()); + addConfigCallback(callback.getBinder()); + } + + /** + * Adds a {@link IImsConfigCallback} to the ImsService to notify when a Configuration + * item has changed. + * + * Make sure to call {@link #removeConfigCallback(IImsConfigCallback)} when finished + * using this callback. + */ + public void addConfigCallback(IImsConfigCallback callback) throws ImsException { if (DBG) Rlog.d(TAG, "addConfigCallback: " + callback); try { miConfig.addImsConfigCallback(callback); @@ -690,10 +709,9 @@ public class ImsConfig { } /** - * Removes a {@link ImsConfigImplBase.Callback} from the ImsService that was previously added - * by {@link #addConfigCallback(ImsConfigImplBase.Callback)}. + * Removes an existing {@link IImsConfigCallback} from the ImsService. */ - public void removeConfigCallback(ImsConfigImplBase.Callback callback) throws ImsException { + public void removeConfigCallback(IImsConfigCallback callback) throws ImsException { if (DBG) Rlog.d(TAG, "removeConfigCallback: " + callback); try { miConfig.removeImsConfigCallback(callback); @@ -709,4 +727,11 @@ public class ImsConfig { public boolean isBinderAlive() { return miConfig.asBinder().isBinderAlive(); } + + private Executor getThreadExecutor() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + return new HandlerExecutor(new Handler(Looper.myLooper())); + } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 3aaa32344e0b..85a9cf57ed4b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -40,6 +40,7 @@ import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; +import android.telephony.ims.aidl.IImsConfigCallback; import android.telephony.ims.aidl.IImsMmTelFeature; import android.telephony.ims.aidl.IImsRcsFeature; import android.telephony.ims.aidl.IImsRegistration; @@ -1569,24 +1570,24 @@ interface ITelephony { /** * Adds an IMS registration status callback for the subscription id specified. */ - oneway void addImsRegistrationCallback(int subId, IImsRegistrationCallback c, + void addImsRegistrationCallback(int subId, IImsRegistrationCallback c, String callingPackage); /** * Removes an existing IMS registration status callback for the subscription specified. */ - oneway void removeImsRegistrationCallback(int subId, IImsRegistrationCallback c, + void removeImsRegistrationCallback(int subId, IImsRegistrationCallback c, String callingPackage); /** * Adds an IMS MmTel capabilities callback for the subscription specified. */ - oneway void addMmTelCapabilityCallback(int subId, IImsCapabilityCallback c, + void addMmTelCapabilityCallback(int subId, IImsCapabilityCallback c, String callingPackage); /** * Removes an existing IMS MmTel capabilities callback for the subscription specified. */ - oneway void removeMmTelCapabilityCallback(int subId, IImsCapabilityCallback c, + void removeMmTelCapabilityCallback(int subId, IImsCapabilityCallback c, String callingPackage); /** @@ -1691,4 +1692,34 @@ interface ITelephony { * Return a list of certs in hex string from loaded carrier privileges access rules. */ List<String> getCertsFromCarrierPrivilegeAccessRules(int subId); + + /** + * Register an IMS provisioning change callback with Telephony. + */ + void registerImsProvisioningChangedCallback(int subId, IImsConfigCallback callback); + + /** + * unregister an existing IMS provisioning change callback. + */ + void unregisterImsProvisioningChangedCallback(int subId, IImsConfigCallback callback); + + /** + * Return an integer containing the provisioning value for the specified provisioning key. + */ + int getImsProvisioningInt(int subId, int key); + + /** + * return a String containing the provisioning value for the provisioning key specified. + */ + String getImsProvisioningString(int subId, int key); + + /** + * Set the integer provisioning value for the provisioning key specified. + */ + int setImsProvisioningInt(int subId, int key, int value); + + /** + * Set the String provisioning value for the provisioning key specified. + */ + int setImsProvisioningString(int subId, int key, String value); } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 954b51f02820..7919074c5a2b 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -4256,27 +4256,21 @@ public class WifiManager { /** * @return true if this device supports WPA3-Personal SAE - * @hide */ - @SystemApi public boolean isWpa3SaeSupported() { return isFeatureSupported(WIFI_FEATURE_WPA3_SAE); } /** * @return true if this device supports WPA3-Enterprise Suite-B-192 - * @hide */ - @SystemApi public boolean isWpa3SuiteBSupported() { return isFeatureSupported(WIFI_FEATURE_WPA3_SUITE_B); } /** * @return true if this device supports Wi-Fi Enhanced Open (OWE) - * @hide */ - @SystemApi public boolean isOweSupported() { return isFeatureSupported(WIFI_FEATURE_OWE); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index e6892bea4595..f58a006278d2 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -491,6 +491,17 @@ public class WifiP2pManager { /** @hide */ public static final int FACTORY_RESET_SUCCEEDED = BASE + 84; + /** @hide */ + public static final int REQUEST_ONGOING_PEER_CONFIG = BASE + 85; + /** @hide */ + public static final int RESPONSE_ONGOING_PEER_CONFIG = BASE + 86; + /** @hide */ + public static final int SET_ONGOING_PEER_CONFIG = BASE + 87; + /** @hide */ + public static final int SET_ONGOING_PEER_CONFIG_FAILED = BASE + 88; + /** @hide */ + public static final int SET_ONGOING_PEER_CONFIG_SUCCEEDED = BASE + 89; + /** * Create a new WifiP2pManager instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -680,6 +691,18 @@ public class WifiP2pManager { } /** + * Interface for callback invocation when ongoing peer info is available + * @hide + */ + public interface OngoingPeerInfoListener { + /** + * The requested ongoing WifiP2pConfig is available + * @param peerConfig WifiP2pConfig for current connecting session + */ + void onOngoingPeerAvailable(WifiP2pConfig peerConfig); + } + + /** * A channel that connects the application to the Wifi p2p framework. * Most p2p operations require a Channel as an argument. An instance of Channel is obtained * by doing a call on {@link #initialize} @@ -787,6 +810,7 @@ public class WifiP2pManager { case SET_CHANNEL_FAILED: case REPORT_NFC_HANDOVER_FAILED: case FACTORY_RESET_FAILED: + case SET_ONGOING_PEER_CONFIG_FAILED: if (listener != null) { ((ActionListener) listener).onFailure(message.arg1); } @@ -814,6 +838,7 @@ public class WifiP2pManager { case SET_CHANNEL_SUCCEEDED: case REPORT_NFC_HANDOVER_SUCCEEDED: case FACTORY_RESET_SUCCEEDED: + case SET_ONGOING_PEER_CONFIG_SUCCEEDED: if (listener != null) { ((ActionListener) listener).onSuccess(); } @@ -857,6 +882,13 @@ public class WifiP2pManager { .onHandoverMessageAvailable(handoverMessage); } break; + case RESPONSE_ONGOING_PEER_CONFIG: + WifiP2pConfig peerConfig = (WifiP2pConfig) message.obj; + if (listener != null) { + ((OngoingPeerInfoListener) listener) + .onOngoingPeerAvailable(peerConfig); + } + break; default: Log.d(TAG, "Ignored " + message); break; @@ -1536,6 +1568,7 @@ public class WifiP2pManager { /** * Removes all saved p2p groups. + * * @param c is the channel created at {@link #initialize}. * @param listener for callback on success or failure. Can be null. * @hide @@ -1550,4 +1583,37 @@ public class WifiP2pManager { callingPackage); } + /** + * Request saved WifiP2pConfig which used for an ongoing peer connection + * + * @param c is the channel created at {@link #initialize} + * @param listener for callback when ongoing peer config updated. Can't be null. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void requestOngoingPeerConfig(@NonNull Channel c, + @NonNull OngoingPeerInfoListener listener) { + checkChannel(c); + c.mAsyncChannel.sendMessage(REQUEST_ONGOING_PEER_CONFIG, + Binder.getCallingUid(), c.putListener(listener)); + } + + /** + * Set saved WifiP2pConfig which used for an ongoing peer connection + * + * @param c is the channel created at {@link #initialize} + * @param config used for change an ongoing peer connection + * @param listener for callback when ongoing peer config updated. Can be null. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + public void setOngoingPeerConfig(@NonNull Channel c, @NonNull WifiP2pConfig config, + @Nullable ActionListener listener) { + checkChannel(c); + checkP2pConfig(config); + c.mAsyncChannel.sendMessage(SET_ONGOING_PEER_CONFIG, 0, + c.putListener(listener), config); + } } |