Merge "Public EuiccManager APIs."
diff --git a/Android.bp b/Android.bp
index 3d56254..c5d64fb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -578,7 +578,6 @@
"wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
"wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
"wifi/java/android/net/wifi/IWifiScanner.aidl",
- "wifi/java/android/net/wifi/IRttManager.aidl",
"packages/services/PacProcessor/com/android/net/IProxyService.aidl",
"packages/services/Proxy/com/android/net/IProxyCallback.aidl",
"packages/services/Proxy/com/android/net/IProxyPortListener.aidl",
diff --git a/api/system-current.txt b/api/system-current.txt
index cd9c957..9922df6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5173,22 +5173,19 @@
}
public class UiccSlotInfo implements android.os.Parcelable {
- ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int);
+ ctor public UiccSlotInfo(boolean, boolean, java.lang.String, int, int);
method public int describeContents();
method public java.lang.String getCardId();
method public int getCardStateInfo();
method public boolean getIsActive();
method public boolean getIsEuicc();
+ method public int getLogicalSlotIdx();
method public void writeToParcel(android.os.Parcel, int);
field public static final int CARD_STATE_INFO_ABSENT = 1; // 0x1
field public static final int CARD_STATE_INFO_ERROR = 3; // 0x3
field public static final int CARD_STATE_INFO_PRESENT = 2; // 0x2
field public static final int CARD_STATE_INFO_RESTRICTED = 4; // 0x4
field public static final android.os.Parcelable.Creator<android.telephony.UiccSlotInfo> CREATOR;
- field public final java.lang.String cardId;
- field public final int cardStateInfo;
- field public final boolean isActive;
- field public final boolean isEuicc;
}
public abstract class VisualVoicemailService extends android.app.Service {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b46c5c1..90158a0 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
src/external/KernelUidCpuActiveTimeReader.cpp \
src/external/KernelUidCpuClusterTimeReader.cpp \
src/external/StatsPullerManagerImpl.cpp \
+ src/external/puller_util.cpp \
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
src/logd/LogReader.cpp \
@@ -175,6 +176,7 @@
tests/AnomalyMonitor_test.cpp \
tests/anomaly/AnomalyTracker_test.cpp \
tests/ConfigManager_test.cpp \
+ tests/external/puller_util_test.cpp \
tests/indexed_priority_queue_test.cpp \
tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index f0eaeff..8483b02 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -181,7 +181,9 @@
return toString().compare(that.toString()) < 0;
};
-
+bool compareDimensionsValue(const DimensionsValue& s1, const DimensionsValue& s2) {
+ return EqualsTo(s1, s2);
+}
} // namespace statsd
} // namespace os
} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 3efe9b1..f24bb04 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -77,6 +77,7 @@
: mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS))
{
mUidMap = new UidMap();
+ StatsPuller::SetUidMap(mUidMap);
mConfigManager = new ConfigManager();
mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, time(nullptr), [this](const ConfigKey& key) {
sp<IStatsCompanionService> sc = getStatsCompanionService();
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 41e4705..fc0ad7c 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -19,6 +19,7 @@
#include "StatsPuller.h"
#include "guardrail/StatsdStats.h"
+#include "puller_util.h"
namespace android {
namespace os {
@@ -26,6 +27,9 @@
using std::lock_guard;
+sp<UidMap> StatsPuller::mUidMap = nullptr;
+void StatsPuller::SetUidMap(const sp<UidMap>& uidMap) { mUidMap = uidMap; }
+
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
StatsPuller::StatsPuller(const int tagId)
: mTagId(tagId) {
@@ -54,7 +58,8 @@
mLastPullTimeSec = curTime;
bool ret = PullInternal(&mCachedData);
if (ret) {
- (*data) = mCachedData;
+ mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
+ (*data) = mCachedData;
}
return ret;
}
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 3446f9b..82a8611 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -18,11 +18,14 @@
#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
+#include <utils/RefBase.h>
#include <mutex>
#include <vector>
+#include "packages/UidMap.h"
-#include "logd/LogEvent.h"
#include "guardrail/StatsdStats.h"
+#include "logd/LogEvent.h"
+#include "puller_util.h"
using android::os::StatsLogEventWrapper;
@@ -30,7 +33,7 @@
namespace os {
namespace statsd {
-class StatsPuller {
+class StatsPuller : public virtual RefBase {
public:
StatsPuller(const int tagId);
@@ -44,7 +47,9 @@
// Clear cache if elapsed time is more than cooldown time
int ClearCacheIfNecessary(long timestampSec);
-protected:
+ static void SetUidMap(const sp<UidMap>& uidMap);
+
+ protected:
// The atom tag id this puller pulls
const int mTagId;
@@ -67,6 +72,8 @@
long mLastPullTimeSec;
int clearCache();
+
+ static sp<UidMap> mUidMap;
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 19b3a86..0b772b3 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define DEBUG true
+#define DEBUG false
#include "Log.h"
#include <android/os/IStatsCompanionService.h>
@@ -24,6 +24,9 @@
#include "CpuTimePerUidFreqPuller.h"
#include "CpuTimePerUidPuller.h"
#include "ResourceHealthManagerPuller.h"
+#include "KernelUidCpuActiveTimeReader.h"
+#include "KernelUidCpuClusterTimeReader.h"
+#include "SubsystemSleepStatePuller.h"
#include "StatsCompanionServicePuller.h"
#include "StatsPullerManagerImpl.h"
#include "StatsService.h"
@@ -44,60 +47,130 @@
namespace os {
namespace statsd {
+const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
+ // wifi_bytes_transfer
+ {android::util::WIFI_BYTES_TRANSFER,
+ {{2, 3, 4, 5},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
+ // wifi_bytes_transfer_by_fg_bg
+ {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
+ {{3, 4, 5, 6},
+ {2},
+ 1,
+ new StatsCompanionServicePuller(
+ android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
+ // mobile_bytes_transfer
+ {android::util::MOBILE_BYTES_TRANSFER,
+ {{2, 3, 4, 5},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
+ // mobile_bytes_transfer_by_fg_bg
+ {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
+ {{3, 4, 5, 6},
+ {2},
+ 1,
+ new StatsCompanionServicePuller(
+ android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
+ // bluetooth_bytes_transfer
+ {android::util::BLUETOOTH_BYTES_TRANSFER,
+ {{2, 3},
+ {},
+ 1,
+ new StatsCompanionServicePuller(
+ android::util::BLUETOOTH_BYTES_TRANSFER)}},
+ // kernel_wakelock
+ {android::util::KERNEL_WAKELOCK,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+ // subsystem_sleep_state
+ {android::util::SUBSYSTEM_SLEEP_STATE,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::SUBSYSTEM_SLEEP_STATE)}},
+ // cpu_time_per_freq
+ {android::util::CPU_TIME_PER_FREQ,
+ {{3},
+ {2},
+ 1,
+ new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+ // cpu_time_per_uid
+ {android::util::CPU_TIME_PER_UID,
+ {{2, 3}, {}, 1, new CpuTimePerUidPuller()}},
+ // cpu_time_per_uid_freq
+ {android::util::CPU_TIME_PER_UID_FREQ,
+ {{3}, {2}, 1, new CpuTimePerUidFreqPuller()}},
+ // wifi_activity_energy_info
+ {android::util::WIFI_ACTIVITY_ENERGY_INFO,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(
+ android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
+ // modem_activity_info
+ {android::util::MODEM_ACTIVITY_INFO,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+ // bluetooth_activity_info
+ {android::util::BLUETOOTH_ACTIVITY_INFO,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+ // system_elapsed_realtime
+ {android::util::SYSTEM_ELAPSED_REALTIME,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
+ // system_uptime
+ {android::util::SYSTEM_UPTIME,
+ {{},
+ {},
+ 1,
+ new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+ // cpu_active_time
+ {android::util::CPU_ACTIVE_TIME,
+ {{3}, {2}, 1, new KernelUidCpuActiveTimeReader()}},
+ // cpu_cluster_time
+ {android::util::CPU_CLUSTER_TIME,
+ {{3}, {2}, 1, new KernelUidCpuClusterTimeReader()}},
+ // disk_space
+ {android::util::DISK_SPACE,
+ {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
+ // remaining_battery_capacity
+ {android::util::REMAINING_BATTERY_CAPACITY,
+ {{},
+ {},
+ 1,
+ new ResourceHealthManagerPuller(
+ android::util::REMAINING_BATTERY_CAPACITY)}},
+ // full_battery_capacity
+ {android::util::FULL_BATTERY_CAPACITY,
+ {{},
+ {},
+ 1,
+ new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}};
+
StatsPullerManagerImpl::StatsPullerManagerImpl()
: mCurrentPullingInterval(LONG_MAX) {
- mPullers.insert({android::util::KERNEL_WAKELOCK,
- make_shared<StatsCompanionServicePuller>(android::util::KERNEL_WAKELOCK)});
- mPullers.insert({android::util::WIFI_BYTES_TRANSFER,
- make_shared<StatsCompanionServicePuller>(android::util::WIFI_BYTES_TRANSFER)});
- mPullers.insert(
- {android::util::MOBILE_BYTES_TRANSFER,
- make_shared<StatsCompanionServicePuller>(android::util::MOBILE_BYTES_TRANSFER)});
- mPullers.insert({android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
- make_shared<StatsCompanionServicePuller>(
- android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)});
- mPullers.insert({android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
- make_shared<StatsCompanionServicePuller>(
- android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)});
- mPullers.insert(
- {android::util::SUBSYSTEM_SLEEP_STATE,
- make_shared<SubsystemSleepStatePuller>()});
- mPullers.insert({android::util::CPU_TIME_PER_FREQ, make_shared<StatsCompanionServicePuller>(android::util::CPU_TIME_PER_FREQ)});
- mPullers.insert({android::util::CPU_TIME_PER_UID, make_shared<CpuTimePerUidPuller>()});
- mPullers.insert({android::util::CPU_TIME_PER_UID_FREQ, make_shared<CpuTimePerUidFreqPuller>()});
- mPullers.insert(
- {android::util::SYSTEM_ELAPSED_REALTIME,
- make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_ELAPSED_REALTIME)});
- mPullers.insert({android::util::SYSTEM_UPTIME,
- make_shared<StatsCompanionServicePuller>(android::util::SYSTEM_UPTIME)});
- mPullers.insert({android::util::DISK_SPACE,
- make_shared<StatsCompanionServicePuller>(android::util::DISK_SPACE)});
- mPullers.insert(
- {android::util::BLUETOOTH_ACTIVITY_INFO,
- make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_ACTIVITY_INFO)});
-
- mPullers.insert(
- {android::util::BLUETOOTH_BYTES_TRANSFER,
- make_shared<StatsCompanionServicePuller>(android::util::BLUETOOTH_BYTES_TRANSFER)});
- mPullers.insert(
- {android::util::WIFI_ACTIVITY_ENERGY_INFO,
- make_shared<StatsCompanionServicePuller>(android::util::WIFI_ACTIVITY_ENERGY_INFO)});
- mPullers.insert({android::util::MODEM_ACTIVITY_INFO,
- make_shared<StatsCompanionServicePuller>(android::util::MODEM_ACTIVITY_INFO)});
- mPullers.insert({android::util::REMAINING_BATTERY_CAPACITY,
- make_shared<ResourceHealthManagerPuller>(android::util::REMAINING_BATTERY_CAPACITY)});
- mPullers.insert({android::util::FULL_BATTERY_CAPACITY,
- make_shared<ResourceHealthManagerPuller>(android::util::FULL_BATTERY_CAPACITY)});
mStatsCompanionService = StatsService::getStatsCompanionService();
}
bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
if (DEBUG) ALOGD("Initiating pulling %d", tagId);
- if (mPullers.find(tagId) != mPullers.end()) {
- bool ret = mPullers.find(tagId)->second->Pull(data);
- ALOGD("pulled %d items", (int)data->size());
- return ret;
+ if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
+ bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
+ ALOGD("pulled %d items", (int)data->size());
+ return ret;
} else {
ALOGD("Unknown tagId %d", tagId);
return false; // Return early since we don't know what to pull.
@@ -110,7 +183,7 @@
}
bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) const {
- return mPullers.find(tagId) != mPullers.end();
+ return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
}
void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver,
@@ -201,16 +274,16 @@
int StatsPullerManagerImpl::ForceClearPullerCache() {
int totalCleared = 0;
- for (auto puller : mPullers) {
- totalCleared += puller.second->ForceClearCache();
+ for (const auto& pulledAtom : kAllPullAtomInfo) {
+ totalCleared += pulledAtom.second.puller->ForceClearCache();
}
return totalCleared;
}
int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(long timestampSec) {
int totalCleared = 0;
- for (auto puller : mPullers) {
- totalCleared += puller.second->ClearCacheIfNecessary(timestampSec);
+ for (const auto& pulledAtom : kAllPullAtomInfo) {
+ totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampSec);
}
return totalCleared;
}
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h
index 3535fa3..76a4c14 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.h
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h
@@ -32,6 +32,20 @@
namespace os {
namespace statsd {
+typedef struct {
+ // The field numbers of the fields that need to be summed when merging
+ // isolated uid with host uid.
+ std::vector<int> additiveFields;
+ // The field numbers of the fields that can't be merged when merging
+ // data belong to isolated uid and host uid.
+ std::vector<int> nonAdditiveFields;
+ // How long should the puller wait before doing an actual pull again. Default
+ // 1 sec. Set this to 0 if this is handled elsewhere.
+ long coolDownSec = 1;
+ // The actual puller
+ sp<StatsPuller> puller;
+} PullAtomInfo;
+
class StatsPullerManagerImpl : public virtual RefBase {
public:
static StatsPullerManagerImpl& GetInstance();
@@ -53,7 +67,9 @@
int ClearPullerCacheIfNecessary(long timestampSec);
-private:
+ const static std::map<int, PullAtomInfo> kAllPullAtomInfo;
+
+ private:
StatsPullerManagerImpl();
// use this to update alarm
@@ -61,9 +77,6 @@
sp<IStatsCompanionService> get_stats_companion_service();
- // mapping from simple matcher tagId to puller
- std::map<int, std::shared_ptr<StatsPuller>> mPullers;
-
typedef struct {
// pull_interval_sec : last_pull_time_sec
std::pair<uint64_t, uint64_t> timeInfo;
@@ -81,8 +94,6 @@
// bucket size. All pulled metrics start pulling based on this time, so that they can be
// correctly attributed to the correct buckets.
long mTimeBaseSec;
-
- LogEvent parse_pulled_data(String16 data);
};
} // namespace statsd
diff --git a/cmds/statsd/src/external/puller_util.cpp b/cmds/statsd/src/external/puller_util.cpp
new file mode 100644
index 0000000..7cfc1d48
--- /dev/null
+++ b/cmds/statsd/src/external/puller_util.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#include "Log.h"
+
+#include "StatsPullerManagerImpl.h"
+#include "field_util.h"
+#include "puller_util.h"
+#include "statslog.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::map;
+using std::shared_ptr;
+using std::vector;
+
+DimensionsValue* getFieldValue(shared_ptr<LogEvent> event, int tagId, int fieldNum) {
+ Field field;
+ buildSimpleAtomField(tagId, fieldNum, &field);
+ return event->findFieldValueOrNull(field);
+}
+
+bool shouldMerge(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
+ const vector<int>& nonAdditiveFields, int tagId) {
+ for (int f : nonAdditiveFields) {
+ DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
+ DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
+ if (!compareDimensionsValue(*lValue, *rValue)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// merge rhs to lhs
+void mergeEvent(shared_ptr<LogEvent>& lhs, shared_ptr<LogEvent>& rhs,
+ const vector<int>& additiveFields, int tagId) {
+ for (int f : additiveFields) {
+ DimensionsValue* lValue = getFieldValue(lhs, tagId, f);
+ DimensionsValue* rValue = getFieldValue(rhs, tagId, f);
+ if (lValue->has_value_int()) {
+ lValue->set_value_int(lValue->value_int() + rValue->value_int());
+ } else if (lValue->has_value_long()) {
+ lValue->set_value_long(lValue->value_long() + rValue->value_long());
+ }
+ }
+}
+
+// process all data and merge isolated with host if necessary
+void mergeIsolatedUidsToHostUid(vector<shared_ptr<LogEvent>>& data,
+ const sp<UidMap>& uidMap, int tagId) {
+ if (StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId) ==
+ StatsPullerManagerImpl::kAllPullAtomInfo.end()) {
+ VLOG("Unknown pull atom id %d", tagId);
+ return;
+ }
+ if (android::util::kAtomsWithUidField.find(tagId) ==
+ android::util::kAtomsWithUidField.end()) {
+ VLOG("No uid to merge for atom %d", tagId);
+ return;
+ }
+ const vector<int>& additiveFields =
+ StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
+ ->second.additiveFields;
+ const vector<int>& nonAdditiveFields =
+ StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)
+ ->second.nonAdditiveFields;
+
+ // map of host uid to isolated uid data index in the original vector.
+ // because of non additive fields, there could be multiple of them that can't
+ // be merged into one
+ map<int, vector<int>> hostToIsolated;
+ // map of host uid to their position in the original vector
+ map<int, vector<int>> hostPosition;
+ vector<int> isolatedUidPos;
+ // all uids in the original vector
+ vector<int> allUids;
+ for (size_t i = 0; i < data.size(); i++) {
+ // uid field is always first primitive filed, if present
+ DimensionsValue* uidField = getFieldValue(data[i], tagId, 1);
+ if (!uidField) {
+ VLOG("Bad data for %d, %s", tagId, data[i]->ToString().c_str());
+ return;
+ }
+ int uid = uidField->value_int();
+ allUids.push_back(uid);
+ const int hostUid = uidMap->getHostUidOrSelf(uid);
+ if (hostUid != uid) {
+ uidField->set_value_int(hostUid);
+ hostToIsolated[hostUid].push_back(i);
+ isolatedUidPos.push_back(i);
+ }
+ }
+ vector<shared_ptr<LogEvent>> mergedData;
+ for (size_t i = 0; i < allUids.size(); i++) {
+ if (hostToIsolated.find(allUids[i]) != hostToIsolated.end()) {
+ hostPosition[allUids[i]].push_back(i);
+ } else if (std::find(isolatedUidPos.begin(), isolatedUidPos.end(), i) != isolatedUidPos.end()) {
+ continue;
+ } else {
+ mergedData.push_back(data[i]);
+ }
+ }
+ for (auto iter = hostToIsolated.begin(); iter != hostToIsolated.end();
+ iter++) {
+ int uid = iter->first;
+ vector<int>& isolated = hostToIsolated[uid];
+ vector<int> toBeMerged;
+ toBeMerged.insert(toBeMerged.begin(), isolated.begin(), isolated.end());
+ if (hostPosition.find(uid) != hostPosition.end()) {
+ vector<int>& host = hostPosition[uid];
+ toBeMerged.insert(toBeMerged.end(), host.begin(), host.end());
+ }
+ vector<bool> used(toBeMerged.size());
+ for (size_t i = 0; i < toBeMerged.size(); i++) {
+ if (used[i] == true) {
+ continue;
+ }
+ for (size_t j = i + 1; j < toBeMerged.size(); j++) {
+ shared_ptr<LogEvent>& lhs = data[toBeMerged[i]];
+ shared_ptr<LogEvent>& rhs = data[toBeMerged[j]];
+ if (shouldMerge(lhs, rhs, nonAdditiveFields, tagId)) {
+ mergeEvent(lhs, rhs, additiveFields, tagId);
+ used[j] = true;
+ }
+ }
+ }
+ for (size_t i = 0; i < toBeMerged.size(); i++) {
+ if (used[i] == false) {
+ mergedData.push_back(data[i]);
+ }
+ }
+ }
+ data.clear();
+ data = mergedData;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/puller_util.h b/cmds/statsd/src/external/puller_util.h
new file mode 100644
index 0000000..70d5321
--- /dev/null
+++ b/cmds/statsd/src/external/puller_util.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+#include "HashableDimensionKey.h"
+#include "StatsPuller.h"
+#include "logd/LogEvent.h"
+#include "packages/UidMap.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+void mergeIsolatedUidsToHostUid(std::vector<std::shared_ptr<LogEvent>>& data,
+ const sp<UidMap>& uidMap, int tagId);
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 1dcd853..c8857aa 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -294,6 +294,28 @@
}
}
+int LogEvent::GetInt(size_t key, status_t* err) const {
+ DimensionsValue value;
+ if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
+ *err = BAD_INDEX;
+ return 0;
+ }
+ const DimensionsValue* leafValue = getSingleLeafValue(&value);
+ switch (leafValue->value_case()) {
+ case DimensionsValue::ValueCase::kValueInt:
+ return leafValue->value_int();
+ case DimensionsValue::ValueCase::kValueLong:
+ case DimensionsValue::ValueCase::kValueBool:
+ case DimensionsValue::ValueCase::kValueFloat:
+ case DimensionsValue::ValueCase::kValueTuple:
+ case DimensionsValue::ValueCase::kValueStr:
+ case DimensionsValue::ValueCase::VALUE_NOT_SET: {
+ *err = BAD_TYPE;
+ return 0;
+ }
+ }
+}
+
const char* LogEvent::GetString(size_t key, status_t* err) const {
DimensionsValue value;
if (!GetSimpleAtomDimensionsValueProto(key, &value)) {
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index eb2c008..d521e09 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -76,6 +76,7 @@
* Returns BAD_TYPE if the index is available but the data is the wrong type.
*/
int64_t GetLong(size_t key, status_t* err) const;
+ int GetInt(size_t key, status_t* err) const;
const char* GetString(size_t key, status_t* err) const;
bool GetBool(size_t key, status_t* err) const;
float GetFloat(size_t key, status_t* err) const;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 3304f6c..f1da452 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -91,7 +91,7 @@
void removeIsolatedUid(int isolatedUid, int parentUid);
// Returns the host uid if it exists. Otherwise, returns the same uid that was passed-in.
- int getHostUidOrSelf(int uid) const;
+ virtual int getHostUidOrSelf(int uid) const;
// Gets the output. If every config key has received the output, then the output is cleared.
UidMapping getOutput(const ConfigKey& key);
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
new file mode 100644
index 0000000..7d9c8a8
--- /dev/null
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -0,0 +1,269 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "external/puller_util.h"
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+#include "../metrics/metrics_test_helper.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace testing;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
+using testing::Contains;
+/*
+ * Test merge isolated and host uid
+ */
+
+int uidAtomTagId = android::util::CPU_TIME_PER_UID_FREQ;
+int nonUidAtomTagId = android::util::SYSTEM_UPTIME;
+int timestamp = 1234;
+int isolatedUid = 30;
+int isolatedAdditiveData = 31;
+int isolatedNonAdditiveData = 32;
+int hostUid = 20;
+int hostAdditiveData = 21;
+int hostNonAdditiveData = 22;
+
+void extractIntoVector(vector<shared_ptr<LogEvent>> events,
+ vector<vector<int>>& ret) {
+ ret.clear();
+ status_t err;
+ for (const auto& event : events) {
+ vector<int> vec;
+ vec.push_back(event->GetInt(1, &err));
+ vec.push_back(event->GetInt(2, &err));
+ vec.push_back(event->GetInt(3, &err));
+ ret.push_back(vec);
+ }
+}
+
+TEST(puller_util, MergeNoDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ // 30->22->31
+ event->write(isolatedUid);
+ event->write(hostNonAdditiveData);
+ event->write(isolatedAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 20->22->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(hostNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+ .WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+ .WillRepeatedly(ReturnArg<0>());
+ mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 52};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, MergeWithDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ // 30->32->31
+ event->write(isolatedUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(isolatedAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 20->32->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 20->22->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(hostNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+ .WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+ .WillRepeatedly(ReturnArg<0>());
+ mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 21};
+ vector<int> expectedV2 = {20, 32, 52};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, NoMergeHostUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ // 20->32->31
+ event->write(hostUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(isolatedAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 20->22->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(hostNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+ .WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+ .WillRepeatedly(ReturnArg<0>());
+ mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, IsolatedUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ // 30->32->31
+ event->write(hostUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(isolatedAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 30->22->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(hostNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
+ .WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
+ .WillRepeatedly(ReturnArg<0>());
+ mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ // 30->32->31
+ event->write(isolatedUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(isolatedAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 31->32->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(isolatedUid + 1);
+ event->write(isolatedNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ // 20->32->21
+ event = make_shared<LogEvent>(uidAtomTagId, timestamp);
+ event->write(hostUid);
+ event->write(isolatedNonAdditiveData);
+ event->write(hostAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
+ mergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 73};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, NoNeedToMerge) {
+ vector<shared_ptr<LogEvent>> inputData;
+ shared_ptr<LogEvent> event =
+ make_shared<LogEvent>(nonUidAtomTagId, timestamp);
+ // 32
+ event->write(isolatedNonAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ event = make_shared<LogEvent>(nonUidAtomTagId, timestamp);
+ // 22
+ event->write(hostNonAdditiveData);
+ event->init();
+ inputData.push_back(event);
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ mergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId);
+
+ EXPECT_EQ(2, (int)inputData.size());
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index 0a97456..b48de540 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -15,6 +15,7 @@
#include "src/condition/ConditionWizard.h"
#include "src/external/StatsPullerManager.h"
+#include "src/packages/UidMap.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -40,6 +41,11 @@
MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
};
+class MockUidMap : public UidMap {
+ public:
+ MOCK_CONST_METHOD1(getHostUidOrSelf, int(int uid));
+};
+
HashableDimensionKey getMockedDimensionKey(int tagId, int key, std::string value);
MetricDimensionKey getMockedMetricDimensionKey(int tagId, int key, std::string value);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5ee7ede..4626cb2 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -348,4 +348,9 @@
* Returns is the caller has the same uid as the Recents component
*/
public abstract boolean isCallerRecents(int callingUid);
+
+ /**
+ * Whether an UID is active or idle.
+ */
+ public abstract boolean isUidActive(int uid);
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 2b648ea..eb26026 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -609,18 +609,19 @@
/**
* A key was pressed down.
+ * <p>
+ * If the focused view didn't want this event, this method is called.
+ * <p>
+ * Default implementation consumes {@link KeyEvent#KEYCODE_BACK KEYCODE_BACK}
+ * and, as of {@link android.os.Build.VERSION_CODES#P P}, {@link KeyEvent#KEYCODE_ESCAPE
+ * KEYCODE_ESCAPE} to later handle them in {@link #onKeyUp}.
*
- * <p>If the focused view didn't want this event, this method is called.
- *
- * <p>The default implementation consumed the KEYCODE_BACK to later
- * handle it in {@link #onKeyUp}.
- *
* @see #onKeyUp
* @see android.view.KeyEvent
*/
@Override
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
event.startTracking();
return true;
}
@@ -640,16 +641,18 @@
/**
* A key was released.
- *
- * <p>The default implementation handles KEYCODE_BACK to close the
- * dialog.
+ * <p>
+ * Default implementation consumes {@link KeyEvent#KEYCODE_BACK KEYCODE_BACK}
+ * and, as of {@link android.os.Build.VERSION_CODES#P P}, {@link KeyEvent#KEYCODE_ESCAPE
+ * KEYCODE_ESCAPE} to close the dialog.
*
* @see #onKeyDown
- * @see KeyEvent
+ * @see android.view.KeyEvent
*/
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
+ if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
+ && event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
return true;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 87f32b2..aa52cde 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -38,7 +38,6 @@
import android.content.Context;
import android.content.IRestrictionsManager;
import android.content.RestrictionsManager;
-import android.content.pm.ApplicationInfo;
import android.content.pm.CrossProfileApps;
import android.content.pm.ICrossProfileApps;
import android.content.pm.IShortcutService;
@@ -90,7 +89,6 @@
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
-import android.net.wifi.IRttManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.IWifiScanner;
import android.net.wifi.RttManager;
@@ -117,7 +115,6 @@
import android.os.IUserManager;
import android.os.IncidentManager;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RecoverySystem;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -639,13 +636,13 @@
registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
new CachedServiceFetcher<RttManager>() {
- @Override
- public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_SERVICE);
- IRttManager service = IRttManager.Stub.asInterface(b);
- return new RttManager(ctx.getOuterContext(), service,
- ConnectivityThread.getInstanceLooper());
- }});
+ @Override
+ public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_RANGING_SERVICE);
+ IWifiRttManager service = IWifiRttManager.Stub.asInterface(b);
+ return new RttManager(ctx.getOuterContext(),
+ new WifiRttManager(ctx.getOuterContext(), service));
+ }});
registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class,
new CachedServiceFetcher<WifiRttManager>() {
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 09a46b8..0342c93 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -468,6 +468,18 @@
dest.writeBoolean(mOverlayIsStatic);
dest.writeInt(compileSdkVersion);
dest.writeString(compileSdkVersionCodename);
+ writeSigningCertificateHistoryToParcel(dest, parcelableFlags);
+ }
+
+ private void writeSigningCertificateHistoryToParcel(Parcel dest, int parcelableFlags) {
+ if (signingCertificateHistory != null) {
+ dest.writeInt(signingCertificateHistory.length);
+ for (int i = 0; i < signingCertificateHistory.length; i++) {
+ dest.writeTypedArray(signingCertificateHistory[i], parcelableFlags);
+ }
+ } else {
+ dest.writeInt(-1);
+ }
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -523,6 +535,7 @@
mOverlayIsStatic = source.readBoolean();
compileSdkVersion = source.readInt();
compileSdkVersionCodename = source.readString();
+ readSigningCertificateHistoryFromParcel(source);
// The component lists were flattened with the redundant ApplicationInfo
// instances omitted. Distribute the canonical one here as appropriate.
@@ -534,6 +547,16 @@
}
}
+ private void readSigningCertificateHistoryFromParcel(Parcel source) {
+ int len = source.readInt();
+ if (len != -1) {
+ signingCertificateHistory = new Signature[len][];
+ for (int i = 0; i < len; i++) {
+ signingCertificateHistory[i] = source.createTypedArray(Signature.CREATOR);
+ }
+ }
+ }
+
private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
if (components != null) {
for (ComponentInfo ci : components) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f11e516..d14ac20 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7396,7 +7396,8 @@
*/
public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode";
- private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
+ private static final Validator NIGHT_DISPLAY_AUTO_MODE_VALIDATOR =
+ new SettingsValidators.InclusiveIntegerRangeValidator(0, 2);
/**
* Control the color temperature of Night Display, represented in Kelvin.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 79fc134..c460a33 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
+
import static java.lang.Math.max;
import android.animation.AnimatorInflater;
@@ -8378,7 +8379,7 @@
AccessibilityNodeProvider provider, AccessibilityNodeInfo info,
boolean forAutofill) {
structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
- null, null, null);
+ null, null, info.getViewIdResourceName());
Rect rect = structure.getTempRect();
info.getBoundsInParent(rect);
structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
@@ -8418,6 +8419,13 @@
CharSequence cname = info.getClassName();
structure.setClassName(cname != null ? cname.toString() : null);
structure.setContentDescription(info.getContentDescription());
+ if (forAutofill) {
+ final int maxTextLength = info.getMaxTextLength();
+ if (maxTextLength != -1) {
+ structure.setMaxTextLength(maxTextLength);
+ }
+ structure.setHint(info.getHintText());
+ }
if ((info.getText() != null || info.getError() != null)) {
structure.setText(info.getText(), info.getTextSelectionStart(),
info.getTextSelectionEnd());
@@ -8428,7 +8436,8 @@
final AutofillValue autofillValue = AutofillValue.forText(structure.getText());
structure.setAutofillValue(autofillValue);
if (info.isPassword()) {
- structure.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ structure.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
} else {
structure.setDataIsSensitive(false);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 63a9990..5131a8a 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -16,6 +16,10 @@
package android.view.autofill;
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.view.autofill.Helper.sDebug;
+import static android.view.autofill.Helper.sVerbose;
+
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -47,13 +51,14 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+
import org.xmlpull.v1.XmlPullParserException;
-import sun.misc.Cleaner;
import java.io.IOException;
import java.io.PrintWriter;
@@ -66,9 +71,7 @@
import java.util.List;
import java.util.Objects;
-import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
-import static android.view.autofill.Helper.sDebug;
-import static android.view.autofill.Helper.sVerbose;
+import sun.misc.Cleaner;
// TODO: use java.lang.ref.Cleaner once Android supports Java 9
@@ -616,10 +619,8 @@
/**
* @hide
*/
- public boolean isCompatibilityModeEnabled() {
- synchronized (mLock) {
- return mCompatibilityBridge != null;
- }
+ public boolean isCompatibilityModeEnabledLocked() {
+ return mCompatibilityBridge != null;
}
/**
@@ -1381,7 +1382,8 @@
@NonNull AutofillValue value, int flags) {
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
- + ", flags=" + flags + ", state=" + getStateAsStringLocked());
+ + ", flags=" + flags + ", state=" + getStateAsStringLocked()
+ + ", compatMode=" + isCompatibilityModeEnabledLocked());
}
if (mState != STATE_UNKNOWN && !isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
if (sVerbose) {
@@ -1392,7 +1394,7 @@
}
try {
final AutofillClient client = getClient();
- if (client == null) return; // NOTE: getClient() already logd it..
+ if (client == null) return; // NOTE: getClient() already logged it..
mSessionId = mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
@@ -1939,7 +1941,8 @@
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
- pw.print(pfx); pw.print("compat mode enabled: "); pw.println(isCompatibilityModeEnabled());
+ pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
+ isCompatibilityModeEnabledLocked());
pw.print(pfx); pw.print("debug: "); pw.print(sDebug);
pw.print(" verbose: "); pw.println(sVerbose);
}
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
index ad6020c..7d1c706 100644
--- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -98,6 +98,8 @@
if (mPayload != null) {
dest.writeInt(mPayload.length);
dest.writeByteArray(mPayload);
+ } else {
+ dest.writeInt(0);
}
}
}
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ed032c7..f6223fa 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -90,7 +90,7 @@
}
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
- jint weight, jint italic) {
+ jint givenWeight, jint givenItalic) {
uirenderer::FatVector<SkFontArguments::Axis, 2> skiaAxes;
for (const auto& axis : builder->axes) {
skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
@@ -114,15 +114,27 @@
std::shared_ptr<minikin::MinikinFont> minikinFont =
std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
builder->axes);
- minikin::Font::Builder fontBuilder(minikinFont);
- if (weight != RESOLVE_BY_FONT_TABLE) {
- fontBuilder.setWeight(weight);
+ int weight = givenWeight;
+ bool italic = givenItalic == 1;
+ if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
+ int os2Weight;
+ bool os2Italic;
+ if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
+ ALOGE("analyzeStyle failed. Using default style");
+ os2Weight = 400;
+ os2Italic = false;
+ }
+ if (givenWeight == RESOLVE_BY_FONT_TABLE) {
+ weight = os2Weight;
+ }
+ if (givenItalic == RESOLVE_BY_FONT_TABLE) {
+ italic = os2Italic;
+ }
}
- if (italic != RESOLVE_BY_FONT_TABLE) {
- fontBuilder.setSlant(static_cast<minikin::FontStyle::Slant>(italic != 0));
- }
- builder->fonts.push_back(fontBuilder.build());
+
+ builder->fonts.push_back(minikin::Font(minikinFont,
+ minikin::FontStyle(weight, static_cast<minikin::FontStyle::Slant>(italic))));
builder->axes.clear();
return true;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 482d028..115d0d5 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -576,7 +576,7 @@
minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
float saveSkewX = paint->getTextSkewX();
bool savefakeBold = paint->isFakeBoldText();
- MinikinFontSkia::populateSkPaint(paint, baseFont.font->typeface().get(), baseFont.fakery);
+ MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
SkScalar spacing = paint->getFontMetrics(metrics);
// The populateSkPaint call may have changed fake bold / text skew
// because we want to measure with those effects applied, so now
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index 0342c9c..d1c5db6 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -104,11 +104,6 @@
repeated InFlightProto outstanding_deliveries = 34;
- // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. It
- // should be either CosntantsProto.allow_while_idle_short_duration_ms or
- // ConstantsProto.allow_while_idle_long_duration_ms.
- optional int64 allow_while_idle_min_duration_ms = 35;
-
message LastAllowWhileIdleDispatch {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -121,7 +116,7 @@
}
// Whether the short or long while-idle timeout should be used for each UID.
- repeated int32 use_allow_while_idle_short_time = 42;
+ repeated int32 use_allow_while_idle_short_time = 35;
// For each uid, this is the last time we dispatched an "allow while idle"
// alarm, used to determine the earliest we can dispatch the next such alarm.
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index b5c3ac0..5cb5319 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -227,7 +227,6 @@
optional int32 setting_minimum = 1;
optional int32 setting_maximum = 2;
optional int32 setting_default = 3;
- optional int32 setting_for_vr_default = 4;
}
// True to decouple auto-suspend mode from the display state.
@@ -293,44 +292,27 @@
// The stay on while plugged in setting.
// A set of battery conditions under which to make the screen stay on.
optional StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
- // The screen brightness setting, from 0 to 255.
- // Use -1 if no value has been set.
- optional sint32 screen_brightness_setting = 30;
- // The screen auto-brightness adjustment setting, from -1 to 1.
- // Use 0 if there is no adjustment.
- optional float screen_auto_brightness_adjustment_setting = 31;
// The screen brightness mode.
- optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 32;
+ optional .android.providers.settings.SettingsProto.ScreenBrightnessMode screen_brightness_mode_setting = 30;
// The screen brightness setting override from the window manager
// to allow the current foreground activity to override the brightness.
// Use -1 to disable.
- optional sint32 screen_brightness_override_from_window_manager = 33;
+ optional sint32 screen_brightness_override_from_window_manager = 31;
// The user activity timeout override from the window manager
// to allow the current foreground activity to override the user activity
// timeout. Use -1 to disable.
- optional sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+ optional sint64 user_activity_timeout_override_from_window_manager_ms = 32;
// The window manager has determined the user to be inactive via other means.
// Set this to false to disable.
- optional bool is_user_inactive_override_from_window_manager = 35;
- // The screen brightness setting override from the settings application
- // to temporarily adjust the brightness until next updated,
- // Use -1 to disable.
- optional sint32 temporary_screen_brightness_setting_override = 36;
- // The screen brightness adjustment setting override from the settings
- // application to temporarily adjust the auto-brightness adjustment factor
- // until next updated, in the range -1..1.
- // Use NaN to disable.
- optional float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+ optional bool is_user_inactive_override_from_window_manager = 33;
// The screen state to use while dozing.
- optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 38;
+ optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 34;
// The screen brightness to use while dozing.
- optional float dozed_screen_brightness_override_from_dream_manager = 39;
+ optional float dozed_screen_brightness_override_from_dream_manager = 35;
// Screen brightness settings limits.
- optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
- // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
- optional int32 screen_brightness_for_vr_setting = 41;
+ optional ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 36;
// True if double tap to wake is enabled
- optional bool is_double_tap_wake_enabled = 42;
+ optional bool is_double_tap_wake_enabled = 37;
// True if we are currently in VR Mode.
- optional bool is_vr_mode_enabled = 43;
+ optional bool is_vr_mode_enabled = 38;
}
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 1ef74ba..d0565ca 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -472,11 +472,15 @@
### Non-printing keys ###
key ESCAPE {
- base: fallback BACK
+ base: none
alt, meta: fallback HOME
ctrl: fallback MENU
}
+key DEL {
+ ctrl+alt: fallback BACK
+}
+
### Gamepad buttons ###
key BUTTON_A {
diff --git a/data/keyboards/Virtual.kcm b/data/keyboards/Virtual.kcm
index c4647e0..c763cc09 100644
--- a/data/keyboards/Virtual.kcm
+++ b/data/keyboards/Virtual.kcm
@@ -469,11 +469,15 @@
### Non-printing keys ###
key ESCAPE {
- base: fallback BACK
+ base: none
alt, meta: fallback HOME
ctrl: fallback MENU
}
+key DEL {
+ ctrl+alt: fallback BACK
+}
+
### Gamepad buttons ###
key BUTTON_A {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index f5a6f49..8b5114c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -825,6 +825,14 @@
mFillPaint.setXfermode(mode);
}
+ /**
+ * @param aa to draw this drawable with
+ * @hide
+ */
+ public void setAntiAlias(boolean aa) {
+ mFillPaint.setAntiAlias(aa);
+ }
+
private void buildPathIfDirty() {
final GradientState st = mGradientState;
if (mPathIsDirty) {
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index dca9ef5..091b526 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -132,8 +132,8 @@
bool italicFromFont;
const minikin::FontStyle defaultStyle;
- const minikin::MinikinFont* mf = families.empty() ? nullptr
- : families[0]->getClosestMatch(defaultStyle).font->typeface().get();
+ const minikin::MinikinFont* mf =
+ families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
if (mf != nullptr) {
SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
const SkFontStyle& style = skTypeface->fontStyle();
@@ -183,7 +183,7 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
std::vector<minikin::Font> fonts;
- fonts.push_back(minikin::Font::Builder(font).build());
+ fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
std::shared_ptr<minikin::FontCollection> collection = std::make_shared<minikin::FontCollection>(
std::make_shared<minikin::FontFamily>(std::move(fonts)));
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index e424a26..2232c25 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -57,7 +57,7 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
std::vector<minikin::Font> fonts;
- fonts.push_back(minikin::Font::Builder(font).build());
+ fonts.push_back(minikin::Font(std::move(font), minikin::FontStyle()));
return std::make_shared<minikin::FontFamily>(std::move(fonts));
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 6ef3fac..1cff59c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -865,30 +865,49 @@
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
- <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
- <string name="power_remaining_duration_only">About <xliff:g id="time">^1</xliff:g> left</string>
- <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
- <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">^1</xliff:g> left based on your usage</string>
- <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
- <string name="power_remaining_charging_duration_only"><xliff:g id="time">^1</xliff:g> left until fully charged</string>
+ <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
+ <string name="power_remaining_duration_only">About <xliff:g id="time">%1$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=60] Label for estimated remaining duration of battery discharging -->
+ <string name="power_remaining_duration_only_enhanced">About <xliff:g id="time">%1$s</xliff:g> left based on your usage</string>
+ <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
+ <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
- <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
- <string name="power_remaining_duration_only_short"><xliff:g id="time">^1</xliff:g> left</string>
- <!-- [CHAR_LIMIT=60] Short label for estimated remaining duration of battery charging/discharging -->
- <string name="power_remaining_duration_only_short_enhanced"><xliff:g id="time">^1</xliff:g> left based on your usage</string>
+ <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+ <string name="power_remaining_duration_only_short"><xliff:g id="time">%1$s</xliff:g> left</string>
- <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
- <string name="power_discharging_duration"><xliff:g id="level">^1</xliff:g> - about <xliff:g id="time">^2</xliff:g> left</string>
- <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
- <string name="power_discharging_duration_enhanced"><xliff:g id="level">^1</xliff:g> - about <xliff:g id="time">^2</xliff:g> left based on your usage</string>
+ <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount -->
+ <string name="power_remaining_less_than_duration_only">Less than <xliff:g id="threshold">%1$s</xliff:g> remaining</string>
+ <!-- [CHAR_LIMIT=60] label for estimated remaining duration of battery when under a certain amount with the percentage -->
+ <string name="power_remaining_less_than_duration"><xliff:g id="level">%1$s</xliff:g> - Less than <xliff:g id="threshold">%2$s</xliff:g> remaining</string>
- <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
- <string name="power_discharging_duration_short"><xliff:g id="level">^1</xliff:g> - <xliff:g id="time">^2</xliff:g> left</string>
+ <!-- Used to let users know that they have more than some amount of battery life remaining with percentage. ex: 75% - more than 1 day remaining [CHAR LIMIT = 80] -->
+ <string name="power_remaining_more_than_subtext"><xliff:g id="level">%1$s</xliff:g>more than <xliff:g id="time_remaining">%2$s</xliff:g> remaining</string>
+ <!-- Used to let users know that they have more than some amount of battery life remaining. ex: more than 1 day remaining [CHAR LIMIT = 40] -->
+ <string name="power_remaining_only_more_than_subtext">more than <xliff:g id="time_remaining">%1$s</xliff:g> remaining</string>
+
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="default">phone may shutdown soon</string>
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="tablet">tablet may shutdown soon</string>
+ <!-- [CHAR_LIMIT=50] Short label for imminent shutdown warning of device -->
+ <string name="power_remaining_duration_only_shutdown_imminent" product="device">device may shutdown soon</string>
+
+ <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
+ <string name="power_discharging_duration"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
+ <string name="power_discharging_duration_enhanced"><xliff:g id="level">%1$s</xliff:g> - about <xliff:g id="time">%2$s</xliff:g> left based on your usage</string>
+
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="default"><xliff:g id="level">%1$s</xliff:g> - phone may shutdown soon</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="tablet"><xliff:g id="level">%1$s</xliff:g> - tablet may shutdown soon</string>
+ <!-- [CHAR_LIMIT=60] Label for battery level chart when shutdown is imminent-->
+ <string name="power_remaining_duration_shutdown_imminent" product="device"><xliff:g id="level">%1$s</xliff:g> - device may shutdown soon</string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
<string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="state">%2$s</xliff:g></string>
<!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
- <string name="power_charging_duration"><xliff:g id="level">^1</xliff:g> - <xliff:g id="time">^2</xliff:g> until fully charged</string>
+ <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until fully charged</string>
<!-- Battery Info screen. Value for a status item. Used for diagnostic info screens, precise translation isn't needed -->
<string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 190f5e6..68ead09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -17,7 +17,6 @@
import android.annotation.LayoutRes;
import android.annotation.Nullable;
-import android.app.ActionBar;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -72,9 +71,9 @@
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
super.setContentView(R.layout.settings_with_drawer);
- mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
+ mContentHeaderContainer = findViewById(R.id.content_header_container);
- Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
+ Toolbar toolbar = findViewById(R.id.action_bar);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
return;
@@ -89,7 +88,9 @@
@Override
public boolean onNavigateUp() {
- finish();
+ if (!super.onNavigateUp()) {
+ finish();
+ }
return true;
}
@@ -104,11 +105,6 @@
registerReceiver(mPackageReceiver, filter);
new CategoriesUpdateTask().execute();
- final Intent intent = getIntent();
- if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
- // Intent explicitly set to show menu.
- showMenuIcon();
- }
}
@Override
@@ -125,13 +121,6 @@
mCategoryListeners.remove(listener);
}
- public void setContentHeaderView(View headerView) {
- mContentHeaderContainer.removeAllViews();
- if (headerView != null) {
- mContentHeaderContainer.addView(headerView);
- }
- }
-
@Override
public void setContentView(@LayoutRes int layoutResID) {
final ViewGroup parent = findViewById(R.id.content_frame);
@@ -151,13 +140,6 @@
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- private void showMenuIcon() {
- final ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- }
- }
-
private void onCategoriesChanged() {
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
@@ -165,10 +147,6 @@
}
}
- public void onProfileTileOpen() {
- finish();
- }
-
/**
* @return whether or not the enabled state actually changed.
*/
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
new file mode 100644
index 0000000..346ca66
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.utils;
+
+import android.content.Context;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import com.android.settingslib.R;
+import com.android.settingslib.utils.StringUtil;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/** Utility class for keeping power related strings consistent**/
+public class PowerUtil {
+ private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7);
+ private static final long FIFTEEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(15);
+ private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1);
+
+ /**
+ * This method produces the text used in various places throughout the system to describe the
+ * remaining battery life of the phone in a consistent manner.
+ *
+ * @param context
+ * @param drainTimeMs The estimated time remaining before the phone dies in milliseconds.
+ * @param percentageString An optional percentage of battery remaining string.
+ * @param basedOnUsage Whether this estimate is based on usage or simple extrapolation.
+ * @return a properly formatted and localized string describing how much time remains
+ * before the battery runs out.
+ */
+ public static String getBatteryRemainingStringFormatted(Context context, long drainTimeMs,
+ @Nullable String percentageString, boolean basedOnUsage) {
+ if (drainTimeMs > 0) {
+ if (drainTimeMs <= SEVEN_MINUTES_MILLIS) {
+ // show a imminent shutdown warning if less than 7 minutes remain
+ return getShutdownImminentString(context, percentageString);
+ } else if (drainTimeMs <= FIFTEEN_MINUTES_MILLIS) {
+ // show a less than 15 min remaining warning if appropriate
+ CharSequence timeString = StringUtil.formatElapsedTime(context,
+ FIFTEEN_MINUTES_MILLIS,
+ false /* withSeconds */);
+ return getUnderFifteenString(context, timeString, percentageString);
+ } else if (drainTimeMs >= ONE_DAY_MILLIS) {
+ // just say more than one day if over 24 hours
+ return getMoreThanOneDayString(context, percentageString);
+ } else {
+ // show a regular time remaining string
+ return getRegularTimeRemainingString(context, drainTimeMs,
+ percentageString, basedOnUsage);
+ }
+ }
+ return null;
+ }
+
+ private static String getShutdownImminentString(Context context, String percentageString) {
+ return TextUtils.isEmpty(percentageString)
+ ? context.getString(R.string.power_remaining_duration_only_shutdown_imminent)
+ : context.getString(
+ R.string.power_remaining_duration_shutdown_imminent,
+ percentageString);
+ }
+
+ private static String getUnderFifteenString(Context context, CharSequence timeString,
+ String percentageString) {
+ return TextUtils.isEmpty(percentageString)
+ ? context.getString(R.string.power_remaining_less_than_duration_only, timeString)
+ : context.getString(
+ R.string.power_remaining_less_than_duration,
+ percentageString,
+ timeString);
+
+ }
+
+ private static String getMoreThanOneDayString(Context context, String percentageString) {
+ final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0);
+ final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT);
+
+ final Measure daysMeasure = new Measure(1, MeasureUnit.DAY);
+
+ return TextUtils.isEmpty(percentageString)
+ ? context.getString(R.string.power_remaining_only_more_than_subtext,
+ frmt.formatMeasures(daysMeasure))
+ : context.getString(
+ R.string.power_remaining_more_than_subtext,
+ percentageString,
+ frmt.formatMeasures(daysMeasure));
+ }
+
+ private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
+ String percentageString, boolean basedOnUsage) {
+ // round to the nearest 15 min to not appear oversly precise
+ final long roundedTimeMs = roundToNearestThreshold(drainTimeMs,
+ FIFTEEN_MINUTES_MILLIS);
+ CharSequence timeString = StringUtil.formatElapsedTime(context,
+ roundedTimeMs,
+ false /* withSeconds */);
+ if (TextUtils.isEmpty(percentageString)) {
+ int id = basedOnUsage
+ ? R.string.power_remaining_duration_only_enhanced
+ : R.string.power_remaining_duration_only;
+ return context.getString(id, timeString);
+ } else {
+ int id = basedOnUsage
+ ? R.string.power_discharging_duration_enhanced
+ : R.string.power_discharging_duration;
+ return context.getString(id, percentageString, timeString);
+ }
+ }
+
+ public static long convertUsToMs(long timeUs) {
+ return timeUs / 1000;
+ }
+
+ public static long convertMsToUs(long timeMs) {
+ return timeMs * 1000;
+ }
+
+ private static long roundToNearestThreshold(long drainTime, long threshold) {
+ final long remainder = drainTime % threshold;
+ if (remainder < threshold / 2) {
+ return drainTime - remainder;
+ } else {
+ return drainTime - remainder + threshold;
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
new file mode 100644
index 0000000..45fdd78
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.utils;
+
+import android.content.Context;
+import android.icu.text.MeasureFormat;
+import android.icu.text.MeasureFormat.FormatWidth;
+import android.icu.text.RelativeDateTimeFormatter;
+import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
+import android.icu.util.ULocale;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.TtsSpan;
+import java.util.ArrayList;
+import java.util.Locale;
+
+/** Utility class for generally useful string methods **/
+public class StringUtil {
+
+ public static final int SECONDS_PER_MINUTE = 60;
+ public static final int SECONDS_PER_HOUR = 60 * 60;
+ public static final int SECONDS_PER_DAY = 24 * 60 * 60;
+
+ /**
+ * Returns elapsed time for the given millis, in the following format:
+ * 2d 5h 40m 29s
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @param withSeconds include seconds?
+ * @return the formatted elapsed time
+ */
+ public static CharSequence formatElapsedTime(Context context, double millis,
+ boolean withSeconds) {
+ SpannableStringBuilder sb = new SpannableStringBuilder();
+ int seconds = (int) Math.floor(millis / 1000);
+ if (!withSeconds) {
+ // Round up.
+ seconds += 30;
+ }
+
+ int days = 0, hours = 0, minutes = 0;
+ if (seconds >= SECONDS_PER_DAY) {
+ days = seconds / SECONDS_PER_DAY;
+ seconds -= days * SECONDS_PER_DAY;
+ }
+ if (seconds >= SECONDS_PER_HOUR) {
+ hours = seconds / SECONDS_PER_HOUR;
+ seconds -= hours * SECONDS_PER_HOUR;
+ }
+ if (seconds >= SECONDS_PER_MINUTE) {
+ minutes = seconds / SECONDS_PER_MINUTE;
+ seconds -= minutes * SECONDS_PER_MINUTE;
+ }
+
+ final ArrayList<Measure> measureList = new ArrayList(4);
+ if (days > 0) {
+ measureList.add(new Measure(days, MeasureUnit.DAY));
+ }
+ if (hours > 0) {
+ measureList.add(new Measure(hours, MeasureUnit.HOUR));
+ }
+ if (minutes > 0) {
+ measureList.add(new Measure(minutes, MeasureUnit.MINUTE));
+ }
+ if (withSeconds && seconds > 0) {
+ measureList.add(new Measure(seconds, MeasureUnit.SECOND));
+ }
+ if (measureList.size() == 0) {
+ // Everything addable was zero, so nothing was added. We add a zero.
+ measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
+ }
+ final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
+
+ final Locale locale = context.getResources().getConfiguration().locale;
+ final MeasureFormat measureFormat = MeasureFormat.getInstance(
+ locale, FormatWidth.NARROW);
+ sb.append(measureFormat.formatMeasures(measureArray));
+
+ if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
+ // Add ttsSpan if it only have minute value, because it will be read as "meters"
+ final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes)
+ .setUnit("minute").build();
+ sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ return sb;
+ }
+
+ /**
+ * Returns relative time for the given millis in the past, in a short format such as "2 days
+ * ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+ *
+ * <p>The unit is chosen to have good information value while only using one unit. So 27 hours
+ * and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
+ * "2 days ago".
+ *
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @param withSeconds include seconds?
+ * @return the formatted elapsed time
+ */
+ public static CharSequence formatRelativeTime(Context context, double millis,
+ boolean withSeconds) {
+ final int seconds = (int) Math.floor(millis / 1000);
+ final RelativeUnit unit;
+ final int value;
+ if (withSeconds && seconds < 2 * SECONDS_PER_MINUTE) {
+ unit = RelativeUnit.SECONDS;
+ value = seconds;
+ } else if (seconds < 2 * SECONDS_PER_HOUR) {
+ unit = RelativeUnit.MINUTES;
+ value = (seconds + SECONDS_PER_MINUTE / 2)
+ / SECONDS_PER_MINUTE;
+ } else if (seconds < 2 * SECONDS_PER_DAY) {
+ unit = RelativeUnit.HOURS;
+ value = (seconds + SECONDS_PER_HOUR / 2)
+ / SECONDS_PER_HOUR;
+ } else {
+ unit = RelativeUnit.DAYS;
+ value = (seconds + SECONDS_PER_DAY / 2)
+ / SECONDS_PER_DAY;
+ }
+
+ final Locale locale = context.getResources().getConfiguration().locale;
+ final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
+ ULocale.forLocale(locale),
+ null /* default NumberFormat */,
+ RelativeDateTimeFormatter.Style.SHORT,
+ android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
+
+ return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index 003f905..2f417ad 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -18,8 +18,6 @@
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import android.app.Instrumentation;
@@ -49,42 +47,22 @@
}
@Test
- public void startActivityWithNoExtra_showNoNavUp() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- instrumentation.startActivitySync(new Intent(instrumentation.getTargetContext(),
- TestActivity.class));
-
- onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
- .check(doesNotExist());
- }
-
- @Test
- public void startActivityWithExtraToHideMenu_showNavUp() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
- .putExtra(TestActivity.EXTRA_SHOW_MENU, false);
+ public void startActivity_doNotShowNavUp() {
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ final Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instrumentation.startActivitySync(intent);
onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
.check(doesNotExist());
}
- @Test
- public void startActivityWithExtraToShowMenu_showNavUp() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Intent intent = new Intent(instrumentation.getTargetContext(), TestActivity.class)
- .putExtra(TestActivity.EXTRA_SHOW_MENU, true);
- instrumentation.startActivitySync(intent);
-
- onView(withContentDescription(com.android.internal.R.string.action_bar_up_description))
- .check(matches(isDisplayed()));
- }
-
/**
* Test Activity in this test.
*
* Use this activity because SettingsDrawerActivity hasn't been registered in its
* AndroidManifest.xml
*/
- public static class TestActivity extends SettingsDrawerActivity {}
+ public static class TestActivity extends SettingsDrawerActivity {
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
new file mode 100644
index 0000000..f93210f
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import com.android.settingslib.R;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import com.android.settingslib.utils.PowerUtil;
+import java.time.Duration;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class PowerUtilTest {
+ public static final String TEST_BATTERY_LEVEL_10 = "10%";
+ public static final String FIFTEEN_MIN_FORMATTED = "15m";
+ public static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis();
+ public static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis();
+ public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
+ public static final long TWO_DAYS_MILLIS = Duration.ofDays(2).toMillis();
+ public static final String ONE_DAY_FORMATTED = "1 day";
+
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_withPercentage() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ SEVENTEEN_MIN_MILLIS,
+ TEST_BATTERY_LEVEL_10,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ SEVENTEEN_MIN_MILLIS,
+ TEST_BATTERY_LEVEL_10,
+ false /* basedOnUsage */);
+
+ // We only add special mention for the long string
+ assertThat(info).isEqualTo(mContext.getString(
+ R.string.power_discharging_duration_enhanced,
+ TEST_BATTERY_LEVEL_10,
+ FIFTEEN_MIN_FORMATTED));
+ // shortened string should not have extra text
+ assertThat(info2).isEqualTo(mContext.getString(
+ R.string.power_discharging_duration,
+ TEST_BATTERY_LEVEL_10,
+ FIFTEEN_MIN_FORMATTED));
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_noPercentage() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ SEVENTEEN_MIN_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ SEVENTEEN_MIN_MILLIS,
+ null /* percentageString */,
+ false /* basedOnUsage */);
+
+ // We only add special mention for the long string
+ assertThat(info).isEqualTo(mContext.getString(
+ R.string.power_remaining_duration_only_enhanced,
+ FIFTEEN_MIN_FORMATTED));
+ // shortened string should not have extra text
+ assertThat(info2).isEqualTo(mContext.getString(
+ R.string.power_remaining_duration_only,
+ FIFTEEN_MIN_FORMATTED));
+ }
+
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_lessThanSevenMinutes_usesCorrectString() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ FIVE_MINUTES_MILLIS,
+ TEST_BATTERY_LEVEL_10 /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ FIVE_MINUTES_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+
+ // additional battery percentage in this string
+ assertThat(info).isEqualTo(mContext.getString(
+ R.string.power_remaining_duration_shutdown_imminent,
+ TEST_BATTERY_LEVEL_10));
+ // shortened string should not have percentage
+ assertThat(info2).isEqualTo(mContext.getString(
+ R.string.power_remaining_duration_only_shutdown_imminent));
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_betweenSevenAndFifteenMinutes_usesCorrectString() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TEN_MINUTES_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TEN_MINUTES_MILLIS,
+ TEST_BATTERY_LEVEL_10 /* percentageString */,
+ true /* basedOnUsage */);
+
+ // shortened string should not have percentage
+ assertThat(info).isEqualTo(mContext.getString(
+ R.string.power_remaining_less_than_duration_only,
+ FIFTEEN_MIN_FORMATTED));
+ // Add percentage to string when provided
+ assertThat(info2).isEqualTo(mContext.getString(
+ R.string.power_remaining_less_than_duration,
+ TEST_BATTERY_LEVEL_10,
+ FIFTEEN_MIN_FORMATTED));
+ }
+
+ @Test
+ public void testGetBatteryRemainingStringFormatted_moreThanOneDay_usesCorrectString() {
+ String info = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TWO_DAYS_MILLIS,
+ null /* percentageString */,
+ true /* basedOnUsage */);
+ String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext,
+ TWO_DAYS_MILLIS,
+ TEST_BATTERY_LEVEL_10 /* percentageString */,
+ true /* basedOnUsage */);
+
+ // shortened string should not have percentage
+ assertThat(info).isEqualTo(mContext.getString(
+ R.string.power_remaining_only_more_than_subtext,
+ ONE_DAY_FORMATTED));
+ // Add percentage to string when provided
+ assertThat(info2).isEqualTo(mContext.getString(
+ R.string.power_remaining_more_than_subtext,
+ TEST_BATTERY_LEVEL_10,
+ ONE_DAY_FORMATTED));
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
new file mode 100644
index 0000000..d5e3cdb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.text.SpannableStringBuilder;
+import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.TestConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class StringUtilTest {
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = spy(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void testFormatElapsedTime_WithSeconds_ShowSeconds() {
+ final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "5m 30s";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_NoSeconds_DoNotShowSeconds() {
+ final double testMillis = 5 * DateUtils.MINUTE_IN_MILLIS + 30 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "6m";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_TimeMoreThanOneDay_ShowCorrectly() {
+ final double testMillis = 2 * DateUtils.DAY_IN_MILLIS
+ + 4 * DateUtils.HOUR_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
+ final String expectedTime = "2d 4h 15m";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_ZeroFieldsInTheMiddleDontShow() {
+ final double testMillis = 2 * DateUtils.DAY_IN_MILLIS + 15 * DateUtils.MINUTE_IN_MILLIS;
+ final String expectedTime = "2d 15m";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_FormatZero_WithSeconds() {
+ final double testMillis = 0;
+ final String expectedTime = "0s";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, true).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_FormatZero_NoSeconds() {
+ final double testMillis = 0;
+ final String expectedTime = "0m";
+
+ assertThat(StringUtil.formatElapsedTime(mContext, testMillis, false).toString())
+ .isEqualTo(expectedTime);
+ }
+
+ @Test
+ public void testFormatElapsedTime_onlyContainsMinute_hasTtsSpan() {
+ final double testMillis = 15 * DateUtils.MINUTE_IN_MILLIS;
+
+ final CharSequence charSequence =
+ StringUtil.formatElapsedTime(mContext, testMillis, false);
+ assertThat(charSequence).isInstanceOf(SpannableStringBuilder.class);
+
+ final SpannableStringBuilder expectedString = (SpannableStringBuilder) charSequence;
+ final TtsSpan[] ttsSpans = expectedString.getSpans(0, expectedString.length(),
+ TtsSpan.class);
+
+ assertThat(ttsSpans).asList().hasSize(1);
+ assertThat(ttsSpans[0].getType()).isEqualTo(TtsSpan.TYPE_MEASURE);
+ }
+
+ @Test
+ public void testFormatRelativeTime_WithSeconds_ShowSeconds() {
+ final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "40 sec. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_NoSeconds_DoNotShowSeconds() {
+ final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "1 min. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_LessThanTwoMinutes_withSeconds() {
+ final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "119 sec. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_LessThanTwoMinutes_NoSeconds() {
+ final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
+ final String expectedTime = "2 min. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_TwoMinutes_withSeconds() {
+ final double testMillis = 2 * DateUtils.MINUTE_IN_MILLIS;
+ final String expectedTime = "2 min. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_LessThanTwoHours_withSeconds() {
+ final double testMillis = 119 * DateUtils.MINUTE_IN_MILLIS;
+ final String expectedTime = "119 min. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_TwoHours_withSeconds() {
+ final double testMillis = 2 * DateUtils.HOUR_IN_MILLIS;
+ final String expectedTime = "2 hr. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_LessThanTwoDays_withSeconds() {
+ final double testMillis = 47 * DateUtils.HOUR_IN_MILLIS;
+ final String expectedTime = "47 hr. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_TwoDays_withSeconds() {
+ final double testMillis = 2 * DateUtils.DAY_IN_MILLIS;
+ final String expectedTime = "2 days ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_FormatZero_WithSeconds() {
+ final double testMillis = 0;
+ final String expectedTime = "0 sec. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
+ expectedTime);
+ }
+
+ @Test
+ public void testFormatRelativeTime_FormatZero_NoSeconds() {
+ final double testMillis = 0;
+ final String expectedTime = "0 min. ago";
+
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
+ expectedTime);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index aa56694..3a2b12f 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -26,10 +26,6 @@
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.IntentFilter;
-import android.icu.text.MeasureFormat;
-import android.icu.text.MeasureFormat.FormatWidth;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
import android.media.AudioAttributes;
import android.os.AsyncTask;
import android.os.Handler;
@@ -37,11 +33,11 @@
import android.os.PowerManager;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
-import android.text.format.DateUtils;
import android.util.Slog;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.settingslib.Utils;
+import com.android.settingslib.utils.PowerUtil;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -49,8 +45,6 @@
import java.io.PrintWriter;
import java.text.NumberFormat;
-import java.util.Locale;
-import java.util.concurrent.TimeUnit;
public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String TAG = PowerUI.TAG + ".Notification";
@@ -200,12 +194,7 @@
// override notification copy if hybrid notification enabled
if (mEstimate != null) {
title = mContext.getString(R.string.battery_low_title_hybrid);
- contentText = mContext.getString(
- mEstimate.isBasedOnUsage
- ? R.string.battery_low_percent_format_hybrid
- : R.string.battery_low_percent_format_hybrid_short,
- percentage,
- getTimeRemainingFormatted());
+ contentText = getHybridContentString(percentage);
}
final Notification.Builder nb =
@@ -239,21 +228,12 @@
mNoMan.notifyAsUser(TAG_BATTERY, SystemMessage.NOTE_POWER_LOW, n, UserHandle.ALL);
}
- @VisibleForTesting
- String getTimeRemainingFormatted() {
- final Locale currentLocale = mContext.getResources().getConfiguration().getLocales().get(0);
- MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.NARROW);
-
- final long remainder = mEstimate.estimateMillis % DateUtils.HOUR_IN_MILLIS;
- final long hours = TimeUnit.MILLISECONDS.toHours(
- mEstimate.estimateMillis - remainder);
- // round down to the nearest 15 min for now to not appear overly precise
- final long minutes = TimeUnit.MILLISECONDS.toMinutes(
- remainder - (remainder % TimeUnit.MINUTES.toMillis(15)));
- final Measure hoursMeasure = new Measure(hours, MeasureUnit.HOUR);
- final Measure minutesMeasure = new Measure(minutes, MeasureUnit.MINUTE);
-
- return frmt.formatMeasures(hoursMeasure, minutesMeasure);
+ private String getHybridContentString(String percentage) {
+ return PowerUtil.getBatteryRemainingStringFormatted(
+ mContext,
+ mEstimate.estimateMillis,
+ percentage,
+ mEstimate.isBasedOnUsage);
}
private PendingIntent pendingBroadcast(String action) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 3b9e7bc..65135ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -104,6 +104,11 @@
setMeasuredDimension(width, height);
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
private static int exactly(int size) {
return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index d6beb7f..ab89a52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -249,6 +249,9 @@
(GradientDrawable) ((LayerDrawable) mBackground).getDrawable(0);
gradientDrawable.setXfermode(
running ? new PorterDuffXfermode(PorterDuff.Mode.SRC) : null);
+ // Speed optimization: disable AA if transfer mode is not SRC_OVER. AA is not easy to
+ // spot during animation anyways.
+ gradientDrawable.setAntiAlias(!running);
}
if (!mExpandAnimationRunning) {
setDrawableAlpha(mDrawableAlpha);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index 3e37cfe..bf6cc53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -151,22 +151,4 @@
verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
eq(SystemMessage.NOTE_THERMAL_SHUTDOWN), any());
}
-
- @Test
- public void testGetTimeRemainingFormatted_roundsDownTo15() {
- mPowerNotificationWarnings.updateEstimate(
- new Estimate(TimeUnit.MINUTES.toMillis(57), true));
- String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
-
- assertTrue("time:" + time + ", expected: " + FORMATTED_45M, time.equals(FORMATTED_45M));
- }
-
- @Test
- public void testGetTimeRemainingFormatted_keepsMinutesWhenZero() {
- mPowerNotificationWarnings.updateEstimate(
- new Estimate(TimeUnit.MINUTES.toMillis(65), true));
- String time = mPowerNotificationWarnings.getTimeRemainingFormatted();
-
- assertTrue("time:" + time + ", expected: " + FORMATTED_HOUR, time.equals(FORMATTED_HOUR));
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
index a10bebf..e1b97bda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/LocationControllerImplTest.java
@@ -29,12 +29,14 @@
import com.android.systemui.statusbar.policy.LocationController.LocationChangeCallback;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
+@Ignore
public class LocationControllerImplTest extends SysuiTestCase {
private LocationControllerImpl mLocationController;
@@ -79,4 +81,4 @@
TestableLooper.get(this).processAllMessages();
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 17c617c..355da2d 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -98,7 +98,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.LocalLog;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker.Listener;
/**
* Alarm manager implementaion.
@@ -249,7 +250,7 @@
private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
new SparseArray<>();
- private final ForceAppStandbyTracker mForceAppStandbyTracker;
+ private AppStateTracker mAppStateTracker;
private boolean mAppStandbyParole;
private ArrayMap<Pair<String, Integer>, Long> mLastAlarmDeliveredForPackage = new ArrayMap<>();
@@ -707,9 +708,6 @@
super(context);
mConstants = new Constants(mHandler);
- mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
- mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
-
publishLocalService(AlarmManagerInternal.class, new LocalService());
}
@@ -1329,13 +1327,15 @@
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_SYSTEM_SERVICES_READY) {
- mForceAppStandbyTracker.start();
mConstants.start(getContext().getContentResolver());
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+
+ mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+ mAppStateTracker.addListener(mForceAppStandbyListener);
}
}
@@ -1729,7 +1729,8 @@
// timing restrictions.
} else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
|| callingUid == mSystemUiUid
- || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
+ || (mAppStateTracker != null
+ && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) {
flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
}
@@ -1812,8 +1813,10 @@
mConstants.dump(pw);
pw.println();
- mForceAppStandbyTracker.dump(pw, " ");
- pw.println();
+ if (mAppStateTracker != null) {
+ mAppStateTracker.dump(pw, " ");
+ pw.println();
+ }
pw.println(" App Standby Parole: " + mAppStandbyParole);
pw.println();
@@ -2161,8 +2164,10 @@
mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
- mForceAppStandbyTracker.dumpProto(proto,
- AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+ if (mAppStateTracker != null) {
+ mAppStateTracker.dumpProto(proto,
+ AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+ }
proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
if (!mInteractive) {
@@ -2942,7 +2947,7 @@
}
final String sourcePackage = alarm.sourcePackage;
final int sourceUid = alarm.creatorUid;
- return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage,
+ return mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage,
allowWhileIdle);
}
@@ -2955,7 +2960,7 @@
private long getWhileIdleMinIntervalLocked(int uid) {
final boolean dozing = mPendingIdleUntil != null;
- final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
+ final boolean ebs = mAppStateTracker.isForceAllAppsStandbyEnabled();
if (!dozing && !ebs) {
return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
}
@@ -4133,7 +4138,7 @@
if (allowWhileIdle) {
// Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
- if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) {
+ if (mAppStateTracker.isUidInForeground(alarm.creatorUid)) {
mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);
} else {
mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/AppStateTracker.java
similarity index 95%
rename from services/core/java/com/android/server/ForceAppStandbyTracker.java
rename to services/core/java/com/android/server/AppStateTracker.java
index 100680d..51dff56 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -54,7 +54,6 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.DeviceIdleController.LocalService;
import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
@@ -73,14 +72,14 @@
* TODO: Make it a LocalService.
*
* Test:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
*/
-public class ForceAppStandbyTracker {
+public class AppStateTracker {
private static final String TAG = "ForceAppStandbyTracker";
private static final boolean DEBUG = true;
- @GuardedBy("ForceAppStandbyTracker.class")
- private static ForceAppStandbyTracker sInstance;
+ @GuardedBy("AppStateTracker.class")
+ private static AppStateTracker sInstance;
private final Object mLock = new Object();
private final Context mContext;
@@ -89,6 +88,7 @@
static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
IActivityManager mIActivityManager;
+ ActivityManagerInternal mActivityManagerInternal;
AppOpsManager mAppOpsManager;
IAppOpsService mAppOpsService;
PowerManagerInternal mPowerManagerInternal;
@@ -172,6 +172,9 @@
int EXEMPT_CHANGED = 6;
int FORCE_ALL_CHANGED = 7;
int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
+
+ int IS_UID_ACTIVE_CACHED = 9;
+ int IS_UID_ACTIVE_RAW = 10;
}
private final StatLogger mStatLogger = new StatLogger(new String[] {
@@ -184,6 +187,9 @@
"EXEMPT_CHANGED",
"FORCE_ALL_CHANGED",
"FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
+
+ "IS_UID_ACTIVE_CACHED",
+ "IS_UID_ACTIVE_RAW",
});
@VisibleForTesting
@@ -249,7 +255,7 @@
/**
* This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
*/
- private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
+ private void onRunAnyAppOpsChanged(AppStateTracker sender,
int uid, @NonNull String packageName) {
updateJobsForUidPackage(uid, packageName);
@@ -264,14 +270,14 @@
/**
* This is called when the foreground state changed for a UID.
*/
- private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+ private void onUidForegroundStateChanged(AppStateTracker sender, int uid) {
onUidForeground(uid, sender.isUidInForeground(uid));
}
/**
* This is called when the active/idle state changed for a UID.
*/
- private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) {
+ private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
updateJobsForUid(uid);
if (sender.isUidActive(uid)) {
@@ -282,7 +288,7 @@
/**
* This is called when an app-id(s) is removed from the power save whitelist.
*/
- private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
+ private void onPowerSaveUnwhitelisted(AppStateTracker sender) {
updateAllJobs();
unblockAllUnrestrictedAlarms();
}
@@ -291,14 +297,14 @@
* This is called when the power save whitelist changes, excluding the
* {@link #onPowerSaveUnwhitelisted} case.
*/
- private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
+ private void onPowerSaveWhitelistedChanged(AppStateTracker sender) {
updateAllJobs();
}
/**
* This is called when the temp whitelist changes.
*/
- private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
+ private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) {
// TODO This case happens rather frequently; consider optimizing and update jobs
// only for affected app-ids.
@@ -311,7 +317,7 @@
/**
* This is called when the EXEMPT bucket is updated.
*/
- private void onExemptChanged(ForceAppStandbyTracker sender) {
+ private void onExemptChanged(AppStateTracker sender) {
// This doesn't happen very often, so just re-evaluate all jobs / alarms.
updateAllJobs();
unblockAllUnrestrictedAlarms();
@@ -320,7 +326,7 @@
/**
* This is called when the global "force all apps standby" flag changes.
*/
- private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
+ private void onForceAllAppsStandbyChanged(AppStateTracker sender) {
updateAllJobs();
if (!sender.isForceAllAppsStandbyEnabled()) {
@@ -377,30 +383,15 @@
}
}
- @VisibleForTesting
- ForceAppStandbyTracker(Context context, Looper looper) {
+ public AppStateTracker(Context context, Looper looper) {
mContext = context;
mHandler = new MyHandler(looper);
}
- private ForceAppStandbyTracker(Context context) {
- this(context, FgThread.get().getLooper());
- }
-
- /**
- * Get the singleton instance.
- */
- public static synchronized ForceAppStandbyTracker getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new ForceAppStandbyTracker(context);
- }
- return sInstance;
- }
-
/**
* Call it when the system is ready.
*/
- public void start() {
+ public void onSystemServicesReady() {
synchronized (mLock) {
if (mStarted) {
return;
@@ -408,6 +399,7 @@
mStarted = true;
mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
+ mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
@@ -475,6 +467,11 @@
}
@VisibleForTesting
+ ActivityManagerInternal injectActivityManagerInternal() {
+ return LocalServices.getService(ActivityManagerInternal.class);
+ }
+
+ @VisibleForTesting
PowerManagerInternal injectPowerManagerInternal() {
return LocalServices.getService(PowerManagerInternal.class);
}
@@ -799,7 +796,7 @@
return;
}
}
- final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
+ final AppStateTracker sender = AppStateTracker.this;
long start = mStatLogger.getTime();
switch (msg.what) {
@@ -1089,11 +1086,11 @@
}
/**
- * @return whether a UID is in active or not.
+ * @return whether a UID is in active or not *based on cached information.*
*
* Note this information is based on the UID proc state callback, meaning it's updated
* asynchronously and may subtly be stale. If the fresh data is needed, use
- * {@link ActivityManagerInternal#getUidProcessState} instead.
+ * {@link #isUidActiveSynced} instead.
*/
public boolean isUidActive(int uid) {
if (UserHandle.isCore(uid)) {
@@ -1105,6 +1102,23 @@
}
/**
+ * @return whether a UID is in active or not *right now.*
+ *
+ * This gives the fresh information, but may access the activity manager so is slower.
+ */
+ public boolean isUidActiveSynced(int uid) {
+ if (isUidActive(uid)) { // Use the cached one first.
+ return true;
+ }
+ final long start = mStatLogger.getTime();
+
+ final boolean ret = mActivityManagerInternal.isUidActive(uid);
+ mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
+
+ return ret;
+ }
+
+ /**
* @return whether a UID is in the foreground or not.
*
* Note this information is based on the UID proc state callback, meaning it's updated
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 44974ff..2b3c585 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -82,6 +82,7 @@
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -128,6 +129,7 @@
private Intent mIdleIntent;
private Intent mLightIdleIntent;
private AnyMotionDetector mAnyMotionDetector;
+ private final AppStateTracker mAppStateTracker;
private boolean mLightEnabled;
private boolean mDeepEnabled;
private boolean mForceIdle;
@@ -1371,6 +1373,8 @@
super(context);
mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
+ mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper());
+ LocalServices.addService(AppStateTracker.class, mAppStateTracker);
}
boolean isAppOnWhitelistInternal(int appid) {
@@ -1501,6 +1505,8 @@
(PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
mHandler, mSensorManager, this, angleThreshold);
+ mAppStateTracker.onSystemServicesReady();
+
mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
@@ -2615,7 +2621,7 @@
}
private void passWhiteListToForceAppStandbyTrackerLocked() {
- ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds(
+ mAppStateTracker.setPowerSaveWhitelistAppIds(
mPowerSaveWhitelistExceptIdleAppIdArray,
mTempWhitelistAppIdArray);
}
diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java
index f211731..0e6f5e2 100644
--- a/services/core/java/com/android/server/StatLogger.java
+++ b/services/core/java/com/android/server/StatLogger.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.os.SystemClock;
+import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -33,6 +34,8 @@
* @hide
*/
public class StatLogger {
+ private static final String TAG = "StatLogger";
+
private final Object mLock = new Object();
private final int SIZE;
@@ -66,8 +69,12 @@
*/
public void logDurationStat(int eventId, long start) {
synchronized (mLock) {
- mCountStats[eventId]++;
- mDurationStats[eventId] += (getTime() - start);
+ if (eventId >= 0 && eventId < SIZE) {
+ mCountStats[eventId]++;
+ mDurationStats[eventId] += (getTime() - start);
+ } else {
+ Slog.wtf(TAG, "Invalid event ID: " + eventId);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a6c4fc9..e278e38 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1854,7 +1854,6 @@
static final int REPORT_MEM_USAGE_MSG = 33;
static final int IMMERSIVE_MODE_LOCK_MSG = 37;
static final int PERSIST_URI_GRANTS_MSG = 38;
- static final int REQUEST_ALL_PSS_MSG = 39;
static final int UPDATE_TIME_PREFERENCE_MSG = 41;
static final int ENTER_ANIMATION_COMPLETE_MSG = 44;
static final int FINISH_BOOTING_MSG = 45;
@@ -2320,12 +2319,6 @@
writeGrantedUriPermissions();
break;
}
- case REQUEST_ALL_PSS_MSG: {
- synchronized (ActivityManagerService.this) {
- requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
- }
- break;
- }
case UPDATE_TIME_PREFERENCE_MSG: {
// The user's time format preference might have changed.
// For convenience we re-use the Intent extra values.
@@ -2615,11 +2608,17 @@
procState = proc.pssProcState;
statType = proc.pssStatType;
lastPssTime = proc.lastPssTime;
+ long now = SystemClock.uptimeMillis();
if (proc.thread != null && procState == proc.setProcState
&& (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
- < SystemClock.uptimeMillis()) {
+ < now) {
pid = proc.pid;
} else {
+ ProcessList.abortNextPssTime(proc.procStateMemTracker);
+ if (DEBUG_PSS) Slog.d(TAG_PSS, "Skipped pss collection of " + pid +
+ ": still need " +
+ (lastPssTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE-now) +
+ "ms until safe");
proc = null;
pid = 0;
}
@@ -3005,6 +3004,16 @@
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
+
+ // bind background thread to little cores
+ // this is expected to fail inside of framework tests because apps can't touch cpusets directly
+ try {
+ Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
+ Process.THREAD_GROUP_BG_NONINTERACTIVE);
+ } catch (Exception e) {
+ Slog.w(TAG, "Setting background thread cpuset failed");
+ }
+
}
protected ActivityStackSupervisor createStackSupervisor() {
@@ -12651,6 +12660,9 @@
if (!mBooted && !mBooting
&& userId == UserHandle.USER_SYSTEM
&& (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
+ // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
+ r.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
r.persistent = true;
r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}
@@ -14480,9 +14492,6 @@
mTestPssMode, isSleepingLocked(), now);
}
}
-
- mHandler.removeMessages(REQUEST_ALL_PSS_MSG);
- mHandler.sendEmptyMessageDelayed(REQUEST_ALL_PSS_MSG, 2*60*1000);
}
}
@@ -19529,6 +19538,7 @@
mProcessesToGc.remove(app);
mPendingPssProcesses.remove(app);
+ ProcessList.abortNextPssTime(app.procStateMemTracker);
// Dismiss any open dialogs.
if (app.crashDialog != null && !app.forceCrashReport) {
@@ -23293,9 +23303,9 @@
/**
* Schedule PSS collection of a process.
*/
- void requestPssLocked(ProcessRecord proc, int procState) {
+ boolean requestPssLocked(ProcessRecord proc, int procState) {
if (mPendingPssProcesses.contains(proc)) {
- return;
+ return false;
}
if (mPendingPssProcesses.size() == 0) {
mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
@@ -23304,6 +23314,7 @@
proc.pssProcState = procState;
proc.pssStatType = ProcessStats.ADD_PSS_INTERNAL_SINGLE;
mPendingPssProcesses.add(proc);
+ return true;
}
/**
@@ -23320,6 +23331,9 @@
if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting pss of all procs! memLowered=" + memLowered);
mLastFullPssTime = now;
mFullPssPending = true;
+ for (int i = mPendingPssProcesses.size() - 1; i >= 0; i--) {
+ ProcessList.abortNextPssTime(mPendingPssProcesses.get(i).procStateMemTracker);;
+ }
mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
mPendingPssProcesses.clear();
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
@@ -23328,7 +23342,9 @@
|| app.curProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
continue;
}
- if (memLowered || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
+ if (memLowered || (always && now >
+ app.lastStateTime+ProcessList.PSS_SAFE_TIME_FROM_STATE_CHANGE)
+ || now > (app.lastStateTime+ProcessList.PSS_ALL_INTERVAL)) {
app.pssProcState = app.setProcState;
app.pssStatType = always ? ProcessStats.ADD_PSS_INTERNAL_ALL_POLL
: ProcessStats.ADD_PSS_INTERNAL_ALL_MEM;
@@ -23337,7 +23353,9 @@
mPendingPssProcesses.add(app);
}
}
- mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+ if (!mBgHandler.hasMessages(COLLECT_PSS_BG_MSG)) {
+ mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
+ }
}
public void setTestPssMode(boolean enabled) {
@@ -23695,7 +23713,7 @@
// Experimental code to more aggressively collect pss while
// running test... the problem is that this tends to collect
// the data right when a process is transitioning between process
- // states, which well tend to give noisy data.
+ // states, which will tend to give noisy data.
long start = SystemClock.uptimeMillis();
long startTime = SystemClock.currentThreadTimeMillis();
long pss = Debug.getPss(app.pid, mTmpLong, null);
@@ -23718,9 +23736,10 @@
if (now > app.nextPssTime || (now > (app.lastPssTime+ProcessList.PSS_MAX_INTERVAL)
&& now > (app.lastStateTime+ProcessList.minTimeFromStateChange(
mTestPssMode)))) {
- requestPssLocked(app, app.setProcState);
- app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
- app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
+ if (requestPssLocked(app, app.setProcState)) {
+ app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState,
+ app.procStateMemTracker, mTestPssMode, isSleepingLocked(), now);
+ }
} else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
"Not requesting pss of " + app + ": next=" + (app.nextPssTime-now));
}
@@ -25863,6 +25882,14 @@
public boolean isCallerRecents(int callingUid) {
return getRecentTasks().isCallerRecents(callingUid);
}
+
+ @Override
+ public boolean isUidActive(int uid) {
+ synchronized (ActivityManagerService.this) {
+ final UidRecord uidRec = mActiveUids.get(uid);
+ return (uidRec != null) && !uidRec.idle;
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 08ee237..bf7aef9 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -501,19 +501,19 @@
private static final int PSS_FIRST_CACHED_INTERVAL = 20*1000;
// The amount of time until PSS when an important process stays in the same state.
- private static final int PSS_SAME_PERSISTENT_INTERVAL = 20*60*1000;
+ private static final int PSS_SAME_PERSISTENT_INTERVAL = 10*60*1000;
// The amount of time until PSS when the top process stays in the same state.
- private static final int PSS_SAME_TOP_INTERVAL = 5*60*1000;
+ private static final int PSS_SAME_TOP_INTERVAL = 1*60*1000;
// The amount of time until PSS when an important process stays in the same state.
- private static final int PSS_SAME_IMPORTANT_INTERVAL = 15*60*1000;
+ private static final int PSS_SAME_IMPORTANT_INTERVAL = 10*60*1000;
// The amount of time until PSS when a service process stays in the same state.
- private static final int PSS_SAME_SERVICE_INTERVAL = 20*60*1000;
+ private static final int PSS_SAME_SERVICE_INTERVAL = 5*60*1000;
// The amount of time until PSS when a cached process stays in the same state.
- private static final int PSS_SAME_CACHED_INTERVAL = 20*60*1000;
+ private static final int PSS_SAME_CACHED_INTERVAL = 10*60*1000;
// The amount of time until PSS when a persistent process first appears.
private static final int PSS_FIRST_ASLEEP_PERSISTENT_INTERVAL = 1*60*1000;
@@ -622,16 +622,17 @@
public static final class ProcStateMemTracker {
final int[] mHighestMem = new int[PROC_MEM_NUM];
+ final float[] mScalingFactor = new float[PROC_MEM_NUM];
int mTotalHighestMem = PROC_MEM_CACHED;
- float mCurFactor = 1.0f;
int mPendingMemState;
int mPendingHighestMemState;
- boolean mPendingSame;
+ float mPendingScalingFactor;
public ProcStateMemTracker() {
for (int i = PROC_MEM_PERSISTENT; i < PROC_MEM_NUM; i++) {
mHighestMem[i] = PROC_MEM_NUM;
+ mScalingFactor[i] = 1.0f;
}
mPendingMemState = -1;
}
@@ -639,16 +640,22 @@
public void dumpLine(PrintWriter pw) {
pw.print("best=");
pw.print(mTotalHighestMem);
- pw.print(" ");
- pw.print(mCurFactor);
- pw.print("x (");
+ pw.print(" (");
+ boolean needSep = false;
for (int i = 0; i < PROC_MEM_NUM; i++) {
- if (i != 0) {
- pw.print(", ");
+ if (mHighestMem[i] < PROC_MEM_NUM) {
+ if (needSep) {
+ pw.print(", ");
+ needSep = false;
+ }
+ pw.print(i);
+ pw.print("=");
+ pw.print(mHighestMem[i]);
+ pw.print(" ");
+ pw.print(mScalingFactor[i]);
+ pw.print("x");
+ needSep = true;
}
- pw.print(i);
- pw.print("=");
- pw.print(mHighestMem[i]);
}
pw.print(")");
if (mPendingMemState >= 0) {
@@ -656,8 +663,9 @@
pw.print(mPendingMemState);
pw.print(" highest=");
pw.print(mPendingHighestMemState);
- pw.print(" same=");
- pw.print(mPendingSame);
+ pw.print(" ");
+ pw.print(mPendingScalingFactor);
+ pw.print("x");
}
pw.println();
}
@@ -674,12 +682,8 @@
public static void commitNextPssTime(ProcStateMemTracker tracker) {
if (tracker.mPendingMemState >= 0) {
tracker.mHighestMem[tracker.mPendingMemState] = tracker.mPendingHighestMemState;
+ tracker.mScalingFactor[tracker.mPendingMemState] = tracker.mPendingScalingFactor;
tracker.mTotalHighestMem = tracker.mPendingHighestMemState;
- if (tracker.mPendingSame) {
- tracker.mCurFactor *= 1.5f;
- } else {
- tracker.mCurFactor = 1;
- }
tracker.mPendingMemState = -1;
}
}
@@ -691,6 +695,7 @@
public static long computeNextPssTime(int procState, ProcStateMemTracker tracker, boolean test,
boolean sleeping, long now) {
boolean first;
+ float scalingFactor;
final int memState = sProcStateToProcMem[procState];
if (tracker != null) {
final int highestMemState = memState < tracker.mTotalHighestMem
@@ -698,9 +703,15 @@
first = highestMemState < tracker.mHighestMem[memState];
tracker.mPendingMemState = memState;
tracker.mPendingHighestMemState = highestMemState;
- tracker.mPendingSame = !first;
+ if (first) {
+ tracker.mPendingScalingFactor = scalingFactor = 1.0f;
+ } else {
+ scalingFactor = tracker.mScalingFactor[memState];
+ tracker.mPendingScalingFactor = scalingFactor * 1.5f;
+ }
} else {
first = true;
+ scalingFactor = 1.0f;
}
final long[] table = test
? (first
@@ -709,8 +720,7 @@
: (first
? (sleeping ? sFirstAsleepPssTimes : sFirstAwakePssTimes)
: (sleeping ? sSameAsleepPssTimes : sSameAwakePssTimes));
- long delay = (long)(table[memState] * (tracker != null && !first
- ? tracker.mCurFactor : 1.0f));
+ long delay = (long)(table[memState] * scalingFactor);
if (delay > PSS_MAX_INTERVAL) {
delay = PSS_MAX_INTERVAL;
}
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index 8bf320e..edf565a 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -237,6 +237,7 @@
if (commit) {
mProcessStats.resetSafely();
updateFile();
+ mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
}
mLastWriteTime = SystemClock.uptimeMillis();
totalTime = SystemClock.uptimeMillis() - now;
@@ -784,12 +785,14 @@
} else if ("--reset".equals(arg)) {
synchronized (mAm) {
mProcessStats.resetSafely();
+ mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
pw.println("Process stats reset.");
quit = true;
}
} else if ("--clear".equals(arg)) {
synchronized (mAm) {
mProcessStats.resetSafely();
+ mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
ArrayList<String> files = getCommittedFiles(0, true, true);
if (files != null) {
for (int fi=0; fi<files.size(); fi++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 401c05e..47a4fb2 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -40,7 +40,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.Intent.UriFlags;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -79,7 +78,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.DeviceIdleController;
import com.android.server.FgThread;
-import com.android.server.ForceAppStandbyTracker;
+import com.android.server.AppStateTracker;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
@@ -184,7 +183,7 @@
ActivityManagerInternal mActivityManagerInternal;
IBatteryStats mBatteryStats;
DeviceIdleController.LocalService mLocalDeviceIdleController;
- final ForceAppStandbyTracker mForceAppStandbyTracker;
+ AppStateTracker mAppStateTracker;
/**
* Set to true once we are allowed to run third party apps.
@@ -787,20 +786,13 @@
}
/**
- * Return whether an UID is in the foreground or not.
+ * Return whether an UID is active or idle.
*/
- private boolean isUidInForeground(int uid) {
- synchronized (mLock) {
- if (mUidPriorityOverride.get(uid, 0) > 0) {
- return true;
- }
- }
- // Note UID observer may not be called in time, so we always check with the AM.
- return mActivityManagerInternal.getUidProcessState(uid)
- <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+ private boolean isUidActive(int uid) {
+ return mAppStateTracker.isUidActiveSynced(uid);
}
- private final Predicate<Integer> mIsUidInForegroundPredicate = this::isUidInForeground;
+ private final Predicate<Integer> mIsUidActivePredicate = this::isUidActive;
public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
int userId, String tag) {
@@ -826,7 +818,7 @@
// If any of work item is enqueued when the source is in the foreground,
// exempt the entire job.
- toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+ toCancel.maybeAddForegroundExemption(mIsUidActivePredicate);
return JobScheduler.RESULT_SUCCESS;
}
@@ -838,7 +830,7 @@
// Note if it's a sync job, this method is called on the handler so it's not exactly
// the state when requestSync() was called, but that should be fine because of the
// 1 minute foreground grace period.
- jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+ jobStatus.maybeAddForegroundExemption(mIsUidActivePredicate);
if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
// Jobs on behalf of others don't apply to the per-app job cap
@@ -1123,8 +1115,6 @@
mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
mControllers.add(mDeviceIdleJobsController);
- mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
// If the job store determined that it can't yet reschedule persisted jobs,
// we need to start watching the clock.
if (!mJobs.jobTimesInflatedValid()) {
@@ -1185,7 +1175,8 @@
if (PHASE_SYSTEM_SERVICES_READY == phase) {
mConstants.start(getContext().getContentResolver());
- mForceAppStandbyTracker.start();
+ mAppStateTracker = Preconditions.checkNotNull(
+ LocalServices.getService(AppStateTracker.class));
// Register br for package removals and user removals.
final IntentFilter filter = new IntentFilter();
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 5eb7700..e8057fb 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -22,8 +22,10 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
-import com.android.server.ForceAppStandbyTracker;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker;
+import com.android.server.AppStateTracker.Listener;
+import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobStore;
import com.android.server.job.StateControllerProto;
@@ -42,8 +44,7 @@
private final JobSchedulerService mJobSchedulerService;
- private final ForceAppStandbyTracker mForceAppStandbyTracker;
-
+ private final AppStateTracker mAppStateTracker;
public static BackgroundJobsController get(JobSchedulerService service) {
synchronized (sCreationLock) {
@@ -59,10 +60,9 @@
super(service, context, lock);
mJobSchedulerService = service;
- mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
- mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
- mForceAppStandbyTracker.start();
+ mAppStateTracker = Preconditions.checkNotNull(
+ LocalServices.getService(AppStateTracker.class));
+ mAppStateTracker.addListener(mForceAppStandbyListener);
}
@Override
@@ -79,7 +79,7 @@
public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
pw.println("BackgroundJobsController");
- mForceAppStandbyTracker.dump(pw, "");
+ mAppStateTracker.dump(pw, "");
pw.println("Job state:");
mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -92,16 +92,16 @@
jobStatus.printUniqueId(pw);
pw.print(" from ");
UserHandle.formatUid(pw, uid);
- pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle");
- if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
- mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
+ pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
+ if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
+ mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
pw.print(", whitelisted");
}
pw.print(": ");
pw.print(sourcePkg);
pw.print(" [RUN_ANY_IN_BACKGROUND ");
- pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
+ pw.print(mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
? "allowed]" : "disallowed]");
if ((jobStatus.satisfiedConstraints
@@ -118,7 +118,7 @@
final long token = proto.start(fieldId);
final long mToken = proto.start(StateControllerProto.BACKGROUND);
- mForceAppStandbyTracker.dumpProto(proto,
+ mAppStateTracker.dumpProto(proto,
StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -136,14 +136,14 @@
proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
proto.write(TrackedJob.IS_IN_FOREGROUND,
- mForceAppStandbyTracker.isUidActive(sourceUid));
+ mAppStateTracker.isUidActive(sourceUid));
proto.write(TrackedJob.IS_WHITELISTED,
- mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) ||
- mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid));
+ mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
+ mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
proto.write(
TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
- mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
+ mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
sourceUid, sourcePkg));
proto.write(
@@ -197,7 +197,7 @@
final int uid = jobStatus.getSourceUid();
final String packageName = jobStatus.getSourcePackageName();
- final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName,
+ final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
(jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
!= 0);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a6f049e..a17dd12 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1722,7 +1722,7 @@
final long totalBytes = getTotalBytes(
NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end);
final long remainingBytes = limitBytes - totalBytes;
- final long remainingDays = Math.min(1, (end - currentTimeMillis())
+ final long remainingDays = Math.max(1, (end - currentTimeMillis())
/ TimeUnit.DAYS.toMillis(1));
if (remainingBytes > 0) {
quotaBytes = (remainingBytes / remainingDays) / 10;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c361434..5ea113b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -724,7 +724,6 @@
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
- boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
boolean disableSystemTextClassifier = SystemProperties.getBoolean(
"config.disable_systemtextclassifier", false);
boolean disableCameraService = SystemProperties.getBoolean("config.disable_cameraservice",
@@ -1105,18 +1104,12 @@
traceEnd();
}
- if (!disableRtt) {
- traceBeginAndSlog("StartWifiRtt");
- mSystemServiceManager.startService("com.android.server.wifi.RttService");
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_RTT)) {
+ traceBeginAndSlog("StartRttService");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
traceEnd();
-
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_RTT)) {
- traceBeginAndSlog("StartRttService");
- mSystemServiceManager.startService(
- "com.android.server.wifi.rtt.RttService");
- traceEnd();
- }
}
if (context.getPackageManager().hasSystemFeature(
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
similarity index 93%
rename from services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
rename to services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index a499472..90db2a3 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server;
-import static com.android.server.ForceAppStandbyTracker.TARGET_OP;
+import static com.android.server.AppStateTracker.TARGET_OP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -33,6 +33,7 @@
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
@@ -63,7 +64,7 @@
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.server.AppStateTracker.Listener;
import org.junit.Before;
import org.junit.Test;
@@ -82,17 +83,17 @@
import java.util.function.Consumer;
/**
- * Tests for {@link ForceAppStandbyTracker}
+ * Tests for {@link AppStateTracker}
*
* Run with:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ForceAppStandbyTrackerTest {
+public class AppStateTrackerTest {
- private class ForceAppStandbyTrackerTestable extends ForceAppStandbyTracker {
- ForceAppStandbyTrackerTestable() {
+ private class AppStateTrackerTestable extends AppStateTracker {
+ AppStateTrackerTestable() {
super(mMockContext, Looper.getMainLooper());
}
@@ -112,6 +113,11 @@
}
@Override
+ ActivityManagerInternal injectActivityManagerInternal() {
+ return mMockIActivityManagerInternal;
+ }
+
+ @Override
PowerManagerInternal injectPowerManagerInternal() {
return mMockPowerManagerInternal;
}
@@ -152,6 +158,9 @@
private IActivityManager mMockIActivityManager;
@Mock
+ private ActivityManagerInternal mMockIActivityManagerInternal;
+
+ @Mock
private AppOpsManager mMockAppOpsManager;
@Mock
@@ -195,7 +204,7 @@
return new PowerSaveState.Builder().setBatterySaverEnabled(mPowerSaveMode).build();
}
- private ForceAppStandbyTrackerTestable newInstance() throws Exception {
+ private AppStateTrackerTestable newInstance() throws Exception {
MockitoAnnotations.initMocks(this);
when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString()))
@@ -205,12 +214,12 @@
AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
});
- final ForceAppStandbyTrackerTestable instance = new ForceAppStandbyTrackerTestable();
+ final AppStateTrackerTestable instance = new AppStateTrackerTestable();
return instance;
}
- private void callStart(ForceAppStandbyTrackerTestable instance) throws RemoteException {
+ private void callStart(AppStateTrackerTestable instance) throws RemoteException {
// Set up functions that start() calls.
when(mMockPowerManagerInternal.getLowPowerState(eq(ServiceType.FORCE_ALL_APPS_STANDBY)))
@@ -223,7 +232,7 @@
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
// Call start.
- instance.start();
+ instance.onSystemServicesReady();
// Capture the listeners.
ArgumentCaptor<IUidObserver> uidObserverArgumentCaptor =
@@ -287,7 +296,7 @@
private static final int JOBS_ONLY = 1 << 1;
private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY;
- private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+ private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
int restrictionTypes, boolean exemptFromBatterySaver) {
assertEquals(((restrictionTypes & JOBS_ONLY) != 0),
instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver));
@@ -295,13 +304,13 @@
instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver));
}
- private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+ private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
int restrictionTypes) {
areRestricted(instance, uid, packageName, restrictionTypes,
/*exemptFromBatterySaver=*/ false);
}
- private void areRestrictedWithExemption(ForceAppStandbyTrackerTestable instance,
+ private void areRestrictedWithExemption(AppStateTrackerTestable instance,
int uid, String packageName, int restrictionTypes) {
areRestricted(instance, uid, packageName, restrictionTypes,
/*exemptFromBatterySaver=*/ true);
@@ -309,7 +318,7 @@
@Test
public void testAll() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -466,7 +475,7 @@
@Test
public void testUidStateForeground() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
mIUidObserver.onUidActive(UID_1);
@@ -476,6 +485,10 @@
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+ assertTrue(instance.isUidActiveSynced(UID_1));
+ assertFalse(instance.isUidActiveSynced(UID_2));
+ assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
assertFalse(instance.isUidInForeground(UID_1));
assertFalse(instance.isUidInForeground(UID_2));
assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -489,6 +502,10 @@
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+ assertTrue(instance.isUidActiveSynced(UID_1));
+ assertFalse(instance.isUidActiveSynced(UID_2));
+ assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
assertFalse(instance.isUidInForeground(UID_1));
assertTrue(instance.isUidInForeground(UID_2));
assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -548,14 +565,34 @@
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+ assertFalse(instance.isUidActiveSynced(UID_1));
+ assertFalse(instance.isUidActiveSynced(UID_2));
+ assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
assertFalse(instance.isUidInForeground(UID_1));
assertFalse(instance.isUidInForeground(UID_2));
assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+ // The result from AMI.isUidActive() only affects isUidActiveSynced().
+ when(mMockIActivityManagerInternal.isUidActive(anyInt())).thenReturn(true);
+
+ assertFalse(instance.isUidActive(UID_1));
+ assertFalse(instance.isUidActive(UID_2));
+ assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+ assertTrue(instance.isUidActiveSynced(UID_1));
+ assertTrue(instance.isUidActiveSynced(UID_2));
+ assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
+ assertFalse(instance.isUidInForeground(UID_1));
+ assertFalse(instance.isUidInForeground(UID_2));
+ assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
}
@Test
public void testExempt() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -621,7 +658,7 @@
}
public void loadPersistedAppOps() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
final List<PackageOps> ops = new ArrayList<>();
@@ -631,7 +668,7 @@
AppOpsManager.OP_ACCESS_NOTIFICATIONS,
AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
entries.add(new AppOpsManager.OpEntry(
- ForceAppStandbyTracker.TARGET_OP,
+ AppStateTracker.TARGET_OP,
AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
@@ -639,7 +676,7 @@
//--------------------------------------------------
entries = new ArrayList<>();
entries.add(new AppOpsManager.OpEntry(
- ForceAppStandbyTracker.TARGET_OP,
+ AppStateTracker.TARGET_OP,
AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
@@ -647,7 +684,7 @@
//--------------------------------------------------
entries = new ArrayList<>();
entries.add(new AppOpsManager.OpEntry(
- ForceAppStandbyTracker.TARGET_OP,
+ AppStateTracker.TARGET_OP,
AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null));
ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
@@ -655,7 +692,7 @@
//--------------------------------------------------
entries = new ArrayList<>();
entries.add(new AppOpsManager.OpEntry(
- ForceAppStandbyTracker.TARGET_OP,
+ AppStateTracker.TARGET_OP,
AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
entries.add(new AppOpsManager.OpEntry(
AppOpsManager.OP_ACCESS_NOTIFICATIONS,
@@ -688,10 +725,10 @@
@Test
public void testPowerSaveListener() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
- ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+ AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
instance.addListener(l);
// Power save on.
@@ -731,10 +768,10 @@
@Test
public void testAllListeners() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
- ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+ AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
instance.addListener(l);
// -------------------------------------------------------------------------
@@ -1042,7 +1079,7 @@
@Test
public void testUserRemoved() throws Exception {
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
mIUidObserver.onUidActive(UID_1);
@@ -1077,7 +1114,7 @@
// This is a small battery device
mIsSmallBatteryDevice = true;
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -1103,7 +1140,7 @@
// Not a small battery device, so plugged in status should not affect forced app standby
mIsSmallBatteryDevice = false;
- final ForceAppStandbyTrackerTestable instance = newInstance();
+ final AppStateTrackerTestable instance = newInstance();
callStart(instance);
assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -1152,7 +1189,7 @@
private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
- expected, ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
+ expected, AppStateTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
// Also test isAnyAppIdUnwhitelistedSlow.
assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
@@ -1184,7 +1221,7 @@
final int[] array2 = makeRandomArray();
final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
- final boolean actual = ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(array1, array2);
+ final boolean actual = AppStateTracker.isAnyAppIdUnwhitelisted(array1, array2);
assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
expected, actual);
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 0b3cbad..0c17147 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -55,10 +55,11 @@
/** Card state restricted. */
public static final int CARD_STATE_INFO_RESTRICTED = 4;
- public final boolean isActive;
- public final boolean isEuicc;
- public final String cardId;
- public final @CardStateInfo int cardStateInfo;
+ private final boolean mIsActive;
+ private final boolean mIsEuicc;
+ private final String mCardId;
+ private final @CardStateInfo int mCardStateInfo;
+ private final int mLogicalSlotIdx;
public static final Creator<UiccSlotInfo> CREATOR = new Creator<UiccSlotInfo>() {
@Override
@@ -73,18 +74,20 @@
};
private UiccSlotInfo(Parcel in) {
- isActive = in.readByte() != 0;
- isEuicc = in.readByte() != 0;
- cardId = in.readString();
- cardStateInfo = in.readInt();
+ mIsActive = in.readByte() != 0;
+ mIsEuicc = in.readByte() != 0;
+ mCardId = in.readString();
+ mCardStateInfo = in.readInt();
+ mLogicalSlotIdx = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeByte((byte) (isActive ? 1 : 0));
- dest.writeByte((byte) (isEuicc ? 1 : 0));
- dest.writeString(cardId);
- dest.writeInt(cardStateInfo);
+ dest.writeByte((byte) (mIsActive ? 1 : 0));
+ dest.writeByte((byte) (mIsEuicc ? 1 : 0));
+ dest.writeString(mCardId);
+ dest.writeInt(mCardStateInfo);
+ dest.writeInt(mLogicalSlotIdx);
}
@Override
@@ -93,28 +96,33 @@
}
public UiccSlotInfo(boolean isActive, boolean isEuicc, String cardId,
- @CardStateInfo int cardStateInfo) {
- this.isActive = isActive;
- this.isEuicc = isEuicc;
- this.cardId = cardId;
- this.cardStateInfo = cardStateInfo;
+ @CardStateInfo int cardStateInfo, int logicalSlotIdx) {
+ this.mIsActive = isActive;
+ this.mIsEuicc = isEuicc;
+ this.mCardId = cardId;
+ this.mCardStateInfo = cardStateInfo;
+ this.mLogicalSlotIdx = logicalSlotIdx;
}
public boolean getIsActive() {
- return isActive;
+ return mIsActive;
}
public boolean getIsEuicc() {
- return isEuicc;
+ return mIsEuicc;
}
public String getCardId() {
- return cardId;
+ return mCardId;
}
@CardStateInfo
public int getCardStateInfo() {
- return cardStateInfo;
+ return mCardStateInfo;
+ }
+
+ public int getLogicalSlotIdx() {
+ return mLogicalSlotIdx;
}
@Override
@@ -127,32 +135,36 @@
}
UiccSlotInfo that = (UiccSlotInfo) obj;
- return (isActive == that.isActive)
- && (isEuicc == that.isEuicc)
- && (cardId == that.cardId)
- && (cardStateInfo == that.cardStateInfo);
+ return (mIsActive == that.mIsActive)
+ && (mIsEuicc == that.mIsEuicc)
+ && (mCardId == that.mCardId)
+ && (mCardStateInfo == that.mCardStateInfo)
+ && (mLogicalSlotIdx == that.mLogicalSlotIdx);
}
@Override
public int hashCode() {
int result = 1;
- result = 31 * result + (isActive ? 1 : 0);
- result = 31 * result + (isEuicc ? 1 : 0);
- result = 31 * result + Objects.hashCode(cardId);
- result = 31 * result + cardStateInfo;
+ result = 31 * result + (mIsActive ? 1 : 0);
+ result = 31 * result + (mIsEuicc ? 1 : 0);
+ result = 31 * result + Objects.hashCode(mCardId);
+ result = 31 * result + mCardStateInfo;
+ result = 31 * result + mLogicalSlotIdx;
return result;
}
@Override
public String toString() {
- return "UiccSlotInfo (isActive="
- + isActive
- + ", isEuicc="
- + isEuicc
- + ", cardId="
- + cardId
+ return "UiccSlotInfo (mIsActive="
+ + mIsActive
+ + ", mIsEuicc="
+ + mIsEuicc
+ + ", mCardId="
+ + mCardId
+ ", cardState="
- + cardStateInfo
+ + mCardStateInfo
+ + ", phoneId="
+ + mLogicalSlotIdx
+ ")";
}
}
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
deleted file mode 100644
index 3831809..0000000
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-import android.os.Messenger;
-import android.net.wifi.RttManager;
-
-/**
- * {@hide}
- */
-interface IRttManager
-{
- Messenger getMessenger(in IBinder binder, out int[] key);
- RttManager.RttCapabilities getRttCapabilities();
-}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index fe63aa1..0b81dd2 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -12,7 +12,6 @@
import android.net.wifi.rtt.RangingResult;
import android.net.wifi.rtt.RangingResultCallback;
import android.net.wifi.rtt.WifiRttManager;
-import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -919,51 +918,6 @@
}
/**
- * A parcelable that contains rtt client information.
- *
- * @hide
- */
- public static class RttClient implements Parcelable {
- // Package name of RttClient.
- private final String mPackageName;
-
- public RttClient(String packageName) {
- mPackageName = packageName;
- }
-
- protected RttClient(Parcel in) {
- mPackageName = in.readString();
- }
-
- public static final Creator<RttManager.RttClient> CREATOR =
- new Creator<RttManager.RttClient>() {
- @Override
- public RttManager.RttClient createFromParcel(Parcel in) {
- return new RttManager.RttClient(in);
- }
-
- @Override
- public RttManager.RttClient[] newArray(int size) {
- return new RttManager.RttClient[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeString(mPackageName);
- }
-
- public String getPackageName() {
- return mPackageName;
- }
- }
-
- /**
* Request to start an RTT ranging
*
* @param params -- RTT request Parameters
@@ -1202,7 +1156,6 @@
/** @hide */
public static final int CMD_OP_REG_BINDER = BASE + 9;
- private final Context mContext;
private final WifiRttManager mNewService;
private RttCapabilities mRttCapabilities;
@@ -1211,17 +1164,14 @@
* Applications will almost always want to use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}.
- * @param context the application context
- * @param service the Binder interface
- * @param looper Looper for running the callbacks.
+ * @param service the new WifiRttManager service
*
* @hide
*/
- public RttManager(Context context, IRttManager service, Looper looper) {
- mContext = context;
- mNewService = (WifiRttManager) mContext.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
+ public RttManager(Context context, WifiRttManager service) {
+ mNewService = service;
- boolean rttSupported = mContext.getPackageManager().hasSystemFeature(
+ boolean rttSupported = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_WIFI_RTT);
mRttCapabilities = new RttCapabilities();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7da2656..ddcf327 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -917,6 +917,9 @@
* Does not guarantee that the returned address is valid for use.
*/
public MacAddress getRandomizedMacAddress() {
+ if (mRandomizedMacAddress == null) {
+ mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
+ }
return mRandomizedMacAddress;
}
@@ -1617,6 +1620,7 @@
creatorUid = -1;
shared = true;
dtimInterval = 0;
+ mRandomizedMacAddress = MacAddress.ALL_ZEROS_ADDRESS;
}
/**
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index e7377c1..8a3a7f5 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -176,6 +176,8 @@
@Test
public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() {
WifiConfiguration config = new WifiConfiguration();
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+
MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress();
MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress();
@@ -185,6 +187,8 @@
@Test
public void testSetRandomizedMacAddress_ChangesSavedAddress() {
WifiConfiguration config = new WifiConfiguration();
+ assertEquals(MacAddress.ALL_ZEROS_ADDRESS, config.getRandomizedMacAddress());
+
MacAddress macToChangeInto = MacAddress.createRandomUnicastAddress();
config.setRandomizedMacAddress(macToChangeInto);
MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();