Merge "Import translations. DO NOT MERGE"
diff --git a/Android.mk b/Android.mk
index 7ca8358..10d11f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -656,6 +656,10 @@
# Check comment when you are updating the API
update-api: doc-comment-check-docs
+# Generate API diffs as part of docs builds
+docs: offline-sdk-referenceonly-diff
+docs: offline-system-sdk-referenceonly-diff
+
# ==== static html in the sdk ==================================
include $(CLEAR_VARS)
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 87cde03..337aeaa 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -161,6 +161,7 @@
tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
tests/MetricsManager_test.cpp \
+ tests/StatsLogProcessor_test.cpp \
tests/UidMap_test.cpp \
tests/condition/CombinationConditionTracker_test.cpp \
tests/condition/SimpleConditionTracker_test.cpp \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index c291647..2df0c90 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -86,9 +86,7 @@
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(msg);
- // TODO: THIS CHECK FAILS BECAUSE ONCE UIDMAP SIZE EXCEEDS LIMIT, DROPPING METRICS DATA
- // DOESN'T HELP. FIX THIS.
- // flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
+ flushIfNecessary(msg.GetTimestampNs(), pair.first, *(pair.second));
}
// Hard-coded logic to update the isolated uid's in the uid-map.
@@ -217,23 +215,32 @@
mLastBroadcastTimes.erase(key);
}
-void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
- const ConfigKey& key,
- const unique_ptr<MetricsManager>& metricsManager) {
+void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs, const ConfigKey& key,
+ MetricsManager& metricsManager) {
std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
- size_t totalBytes = metricsManager->byteSize() + mUidMap->getBytesUsed();
- // TODO: Find a way to test that the dropping and broadcasts are sent when memory is exceeded.
- if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
+ auto lastCheckTime = mLastByteSizeTimes.find(key);
+ if (lastCheckTime != mLastByteSizeTimes.end()) {
+ if (timestampNs - lastCheckTime->second < StatsdStats::kMinByteSizeCheckPeriodNs) {
+ return;
+ }
+ }
+
+ // We suspect that the byteSize() computation is expensive, so we set a rate limit.
+ size_t totalBytes = metricsManager.byteSize();
+ mLastByteSizeTimes[key] = timestampNs;
+ if (totalBytes >
+ StatsdStats::kMaxMetricsBytesPerConfig) { // Too late. We need to start clearing data.
// We ignore the return value so we force each metric producer to clear its contents.
- metricsManager->onDumpReport();
+ metricsManager.onDumpReport();
StatsdStats::getInstance().noteDataDropped(key);
VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
- } else if (totalBytes >
- .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
- auto lastFlushNs = mLastBroadcastTimes.find(key);
- if (lastFlushNs != mLastBroadcastTimes.end()) {
- if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) {
+ } else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
+ // Send broadcast so that receivers can pull data.
+ auto lastBroadcastTime = mLastBroadcastTimes.find(key);
+ if (lastBroadcastTime != mLastBroadcastTimes.end()) {
+ if (timestampNs - lastBroadcastTime->second < StatsdStats::kMinBroadcastPeriodNs) {
+ VLOG("StatsD would've sent a broadcast but the rate limit stopped us.");
return;
}
}
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index e9ac015..a4df23a 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -60,29 +60,25 @@
std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
+ // Tracks when we last checked the bytes consumed for each config key.
+ std::unordered_map<ConfigKey, long> mLastByteSizeTimes;
+
sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid.
sp<AnomalyMonitor> mAnomalyMonitor;
- /* Max *serialized* size of the logs kept in memory before flushing through binder call.
- Proto lite does not implement the SpaceUsed() function which gives the in memory byte size.
- So we cap memory usage by limiting the serialized size. Note that protobuf's in memory size
- is higher than its serialized size.
- */
- static const size_t kMaxSerializedBytes = 16 * 1024;
-
/* Check if we should send a broadcast if approaching memory limits and if we're over, we
* actually delete the data. */
- void flushIfNecessary(uint64_t timestampNs,
- const ConfigKey& key,
- const unique_ptr<MetricsManager>& metricsManager);
+ void flushIfNecessary(uint64_t timestampNs, const ConfigKey& key,
+ MetricsManager& metricsManager);
// Function used to send a broadcast so that receiver for the config key can call getData
// to retrieve the stored data.
std::function<void(const ConfigKey& key)> mSendBroadcast;
- /* Minimum period between two broadcasts in nanoseconds. Currently set to 60 seconds. */
- static const unsigned long long kMinBroadcastPeriod = 60 * NS_PER_SEC;
+ FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
+ FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
+ FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index fa7fe0c..dc12efb 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -72,7 +72,7 @@
// ======================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
+ : mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
{
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index bdae1ef..e434f65 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -46,6 +46,10 @@
StatsService(const sp<Looper>& handlerLooper);
virtual ~StatsService();
+ /** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
+ // TODO: Consider making this configurable. And choose a good number.
+ const uint32_t MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS = 5;
+
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 2b2bcfc..4912648 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "anomaly/AnomalyMonitor.h"
+#include "guardrail/StatsdStats.h"
namespace android {
namespace os {
@@ -76,10 +77,7 @@
if (!wasPresent) return;
if (mPq.empty()) {
if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
- mRegisteredAlarmTimeSec = 0;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelAnomalyAlarm();
- }
+ cancelRegisteredAlarmTime_l();
return;
}
uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
@@ -106,10 +104,7 @@
if (!oldAlarms.empty()) {
if (mPq.empty()) {
if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
- mRegisteredAlarmTimeSec = 0;
- if (mStatsCompanionService != nullptr) {
- mStatsCompanionService->cancelAnomalyAlarm();
- }
+ cancelRegisteredAlarmTime_l();
} else {
// Always update the registered alarm in this case (unlike remove()).
updateRegisteredAlarmTime_l(mPq.top()->timestampSec);
@@ -123,6 +118,16 @@
mRegisteredAlarmTimeSec = timestampSec;
if (mStatsCompanionService != nullptr) {
mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+ }
+}
+
+void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
+ if (DEBUG) ALOGD("Cancelling reg alarm.");
+ mRegisteredAlarmTimeSec = 0;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
}
}
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index e19c469..7acc7904 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -138,6 +138,12 @@
*/
void updateRegisteredAlarmTime_l(uint32_t timestampSec);
+ /**
+ * Cancels the alarm registered with StatsCompanionService.
+ * Also correspondingly sets mRegisteredAlarmTimeSec to 0.
+ */
+ void cancelRegisteredAlarmTime_l();
+
/** Converts uint32 timestamp in seconds to a Java long in msec. */
int64_t secToMs(uint32_t timeSec);
};
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7bacb44..e8b4083 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -18,6 +18,7 @@
#include "Log.h"
#include "AnomalyTracker.h"
+#include "guardrail/StatsdStats.h"
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
@@ -31,8 +32,9 @@
// TODO: Separate DurationAnomalyTracker as a separate subclass and let each MetricProducer
// decide and let which one it wants.
// TODO: Get rid of bucketNumbers, and return to the original circular array method.
-AnomalyTracker::AnomalyTracker(const Alert& alert)
+AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
: mAlert(alert),
+ mConfigKey(configKey),
mNumOfPastBuckets(mAlert.number_of_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.number_of_buckets() <= 0) {
@@ -220,6 +222,8 @@
} else {
ALOGW("An anomaly has occurred! (But informing incidentd not requested.)");
}
+
+ StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.name());
}
void AnomalyTracker::declareAnomalyIfAlarmExpired(const HashableDimensionKey& dimensionKey,
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index 49e8323..874add2 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -18,6 +18,7 @@
#include <gtest/gtest_prod.h>
#include "AnomalyMonitor.h"
+#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include "stats_util.h" // HashableDimensionKey and DimToValMap
@@ -35,7 +36,7 @@
// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
public:
- AnomalyTracker(const Alert& alert);
+ AnomalyTracker(const Alert& alert, const ConfigKey& configKey);
virtual ~AnomalyTracker();
@@ -107,9 +108,13 @@
protected:
void flushPastBuckets(const int64_t& currBucketNum);
+
// statsd_config.proto Alert message that defines this tracker.
const Alert mAlert;
+ // A reference to the Alert's config key.
+ const ConfigKey& mConfigKey;
+
// Number of past buckets. One less than the total number of buckets needed
// for the anomaly detection (since the current bucket is not in the past).
int mNumOfPastBuckets;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 2957457..b02b9da 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -41,11 +41,9 @@
const int FIELD_ID_BEGIN_TIME = 1;
const int FIELD_ID_END_TIME = 2;
const int FIELD_ID_CONFIG_STATS = 3;
-const int FIELD_ID_MATCHER_STATS = 4;
-const int FIELD_ID_CONDITION_STATS = 5;
-const int FIELD_ID_METRIC_STATS = 6;
const int FIELD_ID_ATOM_STATS = 7;
const int FIELD_ID_UIDMAP_STATS = 8;
+const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
const int FIELD_ID_MATCHER_STATS_NAME = 1;
const int FIELD_ID_MATCHER_STATS_COUNT = 2;
@@ -59,6 +57,8 @@
const int FIELD_ID_ATOM_STATS_TAG = 1;
const int FIELD_ID_ATOM_STATS_COUNT = 2;
+const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
+
// TODO: add stats for pulled atoms.
StatsdStats::StatsdStats() {
mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1);
@@ -101,11 +101,12 @@
if (it != mConfigStats.end()) {
int32_t nowTimeSec = time(nullptr);
it->second.set_deletion_time_sec(nowTimeSec);
- // Add condition stats, metrics stats, matcher stats
- addSubStatsToConfig(key, it->second);
+ // Add condition stats, metrics stats, matcher stats, alert stats
+ addSubStatsToConfigLocked(key, it->second);
// Remove them after they are added to the config stats.
mMatcherStats.erase(key);
mMetricsStats.erase(key);
+ mAlertStats.erase(key);
mConditionStats.erase(key);
mIceBox.push_back(it->second);
mConfigStats.erase(it);
@@ -219,6 +220,17 @@
matcherStats[name]++;
}
+void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const string& name) {
+ lock_guard<std::mutex> lock(mLock);
+ auto& alertStats = mAlertStats[key];
+ alertStats[name]++;
+}
+
+void StatsdStats::noteRegisteredAnomalyAlarmChanged() {
+ lock_guard<std::mutex> lock(mLock);
+ mAnomalyAlarmRegisteredStats++;
+}
+
void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) {
lock_guard<std::mutex> lock(mLock);
@@ -246,6 +258,8 @@
mConditionStats.clear();
mMetricsStats.clear();
std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0);
+ mAlertStats.clear();
+ mAnomalyAlarmRegisteredStats = 0;
mMatcherStats.clear();
for (auto& config : mConfigStats) {
config.second.clear_broadcast_sent_time_sec();
@@ -254,10 +268,11 @@
config.second.clear_matcher_stats();
config.second.clear_condition_stats();
config.second.clear_metric_stats();
+ config.second.clear_alert_stats();
}
}
-void StatsdStats::addSubStatsToConfig(const ConfigKey& key,
+void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key,
StatsdStatsReport_ConfigStats& configStats) {
// Add matcher stats
if (mMatcherStats.find(key) != mMatcherStats.end()) {
@@ -289,6 +304,16 @@
VLOG("metrics %s max output tuple size %d", stats.first.c_str(), stats.second);
}
}
+ // Add anomaly detection alert stats
+ if (mAlertStats.find(key) != mAlertStats.end()) {
+ const auto& alertStats = mAlertStats[key];
+ for (const auto& stats : alertStats) {
+ auto output = configStats.add_alert_stats();
+ output->set_name(stats.first);
+ output->set_declared_times(stats.second);
+ VLOG("alert %s declared %d times", stats.first.c_str(), stats.second);
+ }
+ }
}
void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) {
@@ -358,7 +383,7 @@
}
}
- addSubStatsToConfig(pair.first, configStats);
+ addSubStatsToConfigLocked(pair.first, configStats);
const int numBytes = configStats.ByteSize();
vector<char> buffer(numBytes);
@@ -370,6 +395,7 @@
configStats.clear_matcher_stats();
configStats.clear_condition_stats();
configStats.clear_metric_stats();
+ configStats.clear_alert_stats();
}
VLOG("********Atom stats***********");
@@ -386,6 +412,15 @@
}
}
+ if (mAnomalyAlarmRegisteredStats > 0) {
+ VLOG("********AnomalyAlarmStats stats***********");
+ long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS);
+ proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED,
+ mAnomalyAlarmRegisteredStats);
+ proto.end(token);
+ VLOG("Anomaly alarm registrations: %d", mAnomalyAlarmRegisteredStats);
+ }
+
const int numBytes = mUidMapStats.ByteSize();
vector<char> buffer(numBytes);
mUidMapStats.SerializeToArray(&buffer[0], numBytes);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index d6f6566..4cf168e 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -19,6 +19,7 @@
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include <gtest/gtest_prod.h>
+#include <log/log_time.h>
#include <mutex>
#include <string>
#include <vector>
@@ -45,10 +46,20 @@
const static int kMaxTimestampCount = 20;
+ // Max memory allowed for storing metrics per configuration. When this limit is approached,
+ // statsd will send a broadcast so that the client can fetch the data and clear this memory.
+ static const size_t kMaxMetricsBytesPerConfig = 128 * 1024;
+
// Cap the UID map's memory usage to this. This should be fairly high since the UID information
// is critical for understanding the metrics.
const static size_t kMaxBytesUsedUidMap = 50 * 1024;
+ /* Minimum period between two broadcasts in nanoseconds. */
+ static const unsigned long long kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
+
+ /* Min period between two checks of byte size per config key in nanoseconds. */
+ static const unsigned long long kMinByteSizeCheckPeriodNs = 10 * NS_PER_SEC;
+
/**
* Report a new config has been received and report the static stats about the config.
*
@@ -112,11 +123,24 @@
void noteMatcherMatched(const ConfigKey& key, const std::string& name);
/**
+ * Report that an anomaly detection alert has been declared.
+ *
+ * [key]: The config key that this alert belongs to.
+ * [name]: The name of the alert.
+ */
+ void noteAnomalyDeclared(const ConfigKey& key, const std::string& name);
+
+ /**
* Report an atom event has been logged.
*/
void noteAtomLogged(int atomId, int32_t timeSec);
/**
+ * Report that statsd modified the anomaly alarm registered with StatsCompanionService.
+ */
+ void noteRegisteredAnomalyAlarmChanged();
+
+ /**
* Records the number of snapshot and delta entries that are being dropped from the uid map.
*/
void noteUidMapDropped(int snapshots, int deltas);
@@ -174,6 +198,14 @@
// This is a vector, not a map because it will be accessed A LOT -- for each stats log.
std::vector<int> mPushedAtomStats;
+ // Stores the number of times statsd modified the anomaly alarm registered with
+ // StatsCompanionService.
+ int mAnomalyAlarmRegisteredStats = 0;
+
+ // Stores the number of times an anomaly detection alert has been declared
+ // (per config, per alert name).
+ std::map<const ConfigKey, std::map<const std::string, int>> mAlertStats;
+
// Stores how many times a matcher have been matched.
std::map<const ConfigKey, std::map<const std::string, int>> mMatcherStats;
@@ -181,7 +213,8 @@
void resetInternalLocked();
- void addSubStatsToConfig(const ConfigKey& key, StatsdStatsReport_ConfigStats& configStats);
+ void addSubStatsToConfigLocked(const ConfigKey& key,
+ StatsdStatsReport_ConfigStats& configStats);
void noteDataDropped(const ConfigKey& key, int32_t timeSec);
@@ -195,6 +228,7 @@
FRIEND_TEST(StatsdStatsTest, TestSubStats);
FRIEND_TEST(StatsdStatsTest, TestAtomLog);
FRIEND_TEST(StatsdStatsTest, TestTimestampThreshold);
+ FRIEND_TEST(StatsdStatsTest, TestAnomalyMonitor);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index fd484c2..cedea30 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -111,7 +111,7 @@
return nullptr;
}
// TODO: return a DurationAnomalyTracker (which should sublclass AnomalyTracker)
- return new AnomalyTracker(alert);
+ return new AnomalyTracker(alert, mConfigKey);
}
void DurationMetricProducer::startNewProtoOutputStreamLocked(long long startTime) {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index e7e84ab..adeb3cd 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -94,7 +94,7 @@
}
virtual sp<AnomalyTracker> createAnomalyTracker(const Alert &alert) {
- return new AnomalyTracker(alert);
+ return new AnomalyTracker(alert, mConfigKey);
}
void addAnomalyTracker(sp<AnomalyTracker> tracker) {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 4e6a0ce..86c4733 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -36,7 +36,7 @@
public:
MetricsManager(const ConfigKey& configKey, const StatsdConfig& config);
- ~MetricsManager();
+ virtual ~MetricsManager();
// Return whether the configuration is valid.
bool isConfigValid() const;
@@ -52,11 +52,11 @@
void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor);
// Config source owner can call onDumpReport() to get all the metrics collected.
- std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
+ virtual std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
// Computes the total byte size of all metrics managed by a single config source.
// Does not change the state.
- size_t byteSize();
+ virtual size_t byteSize();
private:
const ConfigKey mConfigKey;
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 60d9a3d..f8b91fe 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -193,6 +193,11 @@
optional int32 max_tuple_counts = 2;
}
+ message AlertStats {
+ optional string name = 1;
+ optional int32 declared_times = 2;
+ }
+
message ConfigStats {
optional int32 uid = 1;
optional string name = 2;
@@ -210,6 +215,7 @@
repeated MatcherStats matcher_stats = 13;
repeated ConditionStats condition_stats = 14;
repeated MetricStats metric_stats = 15;
+ repeated AlertStats alert_stats = 16;
}
repeated ConfigStats config_stats = 3;
@@ -229,4 +235,9 @@
optional int32 dropped_changes = 5;
}
optional UidMapStats uidmap_stats = 8;
+
+ message AnomalyAlarmStats {
+ optional int32 alarms_registered = 1;
+ }
+ optional AnomalyAlarmStats anomaly_alarm_stats = 9;
}
\ No newline at end of file
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
new file mode 100644
index 0000000..ff04d95
--- /dev/null
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2017 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.
+
+#include "StatsLogProcessor.h"
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "packages/UidMap.h"
+#include "statslog.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+
+using namespace android;
+using namespace testing;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+/**
+ * Mock MetricsManager (ByteSize() is called).
+ */
+class MockMetricsManager : public MetricsManager {
+public:
+ MockMetricsManager() : MetricsManager(ConfigKey(1, "key"), StatsdConfig()) {
+ }
+
+ MOCK_METHOD0(byteSize, size_t());
+ MOCK_METHOD0(onDumpReport, std::vector<std::unique_ptr<std::vector<uint8_t>>>());
+};
+
+TEST(StatsLogProcessorTest, TestRateLimitByteSize) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ // Construct the processor with a dummy sendBroadcast function that does nothing.
+ StatsLogProcessor p(m, anomalyMonitor, [](const ConfigKey& key) {});
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ // Expect only the first flush to trigger a check for byte size since the last two are
+ // rate-limited.
+ EXPECT_CALL(mockMetricsManager, byteSize()).Times(1);
+ p.flushIfNecessary(99, key, mockMetricsManager);
+ p.flushIfNecessary(100, key, mockMetricsManager);
+ p.flushIfNecessary(101, key, mockMetricsManager);
+}
+
+TEST(StatsLogProcessorTest, TestRateLimitBroadcast) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ int broadcastCount = 0;
+ StatsLogProcessor p(m, anomalyMonitor,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ EXPECT_CALL(mockMetricsManager, byteSize())
+ .Times(2)
+ .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * .95)));
+
+ // Expect only one broadcast despite always returning a size that should trigger broadcast.
+ p.flushIfNecessary(1, key, mockMetricsManager);
+ EXPECT_EQ(1, broadcastCount);
+
+ // This next call to flush should not trigger a broadcast.
+ p.mLastByteSizeTimes.clear(); // Force another check for byte size.
+ p.flushIfNecessary(2, key, mockMetricsManager);
+ EXPECT_EQ(1, broadcastCount);
+}
+
+TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) {
+ sp<UidMap> m = new UidMap();
+ sp<AnomalyMonitor> anomalyMonitor;
+ int broadcastCount = 0;
+ StatsLogProcessor p(m, anomalyMonitor,
+ [&broadcastCount](const ConfigKey& key) { broadcastCount++; });
+
+ MockMetricsManager mockMetricsManager;
+
+ ConfigKey key(100, "key");
+ EXPECT_CALL(mockMetricsManager, byteSize())
+ .Times(1)
+ .WillRepeatedly(Return(int(StatsdStats::kMaxMetricsBytesPerConfig * 1.2)));
+
+ EXPECT_CALL(mockMetricsManager, onDumpReport()).Times(1);
+
+ // Expect to call the onDumpReport and skip the broadcast.
+ p.flushIfNecessary(1, key, mockMetricsManager);
+ EXPECT_EQ(0, broadcastCount);
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 65c2a05..f385763 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -30,6 +30,8 @@
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
void AddValueToBucket(const std::vector<std::pair<string, long>>& key_value_pair_list,
std::shared_ptr<DimToValMap> bucket) {
for (auto itr = key_value_pair_list.begin(); itr != key_value_pair_list.end(); itr++) {
@@ -51,7 +53,7 @@
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket0 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
int64_t eventTimestamp0 = 10;
@@ -168,7 +170,7 @@
alert.set_refractory_period_secs(2 * bucketSizeNs / NS_PER_SEC);
alert.set_trigger_if_sum_gt(2);
- AnomalyTracker anomalyTracker(alert);
+ AnomalyTracker anomalyTracker(alert, kConfigKey);
std::shared_ptr<DimToValMap> bucket9 = MockBucket({{"a", 1}, {"b", 2}, {"c", 1}});
std::shared_ptr<DimToValMap> bucket16 = MockBucket({{"b", 4}});
diff --git a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
index a8193dd..9fed4f8 100644
--- a/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
+++ b/cmds/statsd/tests/guardrail/StatsdStats_test.cpp
@@ -118,6 +118,10 @@
stats.noteMetricDimensionSize(key, "metric1", 201);
stats.noteMetricDimensionSize(key, "metric1", 202);
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert1");
+ stats.noteAnomalyDeclared(key, "alert2");
+
// broadcast-> 2
stats.noteBroadcastSent(key);
stats.noteBroadcastSent(key);
@@ -142,7 +146,6 @@
EXPECT_EQ(3, configReport.dump_report_time_sec_size());
EXPECT_EQ(2, configReport.matcher_stats_size());
-
// matcher1 is the first in the list
if (!configReport.matcher_stats(0).name().compare("matcher1")) {
EXPECT_EQ(2, configReport.matcher_stats(0).matched_times());
@@ -157,6 +160,13 @@
EXPECT_EQ("matcher1", configReport.matcher_stats(1).name());
}
+ EXPECT_EQ(2, configReport.alert_stats_size());
+ bool alert1first = !configReport.alert_stats(0).name().compare("alert1");
+ EXPECT_EQ("alert1", configReport.alert_stats(alert1first ? 0 : 1).name());
+ EXPECT_EQ(2, configReport.alert_stats(alert1first ? 0 : 1).declared_times());
+ EXPECT_EQ("alert2", configReport.alert_stats(alert1first ? 1 : 0).name());
+ EXPECT_EQ(1, configReport.alert_stats(alert1first ? 1 : 0).declared_times());
+
EXPECT_EQ(1, configReport.condition_stats_size());
EXPECT_EQ("condition1", configReport.condition_stats(0).name());
EXPECT_EQ(250, configReport.condition_stats(0).max_tuple_counts());
@@ -169,6 +179,7 @@
stats.noteMatcherMatched(key, "matcher99");
stats.noteConditionDimensionSize(key, "condition99", 300);
stats.noteMetricDimensionSize(key, "metric99", 270);
+ stats.noteAnomalyDeclared(key, "alert99");
// now the config stats should only contain the stats about the new event.
stats.dumpStats(&output, false);
@@ -187,6 +198,10 @@
EXPECT_EQ(1, configReport2.metric_stats_size());
EXPECT_EQ("metric99", configReport2.metric_stats(0).name());
EXPECT_EQ(270, configReport2.metric_stats(0).max_tuple_counts());
+
+ EXPECT_EQ(1, configReport2.alert_stats_size());
+ EXPECT_EQ("alert99", configReport2.alert_stats(0).name());
+ EXPECT_EQ(1, configReport2.alert_stats(0).declared_times());
}
TEST(StatsdStatsTest, TestAtomLog) {
@@ -224,6 +239,21 @@
EXPECT_TRUE(sensorAtomGood);
}
+
+TEST(StatsdStatsTest, TestAnomalyMonitor) {
+ StatsdStats stats;
+ stats.noteRegisteredAnomalyAlarmChanged();
+ stats.noteRegisteredAnomalyAlarmChanged();
+
+ vector<uint8_t> output;
+ stats.dumpStats(&output, false);
+ StatsdStatsReport report;
+ bool good = report.ParseFromArray(&output[0], output.size());
+ EXPECT_TRUE(good);
+
+ EXPECT_EQ(2, report.anomaly_alarm_stats().alarms_registered());
+}
+
TEST(StatsdStatsTest, TestTimestampThreshold) {
StatsdStats stats;
vector<int32_t> timestamps;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 9b94099..d973ba1 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -196,7 +196,7 @@
int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
CountMetric metric;
metric.set_name("1");
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index ed13db2..59475d2 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -33,6 +33,8 @@
namespace os {
namespace statsd {
+const ConfigKey kConfigKey(0, "test");
+
TEST(GaugeMetricProducerTest, TestWithCondition) {
int64_t bucketStartTimeNs = 10000000000;
int64_t bucketSizeNs = 60 * 1000 * 1000 * 1000LL;
@@ -148,7 +150,7 @@
alert.set_metric_name("1");
alert.set_trigger_if_sum_gt(25);
alert.set_number_of_buckets(2);
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
gaugeProducer.addAnomalyTracker(anomalyTracker);
std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(1, bucketStartTimeNs + 1);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 1adcc11..4e5e0d6 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -208,7 +208,7 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index fa7b9a7..99d3e05 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -269,7 +269,7 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
bucketSizeNs, {anomalyTracker});
@@ -331,7 +331,7 @@
uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1;
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
- sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
+ sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert, kConfigKey);
OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 392387a..61b90e1 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -4,6 +4,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
@@ -214,4 +215,22 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Start VR Input method for the packageName in {@link ComponentName}.
+ * This method notifies InputMethodManagerService to use VR IME instead of
+ * regular phone IME.
+ * @param componentName ComponentName of a VR InputMethod that should be set as selected
+ * input by InputMethodManagerService.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public void setVrInputMethod(ComponentName componentName) {
+ try {
+ mService.setVrInputMethod(componentName);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 1241f23..838d315 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -678,33 +678,6 @@
}
/**
- * Get battery usage hint for Bluetooth Headset service.
- * This is a monotonically increasing integer. Wraps to 0 at
- * Integer.MAX_INT, and at boot.
- * Current implementation returns the number of AT commands handled since
- * boot. This is a good indicator for spammy headset/handsfree units that
- * can keep the device awake by polling for cellular status updates. As a
- * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
- *
- * @param device the bluetooth headset.
- * @return monotonically increasing battery usage hint, or a negative error code on error
- * @hide
- */
- public int getBatteryUsageHint(BluetoothDevice device) {
- if (VDBG) log("getBatteryUsageHint()");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled() && isValidDevice(device)) {
- try {
- return service.getBatteryUsageHint(device);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return -1;
- }
-
- /**
* Indicates if current platform supports voice dialing over bluetooth SCO.
*
* @return true if voice dialing over bluetooth is supported, false otherwise.
@@ -716,49 +689,6 @@
}
/**
- * Accept the incoming connection.
- * Note: This is an internal function and shouldn't be exposed
- *
- * @hide
- */
- public boolean acceptIncomingConnect(BluetoothDevice device) {
- if (DBG) log("acceptIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.acceptIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * Reject the incoming connection.
- *
- * @hide
- */
- public boolean rejectIncomingConnect(BluetoothDevice device) {
- if (DBG) log("rejectIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null) {
- try {
- return service.rejectIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* Get the current audio state of the Headset.
* Note: This is an internal function and shouldn't be exposed
*
@@ -1053,50 +983,6 @@
}
/**
- * enable WBS codec setting.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean enableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.enableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * disable WBS codec settting. It set NBS codec.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean disableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.disableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* check if in-band ringing is supported for this platform.
*
* @return true if in-band ringing is supported false if in-band ringing is not supported
@@ -1107,30 +993,6 @@
com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support);
}
- /**
- * Send Headset the BIND response from AG to report change in the status of the
- * HF indicators to the headset
- *
- * @param indId Assigned Number of the indicator (defined by SIG)
- * @param indStatus possible values- false-Indicator is disabled, no value changes shall be
- * sent for this indicator true-Indicator is enabled, value changes may be sent for this
- * indicator
- * @hide
- */
- public void bindResponse(int indId, boolean indStatus) {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- service.bindResponse(indId, indStatus);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
-
private final IBluetoothProfileServiceConnection mConnection =
new IBluetoothProfileServiceConnection.Stub() {
@Override
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index bfee2797..4a00486 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -31,36 +31,33 @@
import java.util.List;
/**
- * Provides the public APIs to control the Bluetooth HID Device
- * profile.
+ * Provides the public APIs to control the Bluetooth HID Device profile.
*
- * BluetoothHidDevice is a proxy object for controlling the Bluetooth HID
- * Device Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHidDevice proxy object.
+ * <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
+ * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDevice implements BluetoothProfile {
private static final String TAG = BluetoothHidDevice.class.getSimpleName();
/**
- * Intent used to broadcast the change in connection state of the Input
- * Host profile.
+ * Intent used to broadcast the change in connection state of the Input Host profile.
*
* <p>This intent will have 3 extras:
+ *
* <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * <li>{@link #EXTRA_STATE} - The current state of the profile.
+ * <li>{@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
+ * <li>{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
* </ul>
*
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
+ * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
+ * #STATE_DISCONNECTING}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
@@ -69,9 +66,8 @@
/**
* Constants representing device subclass.
*
- * @see #registerApp
- * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
*/
public static final byte SUBCLASS1_NONE = (byte) 0x00;
public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
@@ -110,8 +106,8 @@
public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
/**
- * Constants representing protocol mode used set by host. Default is always
- * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ * Constants representing protocol mode used set by host. Default is always {@link
+ * #PROTOCOL_REPORT_MODE} unless notified otherwise.
*
* @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
*/
@@ -126,8 +122,8 @@
private BluetoothAdapter mAdapter;
- private static class BluetoothHidDeviceCallbackWrapper extends
- IBluetoothHidDeviceCallback.Stub {
+ private static class BluetoothHidDeviceCallbackWrapper
+ extends IBluetoothHidDeviceCallback.Stub {
private BluetoothHidDeviceCallback mCallback;
@@ -184,13 +180,11 @@
doBind();
}
} catch (IllegalStateException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
} catch (SecurityException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
}
} else {
Log.d(TAG, "Unbinding service...");
@@ -200,23 +194,25 @@
}
};
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "onServiceConnected()");
- mService = IBluetoothHidDevice.Stub.asInterface(service);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
- BluetoothHidDevice.this);
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "onServiceDisconnected()");
- mService = null;
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
- }
- }
- };
+ private final ServiceConnection mConnection =
+ new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected()");
+ mService = IBluetoothHidDevice.Stub.asInterface(service);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(
+ BluetoothProfile.HID_DEVICE, BluetoothHidDevice.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected()");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+ }
+ }
+ };
BluetoothHidDevice(Context context, ServiceListener listener) {
Log.v(TAG, "BluetoothHidDevice");
@@ -280,9 +276,7 @@
mServiceListener = null;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getConnectedDevices() {
Log.v(TAG, "getConnectedDevices()");
@@ -301,9 +295,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
@@ -322,9 +314,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public int getConnectionState(BluetoothDevice device) {
Log.v(TAG, "getConnectionState(): device=" + device);
@@ -344,33 +334,31 @@
}
/**
- * Registers application to be used for HID device. Connections to HID
- * Device are only possible when application is registered. Only one
- * application can be registered at time. When no longer used, application
- * should be unregistered using
- * {@link #unregisterApp()}.
- * The registration status should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
- * to the return value of this method.
+ * Registers application to be used for HID device. Connections to HID Device are only possible
+ * when application is registered. Only one application can be registered at one time. When an
+ * application is registered, the HID Host service will be disabled until it is unregistered.
+ * When no longer used, application should be unregistered using {@link #unregisterApp()}. The
+ * registration status should be tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
+ * the return value of this method.
*
- * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
- * The HID Device SDP record is required.
- * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
- * The Incoming QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings.
- * The Outgoing QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
+ * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
+ * Device SDP record is required.
+ * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The
+ * Incoming QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
+ * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
+ * Outgoing QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
* @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be
- * sent.
- * The BluetoothHidDeviceCallback object is required.
+ * sent. The BluetoothHidDeviceCallback object is required.
* @return true if the command is successfully sent; otherwise false.
*/
public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
BluetoothHidDeviceCallback callback) {
Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos
- + " callback=" + callback);
+ + " callback=" + callback);
boolean result = false;
@@ -395,14 +383,13 @@
}
/**
- * Unregisters application. Active connection will be disconnected and no
- * new connections will be allowed until registered again using
- * {@link #registerApp
+ * Unregisters application. Active connection will be disconnected and no new connections will
+ * be allowed until registered again using {@link #registerApp
* (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)}
- * The registration status should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
- * to the return value of this method.
+ * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should
+ * be tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to
+ * the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
@@ -429,7 +416,7 @@
* Sends report to remote host using interrupt channel.
*
* @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
- * descriptor.
+ * descriptor.
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
@@ -451,8 +438,8 @@
}
/**
- * Sends report to remote host as reply for GET_REPORT request from
- * {@link BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
+ * Sends report to remote host as reply for GET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
*
* @param type Report Type, as in request.
* @param id Report Id, as in request.
@@ -479,8 +466,8 @@
}
/**
- * Sends error handshake message as reply for invalid SET_REPORT request
- * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
+ * Sends error handshake message as reply for invalid SET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
*
* @param error Error to be sent for SET_REPORT via HANDSHAKE.
* @return true if the command is successfully sent; otherwise false.
@@ -508,6 +495,7 @@
* Sends Virtual Cable Unplug to currently connected host.
*
* @return
+ * {@hide}
*/
public boolean unplug(BluetoothDevice device) {
Log.v(TAG, "unplug(): device=" + device);
@@ -529,11 +517,11 @@
}
/**
- * Initiates connection to host which is currently paired with this device.
- * If the application is not registered, #connect(BluetoothDevice) will fail.
- * The connection state should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
- * to the return value of this method.
+ * Initiates connection to host which is currently paired with this device. If the application
+ * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
+ * tracked by the application by handling callback from
+ * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to
+ * the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
@@ -557,10 +545,9 @@
}
/**
- * Disconnects from currently connected host.
- * The connection state should be tracked by the application by handling callback from
- * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related
- * to the return value of this method.
+ * Disconnects from currently connected host. The connection state should be tracked by the
+ * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged.
+ * The connection state is not related to the return value of this method.
*
* @return true if the command is successfully sent; otherwise false.
*/
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index 881ae98..4609d52 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -20,15 +20,14 @@
import android.os.Parcelable;
/**
- * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device
- * application.
+ * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework will update the L2CAP QoS settings for the
- * app during registration.
+ * <p>The BluetoothHidDevice framework will update the L2CAP QoS settings for the app during
+ * registration.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
@@ -46,13 +45,12 @@
public static final int MAX = (int) 0xffffffff;
/**
- * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
- * The QoS Settings is optional.
- * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
- * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
- * https://www.bluetooth.com/specifications/profiles-overview
- * </a>
- * Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+ * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
+ * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder. {@see <a
+ * href="https://www.bluetooth.com/specifications/profiles-overview">
+ * https://www.bluetooth.com/specifications/profiles-overview </a> Bluetooth HID Specfication
+ * v1.1.1 Section 5.2 and Appendix D }
+ *
* @param serviceType L2CAP service type
* @param tokenRate L2CAP token rate
* @param tokenBucketSize L2CAP token bucket size
@@ -123,13 +121,11 @@
/** @return an int array representation of this instance */
public int[] toArray() {
return new int[] {
- serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+ serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
};
}
- /**
- * A helper to build the BluetoothHidDeviceAppQosSettings object.
- */
+ /** A helper to build the BluetoothHidDeviceAppQosSettings object. */
public static class Builder {
// Optional parameters - initialized to default values
private int mServiceType = SERVICE_BEST_EFFORT;
@@ -141,8 +137,9 @@
/**
* Set the service type.
+ *
* @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT,
- * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
+ * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
* @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
*/
public Builder serviceType(int val) {
@@ -151,6 +148,7 @@
}
/**
* Set the token rate.
+ *
* @param val token rate
* @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
*/
@@ -161,6 +159,7 @@
/**
* Set the bucket size.
+ *
* @param val bucket size
* @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
*/
@@ -171,6 +170,7 @@
/**
* Set the peak bandwidth.
+ *
* @param val peak bandwidth
* @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
*/
@@ -180,6 +180,7 @@
}
/**
* Set the latency.
+ *
* @param val latency
* @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
*/
@@ -190,6 +191,7 @@
/**
* Set the delay variation.
+ *
* @param val delay variation
* @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
*/
@@ -200,6 +202,7 @@
/**
* Build the BluetoothHidDeviceAppQosSettings object.
+ *
* @return BluetoothHidDeviceAppQosSettings object with current settings.
*/
public BluetoothHidDeviceAppQosSettings build() {
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 4669637..2da64e5 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -22,16 +22,14 @@
import java.util.Arrays;
/**
- * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
- * HID Device application.
+ * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework adds the SDP record during app
- * registration, so that the Android device can be discovered as a Bluetooth
- * HID Device.
+ * <p>The BluetoothHidDevice framework adds the SDP record during app registration, so that the
+ * Android device can be discovered as a Bluetooth HID Device.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
@@ -43,18 +41,19 @@
/**
* Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+ *
* @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
* @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
* @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
- * @param subclass Subclass of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param subclass Subclass of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
- * @param descriptors Descriptors of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param descriptors Descriptors of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
*/
- public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
- byte subclass, byte[] descriptors) {
+ public BluetoothHidDeviceAppSdpSettings(
+ String name, String description, String provider, byte subclass, byte[] descriptors) {
this.name = name;
this.description = description;
this.provider = provider;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index dc6f9fa..6ed1965 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -19,46 +19,43 @@
import android.util.Log;
/**
- * The template class that applications use to call callback functions on
- * events from the HID host. Callback functions are wrapped in this class and
- * registered to the Android system during app registration.
+ * The template class that applications use to call callback functions on events from the HID host.
+ * Callback functions are wrapped in this class and registered to the Android system during app
+ * registration.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public abstract class BluetoothHidDeviceCallback {
private static final String TAG = "BluetoothHidDevCallback";
/**
- * Callback called when application registration state changes. Usually it's
- * called due to either
- * {@link BluetoothHidDevice#registerApp
- * (String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
- * or
- * {@link BluetoothHidDevice#unregisterApp()}
- * , but can be also unsolicited in case e.g. Bluetooth was turned off in
- * which case application is unregistered automatically.
+ * Callback called when application registration state changes. Usually it's called due to
+ * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
+ * BluetoothHidDeviceCallback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
+ * unsolicited in case e.g. Bluetooth was turned off in which case application is unregistered
+ * automatically.
*
* @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has
- * Virtual Cable established with device. Only valid when application is registered, can be
- * <code>null</code>.
+ * Virtual Cable established with device. Only valid when application is registered, can be
+ * <code>null</code>.
* @param registered <code>true</code> if application is registered, <code>false</code>
- * otherwise.
+ * otherwise.
*/
public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered="
- + registered);
+ Log.d(TAG,
+ "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered=" + registered);
}
/**
- * Callback called when connection state with remote host was changed.
- * Application can assume than Virtual Cable is established when called with
- * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>.
+ * Callback called when connection state with remote host was changed. Application can assume
+ * than Virtual Cable is established when called with {@link BluetoothProfile#STATE_CONNECTED}
+ * <code>state</code>.
*
* @param device {@link BluetoothDevice} object representing host device which connection state
- * was changed.
+ * was changed.
* @param state Connection state as defined in {@link BluetoothProfile}.
*/
public void onConnectionStateChanged(BluetoothDevice device, int state) {
@@ -66,14 +63,14 @@
}
/**
- * Callback called when GET_REPORT is received from remote host. Should be
- * replied by application using
- * {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, byte[])}.
+ * Callback called when GET_REPORT is received from remote host. Should be replied by
+ * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
+ * byte[])}.
*
* @param type Requested Report Type.
* @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
* @param bufferSize Requested buffer size, application shall respond with at least given number
- * of bytes.
+ * of bytes.
*/
public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
@@ -81,9 +78,9 @@
}
/**
- * Callback called when SET_REPORT is received from remote host. In case
- * received data are invalid, application shall respond with
- * {@link BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
+ * Callback called when SET_REPORT is received from remote host. In case received data are
+ * invalid, application shall respond with {@link
+ * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
*
* @param type Report Type.
* @param id Report Id.
@@ -94,10 +91,9 @@
}
/**
- * Callback called when SET_PROTOCOL is received from remote host.
- * Application shall use this information to send only reports valid for
- * given protocol mode. By default,
- * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
+ * Callback called when SET_PROTOCOL is received from remote host. Application shall use this
+ * information to send only reports valid for given protocol mode. By default, {@link
+ * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
*
* @param protocol Protocol Mode.
*/
@@ -106,9 +102,8 @@
}
/**
- * Callback called when report data is received over interrupt channel.
- * Report Type is assumed to be
- * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ * Callback called when report data is received over interrupt channel. Report Type is assumed
+ * to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
*
* @param reportId Report Id.
* @param data Report data.
@@ -118,10 +113,8 @@
}
/**
- * Callback called when Virtual Cable is removed. This can be either due to
- * {@link BluetoothHidDevice#unplug(BluetoothDevice)} or request from remote
- * side. After this callback is received connection will be disconnected
- * automatically.
+ * Callback called when Virtual Cable is removed. After this callback is
+ * received connection will be disconnected automatically.
*/
public void onVirtualCableUnplug(BluetoothDevice device) {
Log.d(TAG, "onVirtualCableUnplug: device=" + device);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 9e54e23..d09ba0b 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -265,6 +265,14 @@
/**
* Include pinned shortcuts in the result.
+ *
+ * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
+ * user owns on the launcher (or by other launchers, in case the user has multiple), use
+ * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
+ *
+ * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
+ * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
+ * flag to get own pinned shortcuts.
*/
public static final int FLAG_MATCH_PINNED = 1 << 1;
@@ -285,8 +293,15 @@
* Include all pinned shortcuts by any launchers, not just by the caller,
* in the result.
*
- * The caller must be the selected assistant app to use this flag, or have the system
+ * <p>The caller must be the selected assistant app to use this flag, or have the system
* {@code ACCESS_SHORTCUTS} permission.
+ *
+ * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
+ * user owns on the launcher (or by other launchers, in case the user has multiple), use
+ * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
+ *
+ * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
+ * then this flag will be ignored.
*/
public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index 5af49d4..6be9b9e 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -16,20 +16,19 @@
package android.content.res;
-import org.xmlpull.v1.XmlPullParser;
-
import android.util.AttributeSet;
+import org.xmlpull.v1.XmlPullParser;
+
/**
* The XML parsing interface returned for an XML resource. This is a standard
- * XmlPullParser interface, as well as an extended AttributeSet interface and
- * an additional close() method on this interface for the client to indicate
- * when it is done reading the resource.
+ * {@link XmlPullParser} interface but also extends {@link AttributeSet} and
+ * adds an additional {@link #close()} method for the client to indicate when
+ * it is done reading the resource.
*/
public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
/**
- * Close this interface to the resource. Calls on the interface are no
- * longer value after this call.
+ * Close this parser. Calls on the interface are no longer valid after this call.
*/
public void close();
}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a7a3df7..cb11d0f 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2729,13 +2729,13 @@
//
/**
- * <p>Scene change is not detected within AF regions.</p>
+ * <p>Scene change is not detected within the AF region(s).</p>
* @see CaptureResult#CONTROL_AF_SCENE_CHANGE
*/
public static final int CONTROL_AF_SCENE_CHANGE_NOT_DETECTED = 0;
/**
- * <p>Scene change is detected within AF regions.</p>
+ * <p>Scene change is detected within the AF region(s).</p>
* @see CaptureResult#CONTROL_AF_SCENE_CHANGE
*/
public static final int CONTROL_AF_SCENE_CHANGE_DETECTED = 1;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index b7d7f7d..6d7b06f 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2185,10 +2185,16 @@
new Key<Boolean>("android.control.enableZsl", boolean.class);
/**
- * <p>Whether scene change is detected within AF regions.</p>
- * <p>When AF detects a scene change within current AF regions, it will be set to DETECTED. Otherwise,
- * it will be set to NOT_DETECTED. This value will remain NOT_DETECTED if afMode is AF_MODE_OFF or
- * AF_MODE_EDOF.</p>
+ * <p>Whether a significant scene change is detected within the currently-set AF
+ * region(s).</p>
+ * <p>When the camera focus routine detects a change in the scene it is looking at,
+ * such as a large shift in camera viewpoint, significant motion in the scene, or a
+ * significant illumination change, this value will be set to DETECTED for a single capture
+ * result. Otherwise the value will be NOT_DETECTED. The threshold for detection is similar
+ * to what would trigger a new passive focus scan to begin in CONTINUOUS autofocus modes.</p>
+ * <p>afSceneChange may be DETECTED only if afMode is AF_MODE_CONTINUOUS_VIDEO or
+ * AF_MODE_CONTINUOUS_PICTURE. In other AF modes, afSceneChange must be NOT_DETECTED.</p>
+ * <p>This key will be available if the camera device advertises this key via {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED NOT_DETECTED}</li>
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 7285fb4..f7acfc5 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -17,6 +17,7 @@
package android.service.vr;
import android.app.Vr2dDisplayProperties;
+import android.content.ComponentName;
import android.service.vr.IVrStateCallbacks;
import android.service.vr.IPersistentVrStateCallbacks;
@@ -109,5 +110,13 @@
* @param standy True if the device is entering standby, false if it's exiting standby.
*/
void setStandbyEnabled(boolean standby);
+
+ /**
+ * Start VR Input method for the given packageName in {@param componentName}.
+ * This method notifies InputMethodManagerService to use VR IME instead of
+ * regular phone IME.
+ */
+ void setVrInputMethod(in ComponentName componentName);
+
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 92d1de8..4d96733 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -697,6 +697,19 @@
}
}
+ /**
+ * Returns a list of VR InputMethod currently installed.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS)
+ public List<InputMethodInfo> getVrInputMethodList() {
+ try {
+ return mService.getVrInputMethodList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
public List<InputMethodInfo> getEnabledInputMethodList() {
try {
return mService.getEnabledInputMethodList();
diff --git a/core/java/android/view/inputmethod/InputMethodManagerInternal.java b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
index 77df4e3..e13813e 100644
--- a/core/java/android/view/inputmethod/InputMethodManagerInternal.java
+++ b/core/java/android/view/inputmethod/InputMethodManagerInternal.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import android.content.ComponentName;
+
/**
* Input method manager local system service interface.
*
@@ -37,4 +39,9 @@
* Hides the current input method, if visible.
*/
void hideCurrentInputMethod();
+
+ /**
+ * Switches to VR InputMethod defined in the packageName of {@param componentName}.
+ */
+ void startVrInputMethodNoCheck(ComponentName componentName);
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 3e231d0..57efae6 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -836,7 +836,6 @@
private final Resources mRes;
private final ContentResolver mResolver;
private final HashMap<String, InputMethodInfo> mMethodMap;
- private final ArrayList<InputMethodInfo> mMethodList;
/**
* On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
@@ -906,7 +905,6 @@
mRes = res;
mResolver = resolver;
mMethodMap = methodMap;
- mMethodList = methodList;
switchCurrentUser(userId, copyOnWrite);
}
@@ -1087,7 +1085,7 @@
final ArrayList<InputMethodInfo> res = new ArrayList<>();
for (Pair<String, ArrayList<String>> ims: imsList) {
InputMethodInfo info = mMethodMap.get(ims.first);
- if (info != null) {
+ if (info != null && !info.isVrOnly()) {
res.add(info);
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index b979807..ca8624d 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -36,6 +36,7 @@
interface IInputMethodManager {
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getInputMethodList();
+ List<InputMethodInfo> getVrInputMethodList();
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getEnabledInputMethodList();
List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 26023b4..e013553 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -21,6 +21,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
@@ -203,6 +204,11 @@
public void onViewAdded(View child) {
super.onViewAdded(child);
clearMeasureOrder();
+ // For some reason ripples + notification actions seem to be an unhappy combination
+ // b/69474443 so just turn them off for now.
+ if (child.getBackground() instanceof RippleDrawable) {
+ ((RippleDrawable)child.getBackground()).setForceSoftware(true);
+ }
}
@Override
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 0228edb..915fe9d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -200,6 +200,7 @@
message WindowContainerProto {
optional ConfigurationContainerProto configuration_container = 1;
optional int32 orientation = 2;
+ optional bool visible = 3;
}
/* represents ConfigurationContainer */
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ef8f6af..5ccaf5c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4490,7 +4490,9 @@
<string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
<string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
<string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
+ <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
+ <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6da24bd..f659360 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1048,9 +1048,11 @@
<java-symbol type="string" name="stk_cc_ss_to_dial" />
<java-symbol type="string" name="stk_cc_ss_to_ss" />
<java-symbol type="string" name="stk_cc_ss_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ss_to_dial_video" />
<java-symbol type="string" name="stk_cc_ussd_to_dial" />
<java-symbol type="string" name="stk_cc_ussd_to_ss" />
<java-symbol type="string" name="stk_cc_ussd_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ussd_to_dial_video" />
<java-symbol type="string" name="safe_media_volume_warning" />
<java-symbol type="string" name="media_route_status_scanning" />
<java-symbol type="string" name="media_route_status_connecting" />
diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk
index d4c1e70..a825581 100644
--- a/packages/EasterEgg/Android.mk
+++ b/packages/EasterEgg/Android.mk
@@ -2,17 +2,23 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+
LOCAL_STATIC_JAVA_LIBRARIES := \
+ jsr305
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-v4 \
android-support-v13 \
android-support-dynamic-animation \
android-support-v7-recyclerview \
android-support-v7-preference \
android-support-v7-appcompat \
- android-support-v14-preference \
- jsr305
+ android-support-v14-preference
+
+LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := EasterEgg
LOCAL_CERTIFICATE := platform
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index 49c5467..9d1c4ca 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -21,6 +21,10 @@
LOCAL_STATIC_ANDROID_LIBRARIES += \
android-support-v4 \
apptoolkit-lifecycle-runtime \
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-v7-appcompat \
+ android-support-v14-preference \
SettingsLib
else
LOCAL_RESOURCE_DIR += $(call my-dir)/res
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
index a966e82..3a03644 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java
@@ -75,23 +75,27 @@
* Note: the returned list serves as a read-only list. If tiles needs to be added or removed
* from the actual tiles list, it should be done through {@link #addTile}, {@link #removeTile}.
*/
- public List<Tile> getTiles() {
- return Collections.unmodifiableList(mTiles);
+ public synchronized List<Tile> getTiles() {
+ final List<Tile> result = new ArrayList<>(mTiles.size());
+ for (Tile tile : mTiles) {
+ result.add(tile);
+ }
+ return result;
}
- public void addTile(Tile tile) {
+ public synchronized void addTile(Tile tile) {
mTiles.add(tile);
}
- public void addTile(int n, Tile tile) {
+ public synchronized void addTile(int n, Tile tile) {
mTiles.add(n, tile);
}
- public void removeTile(Tile tile) {
+ public synchronized void removeTile(Tile tile) {
mTiles.remove(tile);
}
- public void removeTile(int n) {
+ public synchronized void removeTile(int n) {
mTiles.remove(n);
}
@@ -103,7 +107,7 @@
return mTiles.get(n);
}
- public boolean containsComponent(ComponentName component) {
+ public synchronized boolean containsComponent(ComponentName component) {
for (Tile tile : mTiles) {
if (TextUtils.equals(tile.intent.getComponent().getClassName(),
component.getClassName())) {
@@ -129,7 +133,7 @@
/**
* Sort priority value and package name for tiles in this category.
*/
- public void sortTiles(String skipPackageName) {
+ public synchronized void sortTiles(String skipPackageName) {
// Sort mTiles based on [priority, package within priority]
Collections.sort(mTiles, (tile1, tile2) -> {
final String package1 = tile1.intent.getComponent().getPackageName();
diff --git a/packages/SettingsLib/tests/integ/Android.mk b/packages/SettingsLib/tests/integ/Android.mk
index 7ace048..3c8c8ac 100644
--- a/packages/SettingsLib/tests/integ/Android.mk
+++ b/packages/SettingsLib/tests/integ/Android.mk
@@ -27,6 +27,8 @@
LOCAL_PACKAGE_NAME := SettingsLibTests
LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_USE_AAPT2 := true
+
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
espresso-core \
diff --git a/packages/SettingsLib/tests/robotests/Android.mk b/packages/SettingsLib/tests/robotests/Android.mk
index bc1a834..2738027 100644
--- a/packages/SettingsLib/tests/robotests/Android.mk
+++ b/packages/SettingsLib/tests/robotests/Android.mk
@@ -28,6 +28,8 @@
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res
+LOCAL_USE_AAPT2 := true
+
include frameworks/base/packages/SettingsLib/common.mk
include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4f6fcb9..70d13e6 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -59,8 +59,8 @@
<string name="kg_wrong_password" msgid="4580683060277329277">"Palavra-passe incorreta"</string>
<string name="kg_wrong_pin" msgid="4785660766909463466">"PIN incorreto"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="4368805541257003755">
- <item quantity="one">Tente novamente dentro de 1 segundo.</item>
<item quantity="other">Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos.</item>
+ <item quantity="one">Tente novamente dentro de 1 segundo.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="5547646893001491340">"Desenhe o seu padrão"</string>
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"Introduza o PIN do cartão SIM."</string>
@@ -97,13 +97,13 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem êxito, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"Código PIN do cartão SIM incorreto. Tem de contactar o seu operador para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
- <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
<item quantity="other">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas.</item>
+ <item quantity="one">Código PIN do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de precisar de contactar o seu operador para desbloquear o dispositivo.</item>
</plurals>
<string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"Cartão SIM inutilizável. Contacte o seu operador."</string>
<plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
- <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
<item quantity="other">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável.</item>
+ <item quantity="one">Código PUK do cartão SIM incorreto. Tem mais <xliff:g id="NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável.</item>
</plurals>
<string name="kg_password_pin_failed" msgid="8769990811451236223">"Falha ao introduzir o PIN do cartão SIM!"</string>
<string name="kg_password_puk_failed" msgid="1331621440873439974">"Falha ao introduzir o PUK do cartão SIM!"</string>
@@ -123,16 +123,16 @@
<string name="kg_prompt_reason_device_admin" msgid="3452168247888906179">"Dispositivo bloqueado pelo gestor"</string>
<string name="kg_prompt_reason_user_request" msgid="8236951765212462286">"O dispositivo foi bloqueado manualmente"</string>
<plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="71299470072448533">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o padrão.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o padrão.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o padrão.</item>
</plurals>
<plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="34586942088144385">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o PIN.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme o PIN.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme o PIN.</item>
</plurals>
<plurals name="kg_prompt_reason_time_password" formatted="false" msgid="257297696215346527">
- <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a palavra-passe.</item>
<item quantity="other">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_1">%d</xliff:g> horas. Confirme a palavra-passe.</item>
+ <item quantity="one">O dispositivo não é desbloqueado há <xliff:g id="NUMBER_0">%d</xliff:g> hora. Confirme a palavra-passe.</item>
</plurals>
<string name="fingerprint_not_recognized" msgid="348813995267914625">"Não reconhecido"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 3dd0e6c..3a41681 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -367,4 +367,20 @@
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
+ <!-- Instructions telling the user remaining times when enter SIM PIN view. -->
+ <plurals name="kg_password_default_pin_message">
+ <item quantity="one">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempts.</item>
+ </plurals>
+
+ <!-- Instructions telling the user remaining times when enter SIM PUK view. -->
+ <plurals name="kg_password_default_puk_message">
+ <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact carrier for details.</item>
+ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
+ </plurals>
+
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 581ac73..5770779 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -34,14 +34,14 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"বিজ্ঞপ্তিগুলি"</string>
<string name="battery_low_title" msgid="6456385927409742437">"ব্যাটারি কম"</string>
<string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে"</string>
- <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে৷ ব্যাটারি সাশ্রয়কারী চালু আছে৷"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="7879389868952879166">"<xliff:g id="PERCENTAGE">%s</xliff:g> অবশিষ্ট আছে। ব্যাটারি সেভার চালু আছে।"</string>
<string name="invalid_charger" msgid="4549105996740522523">"USB চার্জিং সমর্থিত নয়৷\nকেবলমাত্র সরবহারকৃত চার্জার ব্যবহার করুন৷"</string>
<string name="invalid_charger_title" msgid="3515740382572798460">"USB চার্জিং সমর্থিত নয়।"</string>
<string name="invalid_charger_text" msgid="5474997287953892710">"শুধুমাত্র সরবরাহকৃত চার্জার ব্যবহার করুন।"</string>
<string name="battery_low_why" msgid="4553600287639198111">"সেটিংস"</string>
- <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ব্যাটারি সঞ্চয়কারী চালু করবেন?"</string>
+ <string name="battery_saver_confirmation_title" msgid="2052100465684817154">"ব্যাটারি সেভার চালু করবেন?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"চালু করুন"</string>
- <string name="battery_saver_start_action" msgid="5576697451677486320">"ব্যাটারি সঞ্চয়কারী চালু"</string>
+ <string name="battery_saver_start_action" msgid="8187820911065797519">"ব্যাটারি সেভার চালু করুন"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"সেটিংস"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ওয়াই-ফাই"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"স্বতঃ-ঘূর্ণায়মান স্ক্রিন"</string>
@@ -243,8 +243,6 @@
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
<string name="data_usage_disabled_dialog" msgid="4919541636934603816">"আপনার সেট করা ডেটার সীমা ফুরিয়ে গেছে। আপনি এখন আর মোবাইল ডেটা ব্যবহার করতে পারবেন না।\n\nযদি আপনি আবার শুরু করেন, ডেটা ব্যবহারের জন্য মূল্য প্রযোজ্য হতে পারে।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
- <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS এর জন্য অনুসন্ধান করা হচ্ছে"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS এর দ্বারা সেট করা অবস্থান"</string>
<string name="accessibility_location_active" msgid="2427290146138169014">"অবস্থান অনুরোধ সক্রিয় রয়েছে"</string>
@@ -401,9 +399,9 @@
<string name="user_remove_user_title" msgid="4681256956076895559">"ব্যবহারকারী সরাবেন?"</string>
<string name="user_remove_user_message" msgid="1453218013959498039">"এই ব্যবহারকারীর সমস্ত অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
<string name="user_remove_user_remove" msgid="7479275741742178297">"সরান"</string>
- <string name="battery_saver_notification_title" msgid="237918726750955859">"ব্যাটারি সেভার চালু রয়েছে"</string>
+ <string name="battery_saver_notification_title" msgid="8614079794522291840">"ব্যাটারি সেভার চালু আছে"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
- <string name="battery_saver_notification_action_text" msgid="109158658238110382">"ব্যাটারি সঞ্চয়কারী বন্ধ করুন"</string>
+ <string name="battery_saver_notification_action_text" msgid="132118784269455533">"ব্যাটারি সেভার বন্ধ করুন"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"সবকিছু সাফ করুন"</string>
@@ -582,8 +580,8 @@
<item quantity="other">%d মিনিট</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"ব্যাটারির ব্যবহার"</string>
- <string name="battery_detail_charging_summary" msgid="4055327085770378335">"চার্জ করার সময় ব্যাটারি সেভার কাজ করে না"</string>
- <string name="battery_detail_switch_title" msgid="8763441006881907058">"ব্যাটারি সেভার"</string>
+ <string name="battery_detail_charging_summary" msgid="1279095653533044008">"চার্জ করার সময় ব্যাটারি সেভার উপলব্ধ নয়"</string>
+ <string name="battery_detail_switch_title" msgid="6285872470260795421">"ব্যাটারি সেভার"</string>
<string name="battery_detail_switch_summary" msgid="9049111149407626804">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
<string name="keyboard_key_button_template" msgid="6230056639734377300">"<xliff:g id="NAME">%1$s</xliff:g> বোতাম"</string>
<string name="keyboard_key_home" msgid="2243500072071305073">"হোম"</string>
@@ -732,10 +730,10 @@
<string name="pip_skip_to_prev" msgid="1955311326688637914">"পিছনে যাওয়ার জন্য এড়িয়ে যান"</string>
<string name="thermal_shutdown_title" msgid="4458304833443861111">"আপনার ফোন গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
<string name="thermal_shutdown_message" msgid="9006456746902370523">"আপনার ফোন এখন ঠিক-ঠাক চলছে"</string>
- <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠান্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
+ <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
<string name="high_temp_title" msgid="4589508026407318374">"ফোনটি গরম হচ্ছে"</string>
- <string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠান্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
- <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠান্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠান্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
+ <string name="high_temp_notif_message" msgid="5642466103153429279">"ফোনটি ঠাণ্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
+ <string name="high_temp_dialog_message" msgid="6840700639374113553">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
<string name="lockscreen_shortcut_left" msgid="2182769107618938629">"বাঁদিকের শর্টকাট"</string>
<string name="lockscreen_shortcut_right" msgid="3328683699505226536">"ডানদিকের শর্টকাট"</string>
<string name="lockscreen_unlock_left" msgid="2043092136246951985">"বাঁদিকের শর্টকাট দিয়েও আনলক করা যায়"</string>
@@ -758,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"ঝটপট অ্যাপ"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"ঝটপট অ্যাপ ইনস্টল করার প্রয়োজন হয় না।"</string>
<string name="app_info" msgid="6856026610594615344">"অ্যাপের তথ্য"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ওয়েবে যান"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"মোবাইল ডেটা"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"ওয়াই ফাই বন্ধ আছে"</string>
<string name="bt_is_off" msgid="2640685272289706392">"ব্লুটুথ বন্ধ আছে"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 601d8e3..530c1a8 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -339,9 +339,9 @@
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
- <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Podijeli ekran nagore"</string>
- <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Podijeli ekran nalijevo"</string>
- <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Podijeli ekran nadesno"</string>
+ <string name="recents_accessibility_split_screen_top" msgid="9056056469282256287">"Dijeli ekran nagore"</string>
+ <string name="recents_accessibility_split_screen_left" msgid="8987144699630620019">"Dijeli ekran nalijevo"</string>
+ <string name="recents_accessibility_split_screen_right" msgid="275069779299592867">"Dijeli ekran nadesno"</string>
<string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjeno"</string>
<string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
<string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"Do kraja punjenja preostalo <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
@@ -764,7 +764,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Instant-aplikacije"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Za instant aplikacije nije potrebna instalacija"</string>
<string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Idite na internet"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Mobilni podaci"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi veza je isključena"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth je isključen"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index cd1f057..d107fea 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -756,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"برنامههای فوری"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"برنامههای فوری نیاز به نصب ندارند."</string>
<string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
- <string name="go_to_web" msgid="1106022723459948514">"رفتن به وب"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"داده تلفن همراه"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi خاموش است"</string>
<string name="bt_is_off" msgid="2640685272289706392">"بلوتوث خاموش است"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 075edf1..b4709bb 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -756,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplikasi Instan"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Aplikasi instan tidak perlu diinstal."</string>
<string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Buka di web"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Data seluler"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi nonaktif"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth nonaktif"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 1b80410..e871c6a 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -756,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"მყისიერი აპები"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"მყისიერი აპები ინსტალაციას არ საჭიროებს."</string>
<string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
- <string name="go_to_web" msgid="1106022723459948514">"ვებზე გადასვლა"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"მობილური ინტერნეტი"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi გამორთულია"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth გამორთულია"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ec4e082..b5b3475 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -26,8 +26,8 @@
<string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Os ecrãs recentes aparecem aqui"</string>
<string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ignorar aplicações recentes"</string>
<plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
- <item quantity="one">1 ecrã na Vista geral</item>
<item quantity="other">%d ecrãs na Vista geral</item>
+ <item quantity="one">1 ecrã na Vista geral</item>
</plurals>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
@@ -249,8 +249,8 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Limpar todas as notificações."</string>
<string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
<plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
- <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
<item quantity="other">Mais <xliff:g id="NUMBER_1">%s</xliff:g> notificações no grupo.</item>
+ <item quantity="one">Mais <xliff:g id="NUMBER_0">%s</xliff:g> notificação no grupo.</item>
</plurals>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Definições de notificação"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Definições do <xliff:g id="APP_NAME">%s</xliff:g>"</string>
@@ -551,13 +551,13 @@
<string name="notification_default_channel_desc" msgid="2506053815870808359">"Esta aplicação não tem categorias de notificação"</string>
<string name="notification_unblockable_desc" msgid="3561016061737896906">"Não é possível desativar as notificações desta aplicação"</string>
<plurals name="notification_num_channels_desc" formatted="false" msgid="5492793452274077663">
- <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoria de notificação desta aplicação</item>
<item quantity="other">1 de <xliff:g id="NUMBER_1">%s</xliff:g> categorias de notificação desta aplicação</item>
+ <item quantity="one">1 de <xliff:g id="NUMBER_0">%s</xliff:g> categoria de notificação desta aplicação</item>
</plurals>
<string name="notification_channels_list_desc_2" msgid="6214732715833946441">"<xliff:g id="CHANNEL_NAME_1">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2">%2$s</xliff:g>"</string>
<plurals name="notification_channels_list_desc_2_and_others" formatted="false" msgid="2747813553355336157">
- <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> e mais <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
<item quantity="other"><xliff:g id="CHANNEL_NAME_1_3">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_4">%2$s</xliff:g> e mais <xliff:g id="NUMBER_5">%3$d</xliff:g></item>
+ <item quantity="one"><xliff:g id="CHANNEL_NAME_1_0">%1$s</xliff:g>, <xliff:g id="CHANNEL_NAME_2_1">%2$s</xliff:g> e mais <xliff:g id="NUMBER_2">%3$d</xliff:g></item>
</plurals>
<string name="notification_channel_controls_opened_accessibility" msgid="6553950422055908113">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> abertos"</string>
<string name="notification_channel_controls_closed_accessibility" msgid="7521619812603693144">"Controlos de notificações da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> fechados"</string>
@@ -572,12 +572,12 @@
<string name="snooze_undo" msgid="6074877317002985129">"ANULAR"</string>
<string name="snoozed_for_time" msgid="2390718332980204462">"Suspensa por <xliff:g id="TIME_AMOUNT">%1$s</xliff:g>"</string>
<plurals name="snoozeHourOptions" formatted="false" msgid="2124335842674413030">
- <item quantity="one">%d hora</item>
<item quantity="other">%d horas</item>
+ <item quantity="one">%d hora</item>
</plurals>
<plurals name="snoozeMinuteOptions" formatted="false" msgid="4127251700591510196">
- <item quantity="one">%d minuto</item>
<item quantity="other">%d minutos</item>
+ <item quantity="one">%d minuto</item>
</plurals>
<string name="battery_panel_title" msgid="7944156115535366613">"Utiliz. da bateria"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Poupança de bateria não disponível durante o carregamento"</string>
@@ -756,7 +756,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Aplicações instantâneas"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"As Aplicações instantâneas não requerem instalação."</string>
<string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Aceder à Web"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Dados móveis"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi desativado"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth desativado"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5b9ff78..95cd2d0 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -770,7 +770,8 @@
<string name="instant_apps" msgid="6647570248119804907">"Додатки з миттєвим запуском"</string>
<string name="instant_apps_message" msgid="8116608994995104836">"Додатки з миттєвим запуском не потрібно встановлювати."</string>
<string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
- <string name="go_to_web" msgid="1106022723459948514">"Перейти на веб-сайт"</string>
+ <!-- no translation found for go_to_web (2650669128861626071) -->
+ <skip />
<string name="mobile_data" msgid="7094582042819250762">"Мобільний трафік"</string>
<string name="wifi_is_off" msgid="1838559392210456893">"Wi-Fi вимкнено"</string>
<string name="bt_is_off" msgid="2640685272289706392">"Bluetooth вимкнено"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 432b406..6e0b56e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -53,8 +53,13 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPin mCheckSimPinThread;
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PIN attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -91,34 +96,71 @@
public void resetState() {
super.resetState();
if (DEBUG) Log.v(TAG, "Resetting state");
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPinPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PIN here to query the number of remaining PIN attempts
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -131,17 +173,19 @@
return 0;
}
- private String getPinPasswordErrorMessage(int attemptsRemaining) {
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
-
+ int msgId;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -252,7 +296,7 @@
}
private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining);
+ String msg = getPinPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -288,6 +332,7 @@
post(new Runnable() {
@Override
public void run() {
+ mRemainingAttempts = attemptsRemaining;
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
@@ -296,8 +341,13 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
@@ -305,7 +355,7 @@
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(attemptsRemaining));
+ getPinPasswordErrorMessage(attemptsRemaining, false));
}
} else {
// "PIN operation failed!" - no idea what this was and no way to
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 7f79008..876d170 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -52,11 +52,17 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPuk mCheckSimPukThread;
+
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PUK attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private String mPukText;
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -132,34 +138,17 @@
}
}
+
void reset() {
mPinText="";
mPukText="";
state = ENTER_PUK;
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_puk_enter_puk_hint);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : "";
- msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
mPasswordEntry.requestFocus();
@@ -168,23 +157,79 @@
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : "";
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PUK here to query the number of remaining PIN attempts
+ new CheckSimPuk("", "", mSubId) {
+ void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected int getPromtReasonStringRes(int reason) {
// No message on SIM Puk
return 0;
}
- private String getPukPasswordErrorMessage(int attemptsRemaining) {
+ private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
} else if (attemptsRemaining > 0) {
+ int msgId = isDefault ? R.plurals.kg_password_default_puk_message :
+ R.plurals.kg_password_wrong_puk_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_puk_failed);
+ int msgId = isDefault ? R.string.kg_puk_enter_puk_hint :
+ R.string.kg_password_puk_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -303,7 +348,7 @@
}
private Dialog getPukRemainingAttemptsDialog(int remaining) {
- String msg = getPukPasswordErrorMessage(remaining);
+ String msg = getPukPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -359,16 +404,25 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+ // show message
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ attemptsRemaining, false));
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
getPukRemainingAttemptsDialog(attemptsRemaining).show();
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPukPasswordErrorMessage(attemptsRemaining));
+ getPukPasswordErrorMessage(
+ attemptsRemaining, false));
}
} else {
mSecurityMessageDisplay.setMessage(getContext().getString(
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 5d4ddf0..b2a0ce5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -715,14 +715,14 @@
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
@Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @NonNull ArrayList<AutofillId> detectedFieldIdsList,
- @NonNull ArrayList<Match> detectedMatchesList) {
+ @Nullable ArrayList<AutofillId> detectedFieldIdsList,
+ @Nullable ArrayList<Match> detectedMatchesList) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
AutofillId[] detectedFieldsIds = null;
Match[] detectedMatches = null;
- if (!detectedFieldIdsList.isEmpty()) {
+ if (detectedFieldIdsList != null) {
detectedFieldsIds = new AutofillId[detectedFieldIdsList.size()];
detectedFieldIdsList.toArray(detectedFieldsIds);
detectedMatches = new Match[detectedMatchesList.size()];
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index fc57a0d..dc35051 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -108,6 +108,8 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.ArrayMap;
@@ -189,6 +191,7 @@
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_START_INPUT = 2000;
+ static final int MSG_START_VR_INPUT = 2010;
static final int MSG_UNBIND_CLIENT = 3000;
static final int MSG_BIND_CLIENT = 3010;
@@ -317,6 +320,28 @@
}
}
+ /**
+ * VR state callback.
+ * Listens for when VR mode finishes.
+ */
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+ @Override
+ public void onVrStateChanged(boolean enabled) {
+ if (!enabled) {
+ restoreNonVrImeFromSettingsNoCheck();
+ }
+ }
+ };
+
+ private void restoreNonVrImeFromSettingsNoCheck() {
+ // switch back to non-VR InputMethod from settings.
+ synchronized (mMethodMap) {
+ final String lastInputId = mSettings.getSelectedInputMethod();
+ setInputMethodLocked(lastInputId,
+ mSettings.getSelectedInputMethodSubtypeId(lastInputId));
+ }
+ }
+
static final class ClientState {
final IInputMethodClient client;
final IInputContext inputContext;
@@ -863,6 +888,30 @@
}
/**
+ * Start a VR InputMethod that matches IME with package name of {@param component}.
+ * Note: This method is called from {@link VrManager}.
+ */
+ private void startVrInputMethodNoCheck(@Nullable ComponentName component) {
+ if (component == null) {
+ // clear the current VR-only IME (if any) and restore normal IME.
+ restoreNonVrImeFromSettingsNoCheck();
+ return;
+ }
+
+ synchronized (mMethodMap) {
+ String packageName = component.getPackageName();
+ for (InputMethodInfo info : mMethodList) {
+ if (TextUtils.equals(info.getPackageName(), packageName) && info.isVrOnly()) {
+ // set this is as current inputMethod without updating settings.
+ setInputMethodEnabled(info.getId(), true);
+ setInputMethodLocked(info.getId(), NOT_A_SUBTYPE_ID);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
* Handles {@link Intent#ACTION_LOCALE_CHANGED}.
*
* <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all
@@ -1338,6 +1387,15 @@
mFileManager = new InputMethodFileManager(mMethodMap, userId);
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mSettings, context);
+ // Register VR-state listener.
+ IVrManager vrManager = (IVrManager) ServiceManager.getService(Context.VR_SERVICE);
+ if (vrManager != null) {
+ try {
+ vrManager.registerListener(mVrStateCallbacks);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register VR mode state listener.");
+ }
+ }
}
private void resetDefaultImeLocked(Context context) {
@@ -1562,12 +1620,27 @@
@Override
public List<InputMethodInfo> getInputMethodList() {
+ return getInputMethodList(false /* isVrOnly */);
+ }
+
+ public List<InputMethodInfo> getVrInputMethodList() {
+ return getInputMethodList(true /* isVrOnly */);
+ }
+
+ private List<InputMethodInfo> getInputMethodList(final boolean isVrOnly) {
// TODO: Make this work even for non-current users?
if (!calledFromValidUser()) {
return Collections.emptyList();
}
synchronized (mMethodMap) {
- return new ArrayList<>(mMethodList);
+ ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ for (InputMethodInfo info : mMethodList) {
+
+ if (info.isVrOnly() == isVrOnly) {
+ methodList.add(info);
+ }
+ }
+ return methodList;
}
}
@@ -3356,6 +3429,9 @@
case MSG_SET_INTERACTIVE:
handleSetInteractive(msg.arg1 != 0);
return true;
+ case MSG_START_VR_INPUT:
+ startVrInputMethodNoCheck((ComponentName) msg.obj);
+ return true;
case MSG_SWITCH_IME:
handleSwitchInputMethod(msg.arg1 != 0);
return true;
@@ -3876,8 +3952,12 @@
private void setSelectedInputMethodAndSubtypeLocked(InputMethodInfo imi, int subtypeId,
boolean setSubtypeOnly) {
- // Update the history of InputMethod and Subtype
- mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+ // Updates to InputMethod are transient in VR mode. Its not included in history.
+ final boolean isVrInput = imi != null && imi.isVrOnly();
+ if (!isVrInput) {
+ // Update the history of InputMethod and Subtype
+ mSettings.saveCurrentInputMethodAndSubtypeToHistory(mCurMethodId, mCurrentSubtype);
+ }
mCurUserActionNotificationSequenceNumber =
Math.max(mCurUserActionNotificationSequenceNumber + 1, 1);
@@ -3892,6 +3972,11 @@
mCurUserActionNotificationSequenceNumber, mCurClient));
}
+ if (isVrInput) {
+ // Updates to InputMethod are transient in VR mode. Any changes to Settings are skipped.
+ return;
+ }
+
// Set Subtype here
if (imi == null || subtypeId < 0) {
mSettings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
@@ -4351,6 +4436,11 @@
mHandler.removeMessages(MSG_HIDE_CURRENT_INPUT_METHOD);
mHandler.sendEmptyMessage(MSG_HIDE_CURRENT_INPUT_METHOD);
}
+
+ @Override
+ public void startVrInputMethodNoCheck(@Nullable ComponentName componentName) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_START_VR_INPUT, componentName));
+ }
}
private static String imeWindowStatusToString(final int imeWindowVis) {
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 2d2424f..9bfdd0c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -433,7 +433,9 @@
|| !otherStack.affectedBySplitScreenResize()) {
continue;
}
- otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ false /* animate */, false /* showRecents */,
+ false /* sendNonResizeableNotification */);
}
} finally {
mSupervisor.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7b4703a..982380c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10570,7 +10570,8 @@
if (toTop) {
stack.moveToFront("setTaskWindowingModeSplitScreenPrimary", task);
}
- stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents);
+ stack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, animate, showRecents,
+ true /* sendNonResizeableNotification */);
return windowingMode != task.getWindowingMode();
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index edf9813..fcf9946 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -483,10 +483,12 @@
@Override
public void setWindowingMode(int windowingMode) {
- setWindowingMode(windowingMode, false /* animate */, true /* showRecents */);
+ setWindowingMode(windowingMode, false /* animate */, true /* showRecents */,
+ true /* sendNonResizeableNotification */);
}
- void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents) {
+ void setWindowingMode(int preferredWindowingMode, boolean animate, boolean showRecents,
+ boolean sendNonResizeableNotification) {
final int currentMode = getWindowingMode();
final ActivityDisplay display = getDisplay();
final TaskRecord topTask = topTask();
@@ -505,7 +507,8 @@
final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryStack();
// Take any required action due to us not supporting the preferred windowing mode.
- if (windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
+ if (sendNonResizeableNotification
+ && windowingMode != preferredWindowingMode && isActivityTypeStandardOrUndefined()) {
if (alreadyInSplitScreenMode
&& (preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
@@ -524,8 +527,9 @@
final WindowManagerService wm = mService.mWindowManager;
final ActivityRecord topActivity = getTopActivity();
- if (windowingMode != WINDOWING_MODE_FULLSCREEN && topActivity != null
- && topActivity.isNonResizableOrForcedResizable() && !topActivity.noDisplay) {
+ if (sendNonResizeableNotification && windowingMode != WINDOWING_MODE_FULLSCREEN
+ && topActivity != null && topActivity.isNonResizableOrForcedResizable()
+ && !topActivity.noDisplay) {
// Inform the user that they are starting an app that may not work correctly in
// multi-window mode.
final String packageName = topActivity.appInfo.packageName;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 9cd52d7..bdfd4bd 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -323,7 +323,7 @@
private final BroadcastReceiver mAccountsUpdatedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- EndPoint target = new EndPoint(null, null, context.getUserId());
+ EndPoint target = new EndPoint(null, null, getSendingUserId());
updateRunningAccounts(target /* sync targets for user */);
}
};
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8b2854c..f60cb06 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9714,6 +9714,7 @@
// them in the case where we're not upgrading or booting for the first time.
String primaryCpuAbiFromSettings = null;
String secondaryCpuAbiFromSettings = null;
+ boolean needToDeriveAbi = (scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0;
// writer
synchronized (mPackages) {
@@ -9791,11 +9792,14 @@
}
}
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) == 0) {
+ if (!needToDeriveAbi) {
PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
if (foundPs != null) {
primaryCpuAbiFromSettings = foundPs.primaryCpuAbiString;
secondaryCpuAbiFromSettings = foundPs.secondaryCpuAbiString;
+ } else {
+ // when re-adding a system package failed after uninstalling updates.
+ needToDeriveAbi = true;
}
}
@@ -10011,7 +10015,7 @@
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
- if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+ if (needToDeriveAbi) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
final boolean extractNativeLibs = !pkg.isLibrary();
derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs, mAppLib32InstallDir);
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1f4e64e..7d55b68 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -59,6 +59,7 @@
import android.util.Slog;
import android.util.SparseArray;
import com.android.server.wm.WindowManagerInternal;
+import android.view.inputmethod.InputMethodManagerInternal;
import com.android.internal.R;
import com.android.internal.util.DumpUtils;
@@ -609,6 +610,14 @@
}
@Override
+ public void setVrInputMethod(ComponentName componentName) {
+ enforceCallerPermissionAnyOf(Manifest.permission.RESTRICTED_VR_ACCESS);
+ InputMethodManagerInternal imm =
+ LocalServices.getService(InputMethodManagerInternal.class);
+ imm.startVrInputMethodNoCheck(componentName);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6467582..c371e88 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -21,6 +21,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.server.wm.proto.WindowContainerProto.CONFIGURATION_CONTAINER;
import static com.android.server.wm.proto.WindowContainerProto.ORIENTATION;
+import static com.android.server.wm.proto.WindowContainerProto.VISIBLE;
import static android.view.SurfaceControl.Transaction;
import android.annotation.CallSuper;
@@ -809,6 +810,7 @@
final long token = proto.start(fieldId);
super.writeToProto(proto, CONFIGURATION_CONTAINER, trim);
proto.write(ORIENTATION, mOrientation);
+ proto.write(VISIBLE, isVisible());
proto.end(token);
}
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 70983c8..5c58cdb 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -163,10 +163,10 @@
// TODO: Find an lighter weight approach.
private class LoggingCallbackWrapper extends Callback {
private static final String PREFIX = "INVOKE ";
- private Callback mCallback;
+ private final Callback mCallback;
public LoggingCallbackWrapper(Callback callback) {
- mCallback = callback;
+ mCallback = (callback != null) ? callback : new Callback();
}
private void log(String msg) {
@@ -1273,6 +1273,7 @@
stopAllIP();
resetLinkProperties();
+ mCallback.onLinkPropertiesChange(new LinkProperties(mLinkProperties));
if (mStartTimeMillis > 0) {
recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE);
mStartTimeMillis = 0;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 51c805d..cd3fdee 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -66,6 +66,7 @@
private SoundTriggerDbHelper mDbHelper;
private SoundTriggerHelper mSoundTriggerHelper;
private final TreeMap<UUID, SoundModel> mLoadedModels;
+ private Object mCallbacksLock;
private final TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback> mIntentCallbacks;
private PowerManager.WakeLock mWakelock;
@@ -75,6 +76,7 @@
mServiceStub = new SoundTriggerServiceStub();
mLocalSoundTriggerService = new LocalSoundTriggerService(context);
mLoadedModels = new TreeMap<UUID, SoundModel>();
+ mCallbacksLock = new Object();
mIntentCallbacks = new TreeMap<UUID, LocalSoundTriggerRecognitionStatusCallback>();
mLock = new Object();
}
@@ -211,7 +213,9 @@
// don't know if the other model is loaded.
if (oldModel != null && !oldModel.equals(soundModel)) {
mSoundTriggerHelper.unloadGenericSoundModel(soundModel.uuid);
- mIntentCallbacks.remove(soundModel.uuid);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
}
mLoadedModels.put(soundModel.uuid, soundModel);
}
@@ -240,7 +244,9 @@
// don't know if the other model is loaded.
if (oldModel != null && !oldModel.equals(soundModel)) {
mSoundTriggerHelper.unloadKeyphraseSoundModel(soundModel.keyphrases[0].id);
- mIntentCallbacks.remove(soundModel.uuid);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModel.uuid);
+ }
}
mLoadedModels.put(soundModel.uuid, soundModel);
}
@@ -262,8 +268,10 @@
Slog.e(TAG, soundModelId + " is not loaded");
return STATUS_ERROR;
}
- LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
- soundModelId.getUuid());
+ LocalSoundTriggerRecognitionStatusCallback callback = null;
+ synchronized (mCallbacksLock) {
+ callback = mIntentCallbacks.get(soundModelId.getUuid());
+ }
if (callback != null) {
Slog.e(TAG, soundModelId + " is already running");
return STATUS_ERROR;
@@ -291,7 +299,9 @@
Slog.e(TAG, "Failed to start model: " + ret);
return ret;
}
- mIntentCallbacks.put(soundModelId.getUuid(), callback);
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.put(soundModelId.getUuid(), callback);
+ }
}
return STATUS_OK;
}
@@ -310,8 +320,10 @@
Slog.e(TAG, soundModelId + " is not loaded");
return STATUS_ERROR;
}
- LocalSoundTriggerRecognitionStatusCallback callback = mIntentCallbacks.get(
- soundModelId.getUuid());
+ LocalSoundTriggerRecognitionStatusCallback callback = null;
+ synchronized (mCallbacksLock) {
+ callback = mIntentCallbacks.get(soundModelId.getUuid());
+ }
if (callback == null) {
Slog.e(TAG, soundModelId + " is not running");
return STATUS_ERROR;
@@ -334,7 +346,9 @@
Slog.e(TAG, "Failed to stop model: " + ret);
return ret;
}
- mIntentCallbacks.remove(soundModelId.getUuid());
+ synchronized (mCallbacksLock) {
+ mIntentCallbacks.remove(soundModelId.getUuid());
+ }
}
return STATUS_OK;
}
@@ -379,14 +393,14 @@
public boolean isRecognitionActive(ParcelUuid parcelUuid) {
enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
if (!isInitialized()) return false;
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
LocalSoundTriggerRecognitionStatusCallback callback =
mIntentCallbacks.get(parcelUuid.getUuid());
if (callback == null) {
return false;
}
- return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
}
+ return mSoundTriggerHelper.isRecognitionRequested(parcelUuid.getUuid());
}
}
@@ -513,7 +527,7 @@
private void removeCallback(boolean releaseWakeLock) {
mCallbackIntent = null;
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
mIntentCallbacks.remove(mUuid);
if (releaseWakeLock) {
mWakelock.release();
@@ -523,7 +537,7 @@
}
private void grabWakeLock() {
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
if (mWakelock == null) {
PowerManager pm = ((PowerManager) mContext.getSystemService(Context.POWER_SERVICE));
mWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
@@ -537,7 +551,7 @@
public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
// We're only ever invoked when the callback is done, so release the lock.
- synchronized (mLock) {
+ synchronized (mCallbacksLock) {
mWakelock.release();
}
}
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index c3a2ceb..56e1e64 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -280,6 +280,36 @@
* {@hide}
*/
public static final int NORMAL_UNSPECIFIED = 65;
+
+ /**
+ * Stk Call Control modified DIAL request to video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_MODIFIED_TO_DIAL_VIDEO = 66;
+
+ /**
+ * Stk Call Control modified Video DIAL request to SS request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_SS = 67;
+
+ /**
+ * Stk Call Control modified Video DIAL request to USSD request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_USSD = 68;
+
+ /**
+ * Stk Call Control modified Video DIAL request to DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL = 69;
+
+ /**
+ * Stk Call Control modified Video DIAL request to Video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 70;
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -382,6 +412,16 @@
return "DIAL_MODIFIED_TO_SS";
case DIAL_MODIFIED_TO_DIAL:
return "DIAL_MODIFIED_TO_DIAL";
+ case DIAL_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_MODIFIED_TO_DIAL_VIDEO";
+ case DIAL_VIDEO_MODIFIED_TO_SS:
+ return "DIAL_VIDEO_MODIFIED_TO_SS";
+ case DIAL_VIDEO_MODIFIED_TO_USSD:
+ return "DIAL_VIDEO_MODIFIED_TO_USSD";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO";
case ERROR_UNSPECIFIED:
return "ERROR_UNSPECIFIED";
case OUTGOING_FAILURE:
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
index b371efb..daa74c8 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -21,6 +21,7 @@
import com.android.ims.ImsCallForwardInfo;
import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsUtListener;
@@ -85,4 +86,10 @@
public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
throws RemoteException {
}
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ */
+ @Override
+ public void onSupplementaryServiceIndication(ImsSsData ssData) {}
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index cdfc1fd..6ad54c1 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -111,6 +111,16 @@
// and this capability is not supported by the network.
public static final int CODE_IMEI_NOT_ACCEPTED = 243;
+ //STK CC errors
+ public static final int CODE_DIAL_MODIFIED_TO_USSD = 244;
+ public static final int CODE_DIAL_MODIFIED_TO_SS = 245;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251;
+
/**
* STATUSCODE (SIP response code) (IMS -> Telephony)
*/
@@ -217,6 +227,11 @@
public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803;
public static final int CODE_UT_NETWORK_ERROR = 804;
public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821;
+ //STK CC errors
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822;
+ public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823;
+ public static final int CODE_UT_SS_MODIFIED_TO_SS = 824;
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825;
/**
* ECBM
diff --git a/telephony/java/com/android/ims/ImsSsData.aidl b/telephony/java/com/android/ims/ImsSsData.aidl
new file mode 100644
index 0000000..33f8306
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsSsData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017 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.ims;
+
+parcelable ImsSsData;
diff --git a/telephony/java/com/android/ims/ImsSsData.java b/telephony/java/com/android/ims/ImsSsData.java
new file mode 100644
index 0000000..7336c13
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsSsData.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Provided STK Call Control Suplementary Service information
+ *
+ * {@hide}
+ */
+public class ImsSsData implements Parcelable {
+
+ //ServiceType
+ public static final int SS_CFU = 0;
+ public static final int SS_CF_BUSY = 1;
+ public static final int SS_CF_NO_REPLY = 2;
+ public static final int SS_CF_NOT_REACHABLE = 3;
+ public static final int SS_CF_ALL = 4;
+ public static final int SS_CF_ALL_CONDITIONAL = 5;
+ public static final int SS_CFUT = 6;
+ public static final int SS_CLIP = 7;
+ public static final int SS_CLIR = 8;
+ public static final int SS_COLP = 9;
+ public static final int SS_COLR = 10;
+ public static final int SS_CNAP = 11;
+ public static final int SS_WAIT = 12;
+ public static final int SS_BAOC = 13;
+ public static final int SS_BAOIC = 14;
+ public static final int SS_BAOIC_EXC_HOME = 15;
+ public static final int SS_BAIC = 16;
+ public static final int SS_BAIC_ROAMING = 17;
+ public static final int SS_ALL_BARRING = 18;
+ public static final int SS_OUTGOING_BARRING = 19;
+ public static final int SS_INCOMING_BARRING = 20;
+ public static final int SS_INCOMING_BARRING_DN = 21;
+ public static final int SS_INCOMING_BARRING_ANONYMOUS = 22;
+
+ //SSRequestType
+ public static final int SS_ACTIVATION = 0;
+ public static final int SS_DEACTIVATION = 1;
+ public static final int SS_INTERROGATION = 2;
+ public static final int SS_REGISTRATION = 3;
+ public static final int SS_ERASURE = 4;
+
+ //TeleserviceType
+ public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0;
+ public static final int SS_ALL_TELESEVICES = 1;
+ public static final int SS_TELEPHONY = 2;
+ public static final int SS_ALL_DATA_TELESERVICES = 3;
+ public static final int SS_SMS_SERVICES = 4;
+ public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5;
+
+ // Refer to ServiceType
+ public int serviceType;
+ // Refere to SSRequestType
+ public int requestType;
+ // Refer to TeleserviceType
+ public int teleserviceType;
+ // Service Class
+ public int serviceClass;
+ // Error information
+ public int result;
+
+ public int[] ssInfo; /* Valid for all supplementary services.
+ This field will be empty for RequestType SS_INTERROGATION
+ and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
+ SS_INCOMING_BARRING_ANONYMOUS.*/
+
+ public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services
+ ServiceType SS_CF_* and RequestType SS_INTERROGATION */
+
+ public ImsSsInfo[] imsSsInfo; /* Valid only for ServiceType SS_INCOMING_BARRING_DN and
+ ServiceType SS_INCOMING_BARRING_ANONYMOUS */
+
+ public ImsSsData() {}
+
+ public ImsSsData(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
+ @Override
+ public ImsSsData createFromParcel(Parcel in) {
+ return new ImsSsData(in);
+ }
+
+ @Override
+ public ImsSsData[] newArray(int size) {
+ return new ImsSsData[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(serviceType);
+ out.writeInt(requestType);
+ out.writeInt(teleserviceType);
+ out.writeInt(serviceClass);
+ out.writeInt(result);
+ out.writeIntArray(ssInfo);
+ out.writeParcelableArray(cfInfo, 0);
+ }
+
+ private void readFromParcel(Parcel in) {
+ serviceType = in.readInt();
+ requestType = in.readInt();
+ teleserviceType = in.readInt();
+ serviceClass = in.readInt();
+ result = in.readInt();
+ ssInfo = in.createIntArray();
+ cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public boolean isTypeCF() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_BUSY ||
+ serviceType == SS_CF_NO_REPLY || serviceType == SS_CF_NOT_REACHABLE ||
+ serviceType == SS_CF_ALL || serviceType == SS_CF_ALL_CONDITIONAL);
+ }
+
+ public boolean isTypeUnConditional() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_ALL);
+ }
+
+ public boolean isTypeCW() {
+ return (serviceType == SS_WAIT);
+ }
+
+ public boolean isTypeClip() {
+ return (serviceType == SS_CLIP);
+ }
+
+ public boolean isTypeColr() {
+ return (serviceType == SS_COLR);
+ }
+
+ public boolean isTypeColp() {
+ return (serviceType == SS_COLP);
+ }
+
+ public boolean isTypeClir() {
+ return (serviceType == SS_CLIR);
+ }
+
+ public boolean isTypeIcb() {
+ return (serviceType == SS_INCOMING_BARRING_DN ||
+ serviceType == SS_INCOMING_BARRING_ANONYMOUS);
+ }
+
+ public boolean isTypeBarring() {
+ return (serviceType == SS_BAOC || serviceType == SS_BAOIC ||
+ serviceType == SS_BAOIC_EXC_HOME || serviceType == SS_BAIC ||
+ serviceType == SS_BAIC_ROAMING || serviceType == SS_ALL_BARRING ||
+ serviceType == SS_OUTGOING_BARRING || serviceType == SS_INCOMING_BARRING);
+ }
+
+ public boolean isTypeInterrogation() {
+ return (requestType == SS_INTERROGATION);
+ }
+
+ public String toString() {
+ return "[ImsSsData] " + "ServiceType: " + serviceType
+ + " RequestType: " + requestType
+ + " TeleserviceType: " + teleserviceType
+ + " ServiceClass: " + serviceClass
+ + " Result: " + result;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 250371f..14c184a 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -16,6 +16,7 @@
package com.android.ims;
+import android.os.Handler;
import android.os.Message;
/**
@@ -188,4 +189,18 @@
* Updates the configuration of the COLP supplementary service.
*/
public void updateCOLP(boolean enable, Message result);
+
+ /**
+ * Register for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ * @param event Supplimentary service indication event.
+ * @param Object user object.
+ */
+ public void registerForSuppServiceIndication(Handler handler, int event, Object object);
+
+ /**
+ * Deregister for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ */
+ public void unregisterForSuppServiceIndication(Handler handler);
}
diff --git a/telephony/java/com/android/ims/internal/IImsUtListener.aidl b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
index 300273a..1bc0369 100644
--- a/telephony/java/com/android/ims/internal/IImsUtListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
@@ -19,6 +19,7 @@
import android.os.Bundle;
import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.ImsReasonInfo;
@@ -56,4 +57,11 @@
*/
void utConfigurationCallWaitingQueried(in IImsUt ut,
int id, in ImsSsInfo[] cwInfo);
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ *
+ * @param ssData Details of SS request and response information
+ */
+ void onSupplementaryServiceIndication(in ImsSsData ssData);
}
diff --git a/tests/net/java/android/net/ip/IpManagerTest.java b/tests/net/java/android/net/ip/IpManagerTest.java
index 22d88fb..ebf121a 100644
--- a/tests/net/java/android/net/ip/IpManagerTest.java
+++ b/tests/net/java/android/net/ip/IpManagerTest.java
@@ -69,6 +69,8 @@
/**
* Tests for IpManager.
+ *
+ * TODO: Rename to IpClientTest.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -111,6 +113,10 @@
verify(mNMService, times(1)).registerObserver(arg.capture());
mObserver = arg.getValue();
reset(mNMService);
+ final LinkProperties emptyLp = new LinkProperties();
+ emptyLp.setInterfaceName(ifname);
+ verify(mCb, timeout(100)).onLinkPropertiesChange(eq(emptyLp));
+ reset(mCb);
return ipm;
}