Merge "Correct provider filtering" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 8a64dd0..607109d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38395,17 +38395,17 @@
package android.se.omapi {
- public class Channel {
+ public final class Channel implements java.nio.channels.Channel {
method public void close();
method public byte[] getSelectResponse();
method public android.se.omapi.Session getSession();
method public boolean isBasicChannel();
- method public boolean isClosed();
+ method public boolean isOpen();
method public boolean selectNext() throws java.io.IOException;
method public byte[] transmit(byte[]) throws java.io.IOException;
}
- public class Reader {
+ public final class Reader {
method public void closeSessions();
method public java.lang.String getName();
method public android.se.omapi.SEService getSEService();
@@ -38413,26 +38413,28 @@
method public android.se.omapi.Session openSession() throws java.io.IOException;
}
- public class SEService {
- ctor public SEService(android.content.Context, android.se.omapi.SEService.SecureElementListener);
+ public final class SEService {
+ ctor public SEService(android.content.Context, java.util.concurrent.Executor, android.se.omapi.SEService.OnConnectedListener);
method public android.se.omapi.Reader[] getReaders();
method public java.lang.String getVersion();
method public boolean isConnected();
method public void shutdown();
}
- public static abstract interface SEService.SecureElementListener {
- method public abstract void onServiceConnected();
+ public static abstract interface SEService.OnConnectedListener {
+ method public abstract void onConnected();
}
- public class Session {
+ public final class Session {
method public void close();
method public void closeChannels();
method public byte[] getATR();
method public android.se.omapi.Reader getReader();
method public boolean isClosed();
method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
}
}
@@ -40955,7 +40957,7 @@
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
- method public void requestBluetoothAudio(java.lang.String);
+ method public void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void sendRemoteRttRequest();
method public final void sendRttInitiationFailure(int);
@@ -41166,7 +41168,7 @@
method public void onCanAddCallChanged(boolean);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
- method public final void requestBluetoothAudio(java.lang.String);
+ method public final void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -43376,6 +43378,7 @@
public class PrecomputedText implements android.text.Spannable {
method public char charAt(int);
method public static android.text.PrecomputedText create(java.lang.CharSequence, android.text.PrecomputedText.Params);
+ method public void getBounds(int, int, android.graphics.Rect);
method public int getParagraphCount();
method public int getParagraphEnd(int);
method public int getParagraphStart(int);
@@ -43384,7 +43387,7 @@
method public int getSpanFlags(java.lang.Object);
method public int getSpanStart(java.lang.Object);
method public <T> T[] getSpans(int, int, java.lang.Class<T>);
- method public java.lang.CharSequence getText();
+ method public float getWidth(int, int);
method public int length();
method public int nextSpanTransition(int, int, java.lang.Class);
method public void removeSpan(java.lang.Object);
diff --git a/api/test-current.txt b/api/test-current.txt
index f66fafe..9f5fa0c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -779,6 +779,12 @@
method public void setCdmaSystemAndNetworkId(int, int);
}
+ public class TelephonyManager {
+ method public int getCarrierIdListVersion();
+ method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+ field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
+ }
+
}
package android.telephony.mbms {
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index 50b05cd..fae186a 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -366,7 +366,7 @@
sp<AlarmMonitor> periodicAlarmMonitor;
sp<StatsLogProcessor> processor = new StatsLogProcessor(
uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
- processor->OnConfigUpdated(key, config);
+ processor->OnConfigUpdated(0, key, config);
return processor;
}
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 13f2679..f00cdb3 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -191,11 +191,12 @@
}
}
-void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config) {
std::lock_guard<std::mutex> lock(mMetricsMutex);
VLOG("Updated configuration for key %s", key.ToString().c_str());
sp<MetricsManager> newMetricsManager =
- new MetricsManager(key, config, mTimeBaseSec, mUidMap,
+ new MetricsManager(key, config, mTimeBaseSec, (timestampNs - 1) / NS_PER_SEC + 1, mUidMap,
mAnomalyAlarmMonitor, mPeriodicAlarmMonitor);
if (newMetricsManager->isConfigValid()) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 387a929..1c4698f 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -42,7 +42,8 @@
void OnLogEvent(LogEvent* event);
- void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
+ void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config);
void OnConfigRemoved(const ConfigKey& key);
size_t GetMetricsSize(const ConfigKey& key) const;
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 249cb59..70e6e84 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -30,7 +30,8 @@
namespace os {
namespace statsd {
-AlarmTracker::AlarmTracker(uint64_t startMillis,
+AlarmTracker::AlarmTracker(const uint64_t startMillis,
+ const uint64_t currentMillis,
const Alarm& alarm, const ConfigKey& configKey,
const sp<AlarmMonitor>& alarmMonitor)
: mAlarmConfig(alarm),
@@ -38,7 +39,11 @@
mAlarmMonitor(alarmMonitor) {
VLOG("AlarmTracker() called");
mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC;
+ // startMillis is the time statsd is created. We need to find the 1st alarm timestamp after
+ // the config is added to statsd.
+ mAlarmSec = findNextAlarmSec(currentMillis / MS_PER_SEC); // round up
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->add(mInternalAlarm);
}
@@ -55,9 +60,13 @@
mSubscriptions.push_back(subscription);
}
-uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) {
- int periodsForward = (currentTimeSec - mAlarmSec) * MS_PER_SEC / mAlarmConfig.period_millis();
- return mAlarmSec + (periodsForward + 1) * mAlarmConfig.period_millis() / MS_PER_SEC;
+int64_t AlarmTracker::findNextAlarmSec(int64_t currentTimeSec) {
+ if (currentTimeSec <= mAlarmSec) {
+ return mAlarmSec;
+ }
+ int64_t periodsForward =
+ ((currentTimeSec - mAlarmSec) * MS_PER_SEC - 1) / mAlarmConfig.period_millis() + 1;
+ return mAlarmSec + periodsForward * mAlarmConfig.period_millis() / MS_PER_SEC;
}
void AlarmTracker::informAlarmsFired(
@@ -68,12 +77,14 @@
return;
}
if (!mSubscriptions.empty()) {
+ VLOG("AlarmTracker triggers the subscribers.");
triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey,
mSubscriptions);
}
firedAlarms.erase(mInternalAlarm);
mAlarmSec = findNextAlarmSec((timestampNs-1) / NS_PER_SEC + 1); // round up
mInternalAlarm = new InternalAlarm{static_cast<uint32_t>(mAlarmSec)};
+ VLOG("AlarmTracker sets the periodic alarm at: %lld", (long long)mAlarmSec);
if (mAlarmMonitor != nullptr) {
mAlarmMonitor->add(mInternalAlarm);
}
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h
index 13180a5..962a014 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.h
+++ b/cmds/statsd/src/anomaly/AlarmTracker.h
@@ -34,7 +34,8 @@
class AlarmTracker : public virtual RefBase {
public:
- AlarmTracker(uint64_t startMillis,
+ AlarmTracker(const uint64_t startMillis,
+ const uint64_t currentMillis,
const Alarm& alarm, const ConfigKey& configKey,
const sp<AlarmMonitor>& subscriberAlarmMonitor);
@@ -53,13 +54,13 @@
return mInternalAlarm == nullptr ? 0 : mInternalAlarm->timestampSec;
}
- uint64_t findNextAlarmSec(uint64_t currentTimeMillis);
+ int64_t findNextAlarmSec(int64_t currentTimeMillis);
// statsd_config.proto Alarm message that defines this tracker.
const Alarm mAlarmConfig;
// A reference to the Alarm's config key.
- const ConfigKey& mConfigKey;
+ const ConfigKey mConfigKey;
// The subscriptions that depend on this alarm.
std::vector<Subscription> mSubscriptions;
@@ -68,7 +69,7 @@
sp<AlarmMonitor> mAlarmMonitor;
// The current expected alarm time in seconds.
- uint64_t mAlarmSec;
+ int64_t mAlarmSec;
// The current alarm.
sp<const InternalAlarm> mInternalAlarm;
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index ae0af64..15671a6 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -127,7 +127,7 @@
std::vector<Subscription> mSubscriptions;
// A reference to the Alert's config key.
- const ConfigKey& mConfigKey;
+ const ConfigKey mConfigKey;
// Number of past buckets. One less than the total number of buckets needed
// for the anomaly detection (since the current bucket is not in the past).
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7fe8e62..ab9c7e8 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -108,7 +108,7 @@
ResourceConfigurationChanged resource_configuration_changed = 66;
BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67;
BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68;
- BluetoothA2dpAudioStateChanged bluetooth_a2dp_audio_state_changed = 69;
+ // 69 is blank but need not be.
UsbConnectorStateChanged usb_connector_state_changed = 70;
SpeakerImpedanceReported speaker_impedance_reported = 71;
HardwareFailed hardware_failed = 72;
@@ -1008,22 +1008,6 @@
}
/**
- * Logs when Bluetooth A2dp audio streaming state changes.
- *
- * Logged from:
- * TODO(b/73971848)
- */
-message BluetoothA2dpAudioStateChanged {
- // Whether or not audio is being played using Bluetooth A2dp.
- enum State {
- UNKNOWN = 0;
- PLAY = 1;
- STOP = 2;
- }
- optional State state = 1;
-}
-
-/**
* Logs when something is plugged into or removed from the USB-C connector.
*
* Logged from:
@@ -1225,6 +1209,22 @@
// The pid if available. -1 means not available.
optional sint32 pid = 4;
+
+ optional string package_name = 5;
+
+ enum InstantApp {
+ UNAVAILABLE = 0;
+ FALSE = 1;
+ TRUE = 2;
+ }
+ optional InstantApp is_instant_app = 6;
+
+ enum ForegroundState {
+ UNKNOWN = 0;
+ BACKGROUND = 1;
+ FOREGROUND = 2;
+ }
+ optional ForegroundState foreground_state = 7;
}
/**
@@ -1266,6 +1266,20 @@
optional string short_component_name = 3;
optional string reason = 4;
+
+ enum InstantApp {
+ UNAVAILABLE = 0;
+ FALSE = 1;
+ TRUE = 2;
+ }
+ optional InstantApp is_instant_app = 5;
+
+ enum ForegroundState {
+ UNKNOWN = 0;
+ BACKGROUND = 1;
+ FOREGROUND = 2;
+ }
+ optional ForegroundState foreground_state = 6;
}
/*
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index 19ccfcf..54e7770 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -40,7 +40,8 @@
/**
* A configuration was added or updated.
*/
- virtual void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) = 0;
+ virtual void OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config) = 0;
/**
* A configuration was removed.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index ff25091..f9aaad4 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -21,6 +21,7 @@
#include "storage/StorageManager.h"
#include "guardrail/StatsdStats.h"
+#include "stats_log_util.h"
#include "stats_util.h"
#include <android-base/file.h>
@@ -109,9 +110,10 @@
}
}
+ const int64_t timestampNs = getElapsedRealtimeNs();
// Tell everyone
for (sp<ConfigListener> listener:broadcastList) {
- listener->OnConfigUpdated(key, config);
+ listener->OnConfigUpdated(timestampNs, key, config);
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 00188e8..c61fa76 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -49,7 +49,7 @@
const int FIELD_ID_METRICS = 1;
MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
const sp<UidMap> &uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor)
@@ -58,7 +58,7 @@
mLastReportWallClockNs(getWallClockNs()) {
mConfigValid =
initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, mTagIds, mAllAtomMatchers,
+ timeBaseSec, currentTimeSec, mTagIds, mAllAtomMatchers,
mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers,
mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap,
mTrackerToConditionMap, mNoReportMetricIds);
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index da0cd4a..4fd64b7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -36,7 +36,8 @@
// A MetricsManager is responsible for managing metrics from one single config source.
class MetricsManager : public PackageInfoListener {
public:
- MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec,
+ MetricsManager(const ConfigKey& configKey, const StatsdConfig& config,
+ const long timeBaseSec, const long currentTimeSec,
const sp<UidMap>& uidMap, const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 50eca05..b7c5795 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -599,10 +599,11 @@
bool initAlarms(const StatsdConfig& config, const ConfigKey& key,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
vector<sp<AlarmTracker>>& allAlarmTrackers) {
unordered_map<int64_t, int> alarmTrackerMap;
uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC;
+ uint64_t currentTimeMillis = (uint64_t)currentTimeSec * MS_PER_SEC;
for (int i = 0; i < config.alarm_size(); i++) {
const Alarm& alarm = config.alarm(i);
if (alarm.offset_millis() <= 0) {
@@ -615,7 +616,8 @@
}
alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size()));
allAlarmTrackers.push_back(
- new AlarmTracker(startMillis, alarm, key, periodicAlarmMonitor));
+ new AlarmTracker(startMillis, currentTimeMillis,
+ alarm, key, periodicAlarmMonitor));
}
for (int i = 0; i < config.subscription_size(); ++i) {
const Subscription& subscription = config.subscription(i);
@@ -644,7 +646,7 @@
const UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
set<int>& allTagIds,
vector<sp<LogMatchingTracker>>& allAtomMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
@@ -682,7 +684,8 @@
ALOGE("initAlerts failed");
return false;
}
- if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseSec, allPeriodicAlarmTrackers)) {
+ if (!initAlarms(config, key, periodicAlarmMonitor,
+ timeBaseSec, currentTimeSec, allPeriodicAlarmTrackers)) {
ALOGE("initAlarms failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 386de0b..3754ae0 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -98,7 +98,7 @@
const UidMap& uidMap,
const sp<AlarmMonitor>& anomalyAlarmMonitor,
const sp<AlarmMonitor>& periodicAlarmMonitor,
- const long timeBaseSec,
+ const long timeBaseSec, const long currentTimeSec,
std::set<int>& allTagIds,
std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
index 838745e..9455304 100644
--- a/cmds/statsd/tests/ConfigManager_test.cpp
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -44,7 +44,8 @@
*/
class MockListener : public ConfigListener {
public:
- MOCK_METHOD2(OnConfigUpdated, void(const ConfigKey& key, const StatsdConfig& config));
+ MOCK_METHOD3(OnConfigUpdated, void(const int64_t timestampNs, const ConfigKey& key,
+ const StatsdConfig& config));
MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
};
@@ -88,25 +89,25 @@
manager->StartupForTest();
// Add another one
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
StatsdConfigEq(91)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config91);
// Update It
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("zzz")),
StatsdConfigEq(92)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("zzz")), config92);
// Add one with the same uid but a different name
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, StringToId("yyy")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(1, StringToId("yyy")),
StatsdConfigEq(93)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(1, StringToId("yyy")), config93);
// Add one with the same name but a different uid
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, StringToId("zzz")),
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, ConfigKeyEq(2, StringToId("zzz")),
StatsdConfigEq(94)))
.RetiresOnSaturation();
manager->UpdateConfig(ConfigKey(2, StringToId("zzz")), config94);
@@ -142,7 +143,7 @@
StatsdConfig config;
- EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(5);
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _, _)).Times(5);
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("xxx"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("yyy"))));
EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, StringToId("zzz"))));
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 5d8c3f7..07378db 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -287,7 +287,7 @@
EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -315,7 +315,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -340,7 +340,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -364,7 +364,7 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -388,7 +388,7 @@
std::set<int64_t> noReportMetricIds;
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -413,7 +413,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
@@ -438,7 +438,7 @@
EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap,
anomalyAlarmMonitor, periodicAlarmMonitor,
- timeBaseSec, allTagIds, allAtomMatchers,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers,
allConditionTrackers, allMetricProducers, allAnomalyTrackers,
allAlarmTrackers,
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap,
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 4b9a87d..5a8ba79 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -43,7 +43,7 @@
class MockMetricsManager : public MetricsManager {
public:
MockMetricsManager() : MetricsManager(
- ConfigKey(1, 12345), StatsdConfig(), 1000,
+ ConfigKey(1, 12345), StatsdConfig(), 1000, 1000,
new UidMap(),
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){}),
@@ -135,7 +135,7 @@
ConfigKey key(3, 4);
StatsdConfig config;
config.add_allowed_log_source("AID_ROOT");
- p.OnConfigUpdated(key, config);
+ p.OnConfigUpdated(0, key, config);
// Expect to get no metrics, but snapshot specified above in uidmap.
vector<uint8_t> bytes;
diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
index 3330ee9..5e6de1c 100644
--- a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp
@@ -39,25 +39,24 @@
Alarm alarm;
alarm.set_offset_millis(15 * MS_PER_SEC);
alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr
- uint64_t startMillis = 100000000 * MS_PER_SEC;
- AlarmTracker tracker(startMillis, alarm, kConfigKey,
- subscriberAlarmMonitor);
+ int64_t startMillis = 100000000 * MS_PER_SEC;
+ AlarmTracker tracker(startMillis, startMillis, alarm, kConfigKey, subscriberAlarmMonitor);
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10;
std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> firedAlarmSet =
subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_TRUE(firedAlarmSet.empty());
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15));
currentTimeSec = startMillis / MS_PER_SEC + 7000;
firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
EXPECT_EQ(firedAlarmSet.size(), 1u);
tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet);
EXPECT_TRUE(firedAlarmSet.empty());
- EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15 + 2 * 60 * 60);
+ EXPECT_EQ(tracker.mAlarmSec, (int64_t)(startMillis / MS_PER_SEC + 15 + 2 * 60 * 60));
}
} // namespace statsd
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d0840f0..0acd297 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -455,7 +455,7 @@
[](const sp<IStatsCompanionService>&){});
sp<StatsLogProcessor> processor = new StatsLogProcessor(
uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){});
- processor->OnConfigUpdated(key, config);
+ processor->OnConfigUpdated(timeBaseSec, key, config);
return processor;
}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 90308d7..9c7bfb2 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -296,6 +296,7 @@
Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/app/LoadedApk;->getAssets()Landroid/content/res/AssetManager;
Landroid/app/LoadedApk;->getClassLoader()Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
Landroid/app/LoadedApk;->getDataDirFile()Ljava/io/File;
Landroid/app/LoadedApk;->getResources()Landroid/content/res/Resources;
Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
@@ -377,8 +378,10 @@
Landroid/app/Vr2dDisplayProperties$Builder;->setEnabled(Z)Landroid/app/Vr2dDisplayProperties$Builder;
Landroid/app/Vr2dDisplayProperties;-><init>(III)V
Landroid/app/VrManager;->getPersistentVrModeEnabled()Z
+Landroid/app/VrManager;->mService:Landroid/service/vr/IVrManager;
Landroid/app/VrManager;->registerVrStateCallback(Landroid/app/VrStateCallback;Landroid/os/Handler;)V
Landroid/app/VrManager;->setVr2dDisplayProperties(Landroid/app/Vr2dDisplayProperties;)V
+Landroid/app/VrManager;->unregisterVrStateCallback(Landroid/app/VrStateCallback;)V
Landroid/app/WallpaperColors;->getColorHints()I
Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap;
Landroid/app/WallpaperManager;->getBitmap(Z)Landroid/graphics/Bitmap;
@@ -447,6 +450,7 @@
Landroid/content/ContentResolver;->unstableProviderDied(Landroid/content/IContentProvider;)V
Landroid/content/ContentValues;-><init>(Ljava/util/HashMap;)V
Landroid/content/ContentValues;->mValues:Ljava/util/HashMap;
+Landroid/content/Context;->getBasePackageName()Ljava/lang/String;
Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
Landroid/content/Context;->getThemeResId()I
Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;I)V
@@ -469,6 +473,7 @@
Landroid/content/Intent;->mExtras:Landroid/os/Bundle;
Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
Landroid/content/pm/ActivityInfo;->resizeMode:I
+Landroid/content/pm/ActivityInfo;->supportsPictureInPicture()Z
Landroid/content/pm/ApplicationInfo;->enabledSetting:I
Landroid/content/pm/ApplicationInfo;->getBaseResourcePath()Ljava/lang/String;
Landroid/content/pm/ApplicationInfo;->installLocation:I
@@ -2099,6 +2104,8 @@
Landroid/util/SparseIntArray;->mKeys:[I
Landroid/util/SparseIntArray;->mSize:I
Landroid/util/SparseIntArray;->mValues:[I
+Landroid/view/accessibility/AccessibilityInteractionClient;->clearCache()V
+Landroid/view/accessibility/AccessibilityInteractionClient;->getInstance()Landroid/view/accessibility/AccessibilityInteractionClient;
Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager;
Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z
Landroid/view/accessibility/AccessibilityManager;->mAccessibilityStateChangeListeners:Landroid/util/ArrayMap;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 1776eac..95e4f93 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -279,12 +279,12 @@
}});
registerService(Context.IPSEC_SERVICE, IpSecManager.class,
- new StaticServiceFetcher<IpSecManager>() {
+ new CachedServiceFetcher<IpSecManager>() {
@Override
- public IpSecManager createService() {
+ public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
IIpSecService service = IIpSecService.Stub.asInterface(b);
- return new IpSecManager(service);
+ return new IpSecManager(ctx, service);
}});
registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 4124536..7ebe0f9 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -43,6 +43,9 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
@@ -924,6 +927,37 @@
idCount++;
}
}
+
+ // The sort logic must match the logic in
+ // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
+ Arrays.sort(cameraIds, new Comparator<String>() {
+ @Override
+ public int compare(String s1, String s2) {
+ int s1Int = 0, s2Int = 0;
+ try {
+ s1Int = Integer.parseInt(s1);
+ } catch (NumberFormatException e) {
+ s1Int = -1;
+ }
+
+ try {
+ s2Int = Integer.parseInt(s2);
+ } catch (NumberFormatException e) {
+ s2Int = -1;
+ }
+
+ // Uint device IDs first
+ if (s1Int >= 0 && s2Int >= 0) {
+ return s1Int - s2Int;
+ } else if (s1Int >= 0) {
+ return -1;
+ } else if (s2Int >= 0) {
+ return 1;
+ } else {
+ // Simple string compare if both id are not uint
+ return s1.compareTo(s2);
+ }
+ }});
return cameraIds;
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 2252571..411a97e 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2105,8 +2105,8 @@
* the thumbnail data will also be rotated.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
- * <p>To translate from the device orientation given by the Android sensor APIs, the following
- * sample code may be used:</p>
+ * <p>To translate from the device orientation given by the Android sensor APIs for camera
+ * sensors which are not EXTERNAL, the following sample code may be used:</p>
* <pre><code>private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
* if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0;
* int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -2125,6 +2125,8 @@
* return jpegOrientation;
* }
* </code></pre>
+ * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
+ * also be set to EXTERNAL. The above code is not relevant in such case.</p>
* <p><b>Units</b>: Degrees in multiples of 90</p>
* <p><b>Range of valid values:</b><br>
* 0, 90, 180, 270</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 8df5447..c156616 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2422,8 +2422,8 @@
* the thumbnail data will also be rotated.</p>
* <p>Note that this orientation is relative to the orientation of the camera sensor, given
* by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
- * <p>To translate from the device orientation given by the Android sensor APIs, the following
- * sample code may be used:</p>
+ * <p>To translate from the device orientation given by the Android sensor APIs for camera
+ * sensors which are not EXTERNAL, the following sample code may be used:</p>
* <pre><code>private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
* if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0;
* int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -2442,6 +2442,8 @@
* return jpegOrientation;
* }
* </code></pre>
+ * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
+ * also be set to EXTERNAL. The above code is not relevant in such case.</p>
* <p><b>Units</b>: Degrees in multiples of 90</p>
* <p><b>Range of valid values:</b><br>
* 0, 90, 180, 270</p>
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index 3a3ddcc..d6774d4 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -45,25 +45,31 @@
in String localAddr,
in String remoteAddr,
in Network underlyingNetwork,
- in IBinder binder);
+ in IBinder binder,
+ in String callingPackage);
void addAddressToTunnelInterface(
int tunnelResourceId,
- in LinkAddress localAddr);
+ in LinkAddress localAddr,
+ in String callingPackage);
void removeAddressFromTunnelInterface(
int tunnelResourceId,
- in LinkAddress localAddr);
+ in LinkAddress localAddr,
+ in String callingPackage);
- void deleteTunnelInterface(int resourceId);
+ void deleteTunnelInterface(int resourceId, in String callingPackage);
- IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder);
+ IpSecTransformResponse createTransform(
+ in IpSecConfig c, in IBinder binder, in String callingPackage);
void deleteTransform(int transformId);
- void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId);
+ void applyTransportModeTransform(
+ in ParcelFileDescriptor socket, int direction, int transformId);
- void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId);
+ void applyTunnelModeTransform(
+ int tunnelResourceId, int direction, int transformResourceId, in String callingPackage);
void removeTransportModeTransforms(in ParcelFileDescriptor socket);
}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 1525508..e0654fd 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -140,6 +140,7 @@
}
}
+ private final Context mContext;
private final IIpSecService mService;
/**
@@ -661,6 +662,7 @@
*/
@SystemApi
public static final class IpSecTunnelInterface implements AutoCloseable {
+ private final String mOpPackageName;
private final IIpSecService mService;
private final InetAddress mRemoteAddress;
private final InetAddress mLocalAddress;
@@ -688,7 +690,8 @@
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void addAddress(@NonNull LinkAddress address) throws IOException {
try {
- mService.addAddressToTunnelInterface(mResourceId, address);
+ mService.addAddressToTunnelInterface(
+ mResourceId, address, mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -706,16 +709,18 @@
@RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
public void removeAddress(@NonNull LinkAddress address) throws IOException {
try {
- mService.removeAddressFromTunnelInterface(mResourceId, address);
+ mService.removeAddressFromTunnelInterface(
+ mResourceId, address, mOpPackageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- private IpSecTunnelInterface(@NonNull IIpSecService service,
+ private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
@NonNull Network underlyingNetwork)
throws ResourceUnavailableException, IOException {
+ mOpPackageName = ctx.getOpPackageName();
mService = service;
mLocalAddress = localAddress;
mRemoteAddress = remoteAddress;
@@ -727,7 +732,8 @@
localAddress.getHostAddress(),
remoteAddress.getHostAddress(),
underlyingNetwork,
- new Binder());
+ new Binder(),
+ mOpPackageName);
switch (result.status) {
case Status.OK:
break;
@@ -756,7 +762,7 @@
@Override
public void close() {
try {
- mService.deleteTunnelInterface(mResourceId);
+ mService.deleteTunnelInterface(mResourceId, mOpPackageName);
mResourceId = INVALID_RESOURCE_ID;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -801,7 +807,8 @@
public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
@NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
throws ResourceUnavailableException, IOException {
- return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork);
+ return new IpSecTunnelInterface(
+ mContext, mService, localAddress, remoteAddress, underlyingNetwork);
}
/**
@@ -827,7 +834,8 @@
@PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
try {
mService.applyTunnelModeTransform(
- tunnel.getResourceId(), direction, transform.getResourceId());
+ tunnel.getResourceId(), direction,
+ transform.getResourceId(), mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -839,7 +847,8 @@
* @param context the application context for this manager
* @hide
*/
- public IpSecManager(IIpSecService service) {
+ public IpSecManager(Context ctx, IIpSecService service) {
+ mContext = ctx;
mService = checkNotNull(service, "missing service");
}
}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 099fe02..fb5f46c 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -130,7 +130,8 @@
synchronized (this) {
try {
IIpSecService svc = getIpSecService();
- IpSecTransformResponse result = svc.createTransform(mConfig, new Binder());
+ IpSecTransformResponse result = svc.createTransform(
+ mConfig, new Binder(), mContext.getOpPackageName());
int status = result.status;
checkResultStatus(status);
mResourceId = result.resourceId;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b0367dc..68fc6c1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9220,8 +9220,8 @@
public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
/**
- * Map of package name to application names. Package names must be lower cased as they are
- * used as a key in the map. The application names cannot and will not be localized.
+ * Map of package name to application names. The application names cannot and will not be
+ * localized. App names may not contain colons or semicolons.
*
* The value is "packageName1:appName1;packageName2:appName2;..."
* @hide
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index c8efede..5db3c1a 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Channel {
+public final class Channel implements java.nio.channels.Channel {
private static final String TAG = "OMAPI.Channel";
private Session mSession;
@@ -64,7 +64,7 @@
* before closing the channel.
*/
public void close() {
- if (!isClosed()) {
+ if (isOpen()) {
synchronized (mLock) {
try {
mChannel.close();
@@ -76,21 +76,21 @@
}
/**
- * Tells if this channel is closed.
+ * Tells if this channel is open.
*
- * @return <code>true</code> if the channel is closed or in case of an error.
- * <code>false</code> otherwise.
+ * @return <code>false</code> if the channel is closed or in case of an error.
+ * <code>true</code> otherwise.
*/
- public boolean isClosed() {
+ public boolean isOpen() {
if (!mService.isConnected()) {
Log.e(TAG, "service not connected to system");
- return true;
+ return false;
}
try {
- return mChannel.isClosed();
+ return !mChannel.isClosed();
} catch (RemoteException e) {
Log.e(TAG, "Exception in isClosed()");
- return true;
+ return false;
}
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 9be3da6..80262f7 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -37,7 +37,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Reader {
+public final class Reader {
private static final String TAG = "OMAPI.Reader";
private final String mName;
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 311dc4c..14727f0 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -32,6 +32,7 @@
import android.util.Log;
import java.util.HashMap;
+import java.util.concurrent.Executor;
/**
* The SEService realises the communication to available Secure Elements on the
@@ -40,7 +41,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class SEService {
+public final class SEService {
/**
* Error code used with ServiceSpecificException.
@@ -62,11 +63,11 @@
/**
* Interface to send call-backs to the application when the service is connected.
*/
- public interface SecureElementListener {
+ public interface OnConnectedListener {
/**
* Called by the framework when the service is connected.
*/
- void onServiceConnected();
+ void onConnected();
}
/**
@@ -74,16 +75,22 @@
* SEService could be bound to the backend.
*/
private class SEListener extends ISecureElementListener.Stub {
- public SecureElementListener mListener = null;
+ public OnConnectedListener mListener = null;
+ public Executor mExecutor = null;
@Override
public IBinder asBinder() {
return this;
}
- public void onServiceConnected() {
- if (mListener != null) {
- mListener.onServiceConnected();
+ public void onConnected() {
+ if (mListener != null && mExecutor != null) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onConnected();
+ }
+ });
}
}
}
@@ -116,22 +123,26 @@
* the specified listener is called or if isConnected() returns
* <code>true</code>. <br>
* The call-back object passed as a parameter will have its
- * onServiceConnected() method called when the connection actually happen.
+ * onConnected() method called when the connection actually happen.
*
* @param context
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a SecureElementListener object.
+ * a OnConnectedListener object.
+ * @param executor
+ * an Executor which will be used when invoking the callback.
*/
- public SEService(@NonNull Context context, @NonNull SecureElementListener listener) {
+ public SEService(@NonNull Context context, @NonNull Executor executor,
+ @NonNull OnConnectedListener listener) {
- if (context == null) {
- throw new NullPointerException("context must not be null");
+ if (context == null || listener == null || executor == null) {
+ throw new NullPointerException("Arguments must not be null");
}
mContext = context;
mSEListener.mListener = listener;
+ mSEListener.mExecutor = executor;
mConnection = new ServiceConnection() {
@@ -140,7 +151,7 @@
mSecureElementService = ISecureElementService.Stub.asInterface(service);
if (mSEListener != null) {
- mSEListener.onServiceConnected();
+ mSEListener.onConnected();
}
Log.i(TAG, "Service onServiceConnected");
}
@@ -171,12 +182,12 @@
}
/**
- * Returns the list of available Secure Element readers.
+ * Returns an array of available Secure Element readers.
* There must be no duplicated objects in the returned list.
* All available readers shall be listed even if no card is inserted.
*
- * @return The readers list, as an array of Readers. If there are no
- * readers the returned array is of length 0.
+ * @return An array of Readers. If there are no readers the returned array
+ * is of length 0.
*/
public @NonNull Reader[] getReaders() {
if (mSecureElementService == null) {
@@ -212,7 +223,8 @@
* (including any binding to an underlying service).
* As a result isConnected() will return false after shutdown() was called.
* After this method call, the SEService object is not connected.
- * It is recommended to call this method in the termination method of the calling application
+ * This method should be called when connection to the Secure Element is not needed
+ * or in the termination method of the calling application
* (or part of this application) which is bound to this SEService.
*/
public void shutdown() {
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index adfeddd..d5f8c82 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class Session {
+public final class Session {
private final Object mLock = new Object();
private final SEService mService;
@@ -225,6 +225,32 @@
}
/**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openBasicChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array, or null if no Applet is to be selected.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element session is used after
+ * being closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
+ * selected.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device
+ * @return an instance of Channel if available or null.
+ */
+ public @Nullable Channel openBasicChannel(@Nullable byte[] aid) throws IOException {
+ return openBasicChannel(aid, (byte) 0x00);
+ }
+
+ /**
* Open a logical channel with the Secure Element, selecting the Applet represented by
* the given AID. If the AID is null, which means no Applet is to be selected on this
* channel, the default Applet is used. It's up to the Secure Element to choose which
@@ -304,4 +330,32 @@
}
}
}
+
+ /**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openLogicalChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element is used after being
+ * closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not
+ * available or cannot be selected or a logical channel is already
+ * open to a non-multiselectable Applet.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device.
+ * @return an instance of Channel. Null if the Secure Element is unable to
+ * provide a new logical channel.
+ */
+ public @Nullable Channel openLogicalChannel(@Nullable byte[] aid) throws IOException {
+ return openLogicalChannel(aid, (byte) 0x00);
+ }
}
diff --git a/core/java/android/security/Scrypt.java b/core/java/android/security/Scrypt.java
new file mode 100644
index 0000000..edf8d31
--- /dev/null
+++ b/core/java/android/security/Scrypt.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * A Java wrapper for the JNI function to perform the password hashing algorithm SCRYPT.
+ *
+ * @hide
+ */
+public class Scrypt {
+
+ native byte[] nativeScrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen);
+
+ /** Computes the password hashing algorithm SCRYPT. */
+ public byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
+ return nativeScrypt(password, salt, n, r, p, outLen);
+ }
+}
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index ab3ed91..281822a 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -285,7 +285,17 @@
public void initRecoveryService(
@NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
throws CertificateException, InternalRecoveryServiceException {
- throw new CertificateException("Deprecated initRecoveryService method called");
+ try {
+ mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (ServiceSpecificException e) {
+ if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+ || e.errorCode == ERROR_INVALID_CERTIFICATE) {
+ throw new CertificateException("Invalid certificate for recovery service", e);
+ }
+ throw wrapUnexpectedServiceSpecificException(e);
+ }
}
/**
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 413df05..44789d6 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -16,6 +16,7 @@
package android.text;
+import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -44,13 +45,17 @@
* <pre>
* An example usage is:
* <code>
- * void asyncSetText(final TextView textView, final String longString, Handler bgThreadHandler) {
+ * static void asyncSetText(TextView textView, final String longString, Executor bgExecutor) {
* // construct precompute related parameters using the TextView that we will set the text on.
- * final PrecomputedText.Params params = textView.getTextParams();
- * bgThreadHandler.post(() -> {
- * final PrecomputedText precomputedText =
- * PrecomputedText.create(expensiveLongString, params);
+ * final PrecomputedText.Params params = textView.getTextMetricsParams();
+ * final Reference textViewRef = new WeakReference<>(textView);
+ * bgExecutor.submit(() -> {
+ * TextView textView = textViewRef.get();
+ * if (textView == null) return;
+ * final PrecomputedText precomputedText = PrecomputedText.create(longString, params);
* textView.post(() -> {
+ * TextView textView = textViewRef.get();
+ * if (textView == null) return;
* textView.setText(precomputedText);
* });
* });
@@ -363,6 +368,7 @@
/**
* Return the underlying text.
+ * @hide
*/
public @NonNull CharSequence getText() {
return mText;
@@ -451,27 +457,61 @@
+ ", gave " + pos);
}
- /** @hide */
- public float getWidth(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
+ /**
+ * Returns text width for the given range.
+ * Both {@code start} and {@code end} offset need to be in the same paragraph, otherwise
+ * IllegalArgumentException will be thrown.
+ *
+ * @param start the inclusive start offset in the text
+ * @param end the exclusive end offset in the text
+ * @return the text width
+ * @throws IllegalArgumentException if start and end offset are in the different paragraph.
+ */
+ public @FloatRange(from = 0) float getWidth(@IntRange(from = 0) int start,
+ @IntRange(from = 0) int end) {
+ Preconditions.checkArgument(0 <= start && start <= mText.length(), "invalid start offset");
+ Preconditions.checkArgument(0 <= end && end <= mText.length(), "invalid end offset");
+ Preconditions.checkArgument(start <= end, "start offset can not be larger than end offset");
+
+ if (start == end) {
+ return 0;
+ }
final int paraIndex = findParaIndex(start);
final int paraStart = getParagraphStart(paraIndex);
final int paraEnd = getParagraphEnd(paraIndex);
if (start < paraStart || paraEnd < end) {
- throw new RuntimeException("Cannot measured across the paragraph:"
+ throw new IllegalArgumentException("Cannot measured across the paragraph:"
+ "para: (" + paraStart + ", " + paraEnd + "), "
+ "request: (" + start + ", " + end + ")");
}
return getMeasuredParagraph(paraIndex).getWidth(start - paraStart, end - paraStart);
}
- /** @hide */
+ /**
+ * Retrieves the text bounding box for the given range.
+ * Both {@code start} and {@code end} offset need to be in the same paragraph, otherwise
+ * IllegalArgumentException will be thrown.
+ *
+ * @param start the inclusive start offset in the text
+ * @param end the exclusive end offset in the text
+ * @param bounds the output rectangle
+ * @throws IllegalArgumentException if start and end offset are in the different paragraph.
+ */
public void getBounds(@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@NonNull Rect bounds) {
+ Preconditions.checkArgument(0 <= start && start <= mText.length(), "invalid start offset");
+ Preconditions.checkArgument(0 <= end && end <= mText.length(), "invalid end offset");
+ Preconditions.checkArgument(start <= end, "start offset can not be larger than end offset");
+ Preconditions.checkNotNull(bounds);
+ if (start == end) {
+ bounds.set(0, 0, 0, 0);
+ return;
+ }
final int paraIndex = findParaIndex(start);
final int paraStart = getParagraphStart(paraIndex);
final int paraEnd = getParagraphEnd(paraIndex);
if (start < paraStart || paraEnd < end) {
- throw new RuntimeException("Cannot measured across the paragraph:"
+ throw new IllegalArgumentException("Cannot measured across the paragraph:"
+ "para: (" + paraStart + ", " + paraEnd + "), "
+ "request: (" + start + ", " + end + ")");
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 6e0ba341..97043c7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -389,6 +389,10 @@
@Override
public void showTargetDetails(ResolveInfo ri) {
+ if (ri == null) {
+ return;
+ }
+
ComponentName name = ri.activityInfo.getComponentName();
boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
ResolverTargetActionsDialogFragment f =
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1d22093..302189f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -195,6 +195,7 @@
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_animation_PropertyValuesHolder.cpp",
+ "android_security_Scrypt.cpp",
"com_android_internal_net_NetworkStatsFactory.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
@@ -228,6 +229,7 @@
"libseccomp_policy",
"libselinux",
"libgrallocusage",
+ "libscrypt_static",
],
shared_libs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5ae4a52..f8dd7ac 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -208,6 +208,7 @@
extern int register_android_content_res_ObbScanner(JNIEnv* env);
extern int register_android_content_res_Configuration(JNIEnv* env);
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
+extern int register_android_security_Scrypt(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
@@ -1492,6 +1493,7 @@
REG_JNI(register_android_content_res_Configuration),
REG_JNI(register_android_animation_PropertyValuesHolder),
+ REG_JNI(register_android_security_Scrypt),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
REG_JNI(register_com_android_internal_os_FuseAppLoop),
diff --git a/core/jni/android_security_Scrypt.cpp b/core/jni/android_security_Scrypt.cpp
new file mode 100644
index 0000000..3350804
--- /dev/null
+++ b/core/jni/android_security_Scrypt.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 LOG_TAG "Scrypt"
+
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+
+#include <android_runtime/Log.h>
+#include <utils/Timers.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+
+extern "C" {
+#include "crypto_scrypt.h"
+}
+
+namespace android {
+
+static jbyteArray android_security_Scrypt_nativeScrypt(JNIEnv* env, jobject, jbyteArray password, jbyteArray salt, jint N, jint r, jint p, jint outLen) {
+ if (!password || !salt) {
+ return NULL;
+ }
+
+ int passwordLen = env->GetArrayLength(password);
+ int saltLen = env->GetArrayLength(salt);
+ jbyteArray ret = env->NewByteArray(outLen);
+
+ jbyte* passwordPtr = (jbyte*)env->GetByteArrayElements(password, NULL);
+ jbyte* saltPtr = (jbyte*)env->GetByteArrayElements(salt, NULL);
+ jbyte* retPtr = (jbyte*)env->GetByteArrayElements(ret, NULL);
+
+ int rc = crypto_scrypt((const uint8_t *)passwordPtr, passwordLen,
+ (const uint8_t *)saltPtr, saltLen, N, r, p, (uint8_t *)retPtr,
+ outLen);
+ env->ReleaseByteArrayElements(password, passwordPtr, JNI_ABORT);
+ env->ReleaseByteArrayElements(salt, saltPtr, JNI_ABORT);
+ env->ReleaseByteArrayElements(ret, retPtr, 0);
+
+ if (!rc) {
+ return ret;
+ } else {
+ SLOGE("scrypt failed");
+ return NULL;
+ }
+}
+
+static const JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"nativeScrypt", "([B[BIIII)[B", (void*)android_security_Scrypt_nativeScrypt},
+};
+
+int register_android_security_Scrypt(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "android/security/Scrypt",
+ sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
new file mode 100644
index 0000000..ed42e2e
--- /dev/null
+++ b/core/proto/OWNERS
@@ -0,0 +1,13 @@
+# Be sure you are familiar with proto when you modify this directory.
+
+# Metrics
+bookatz@google.com
+cjyu@google.com
+jinyithu@google.com
+joeo@google.com
+kwekua@google.com
+singhtejinder@google.com
+
+# Frameworks
+ogunwale@google.com
+jjaggi@google.com
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ea0b825..6467976 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -228,7 +228,7 @@
];
optional android.service.print.PrintServiceDumpProto print = 3010 [
- (section).type = SECTION_DUMPSYS,
+ (section).type = SECTION_NONE, // Turn off until we get approval for it.
(section).args = "print --proto"
];
diff --git a/core/proto/android/service/print.proto b/core/proto/android/service/print.proto
index f783b86..994814b 100644
--- a/core/proto/android/service/print.proto
+++ b/core/proto/android/service/print.proto
@@ -75,7 +75,7 @@
repeated PrintJobInfoProto print_jobs = 1;
// Files used by these print jobs
- repeated string print_job_files = 2;
+ repeated string print_job_files = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
// Approved print services
repeated android.content.ComponentNameProto approved_services = 3;
@@ -101,7 +101,7 @@
}
message PrinterInfoProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
// The id of the printer
optional PrinterIdProto id = 1;
@@ -123,7 +123,7 @@
STATUS_UNAVAILABLE = 3;
}
// The status of the printer
- optional Status status = 3;
+ optional Status status = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
// The description of the printer
optional string description = 4;
@@ -171,13 +171,13 @@
}
message PrinterIdProto {
- option (android.msg_privacy).dest = DEST_AUTOMATIC;
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
// Component name of the service that reported the printer
- optional android.content.ComponentNameProto service_name = 1;
+ optional android.content.ComponentNameProto service_name = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Local id of the printer
- optional string local_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+ optional string local_id = 2;
}
message ActivePrintServiceProto {
@@ -331,7 +331,7 @@
optional string label = 1 [ (android.privacy).dest = DEST_EXPLICIT ];
// Id of the job
- optional string print_job_id = 2;
+ optional string print_job_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
enum State {
// Unknown state
@@ -366,7 +366,7 @@
optional PrinterIdProto printer = 4;
// Tag assigned to the job
- optional string tag = 5;
+ optional string tag = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
// Time the job was created
optional int64 creation_time = 6;
@@ -401,4 +401,4 @@
// The print job
optional PrintJobInfoProto print_job = 2;
-}
\ No newline at end of file
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f4715fc..04c4130 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4248,6 +4248,11 @@
android:exported="false">
</receiver>
+ <receiver android:name="com.android.server.stats.StatsCompanionService$PeriodicAlarmReceiver"
+ android:permission="android.permission.STATSCOMPANION"
+ android:exported="false">
+ </receiver>
+
<receiver android:name="com.android.server.am.BatteryStatsService$UsbConnectionReceiver"
android:exported="false">
<intent-filter>
diff --git a/core/res/res/drawable/ic_account_circle.xml b/core/res/res/drawable/ic_account_circle.xml
index a8c5b8c..f7317db 100644
--- a/core/res/res/drawable/ic_account_circle.xml
+++ b/core/res/res/drawable/ic_account_circle.xml
@@ -16,9 +16,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:pathData="M24,0C10.8,0 0,10.8 0,24s10.8,24 24,24s24,-10.8 24,-24S37.200001,0 24,0zM24,7.2c3.96,0 7.2,3.24 7.2,7.2s-3.24,7.2 -7.2,7.2s-7.2,-3.24 -7.2,-7.2S20.040001,7.2 24,7.2zM24,41.279999c-6,0 -11.28,-3.12 -14.4,-7.68c0.12,-4.8 9.6,-7.44 14.4,-7.44s14.28,2.64 14.4,7.44C35.279999,38.16 30,41.279999 24,41.279999z"
- android:fillColor="#FFFFFFFF"/>
+ android:viewportWidth="20.0"
+ android:viewportHeight="20.0">
+ <group
+ android:translateX="-2"
+ android:translateY="-2" >
+ <path
+ android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM18.36,16.83c-1.43,-1.74 -4.9,-2.33 -6.36,-2.33s-4.93,0.59 -6.36,2.33C4.62,15.49 4,13.82 4,12c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,13.82 19.38,15.49 18.36,16.83z"
+ android:fillColor="#FFFFFFFF" />
+ <path
+ android:pathData="M12,6c-1.94,0 -3.5,1.56 -3.5,3.5S10.06,13 12,13c1.94,0 3.5,-1.56 3.5,-3.5S13.94,6 12,6z"
+ android:fillColor="#FFFFFFFF" />
+ </group>
</vector>
diff --git a/core/res/res/drawable/ic_lock_bugreport.xml b/core/res/res/drawable/ic_lock_bugreport.xml
index 5501254..ebeb532 100644
--- a/core/res/res/drawable/ic_lock_bugreport.xml
+++ b/core/res/res/drawable/ic_lock_bugreport.xml
@@ -21,5 +21,11 @@
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#FF000000"
- android:pathData="M20.0,8.0l-2.81,0.0a5.985,5.985 0.0,0.0 0.0,-1.82 -1.96l0.93,-0.93a0.99,0.996 0.0,1.0 0.0,-1.41 -1.41l-1.47,1.47C12.96,5.06 12.49,5.0 12.0,5.0s-0.9,0.06 -1.4,0.17L9.12,3.7a0.99,0.996 0.0,1.0 0.0,-1.41 1.41l0.9,0.92C7.88,6.55 7.26,7.22 6.81,8.0L4.0,8.0c-0.55,0.0 -1.0,0.45 -1.0,1.0s0.45,1.0 1.0,1.0l2.09,0.0c0.0,0.33 0.0,0.66 -0.09,1.0l0.0,1.0L4.0,12.0c-0.55,0.0 -1.0,0.45 -1.0,1.0s0.45,1.0 1.0,1.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.6 0.09,1.0L4.0,16.0c-0.55,0.0 -1.0,0.45 -1.0,1.0s0.45,1.0 1.0,1.0l2.81,0.0c1.04,1.79 2.97,3.0 5.19,3.0s4.15,-1.21 5.19,-3.0L20.0,18.0c0.55,0.0 1.0,-0.45 1.0,-1.0s-0.45,-1.0 -1.0,-1.0l-2.09,0.0c0.05,-0.3 0.09,-0.6 0.09,-1.0l0.0,-1.0l2.0,0.0c0.55,0.0 1.0,-0.45 1.0,-1.0s-0.45,-1.0 -1.0,-1.0l-2.0,0.0l0.0,-1.0c0.0,-0.34 -0.04,-0.67 -0.09,-1.0L20.0,10.0c0.55,0.0 1.0,-0.45 1.0,-1.0s-0.45,-1.0 -1.0,-1.0zm-6.0,8.0l-4.0,0.0l0.0,-2.0l4.0,0.0l0.0,2.0zm0.0,-4.0l-4.0,0.0l0.0,-2.0l4.0,0.0l0.0,2.0z"/>
+ android:pathData="M20,10V8h-2.81c-0.45,-0.78 -1.07,-1.46 -1.82,-1.96L17,4.41L15.59,3l-2.17,2.17c-0.03,-0.01 -0.05,-0.01 -0.08,-0.01c-0.16,-0.04 -0.32,-0.06 -0.49,-0.09c-0.06,-0.01 -0.11,-0.02 -0.17,-0.03C12.46,5.02 12.23,5 12,5h0c-0.49,0 -0.97,0.07 -1.42,0.18l0.02,-0.01L8.41,3L7,4.41l1.62,1.63l0.01,0C7.88,6.54 7.26,7.22 6.81,8H4v2h2.09C6.03,10.33 6,10.66 6,11v1H4v2h2v1c0,0.34 0.04,0.67 0.09,1H4v2h2.81c1.04,1.79 2.97,3 5.19,3h0c2.22,0 4.15,-1.21 5.19,-3H20v-2h-2.09l0,0c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1l0,0H20zM16,15c0,2.21 -1.79,4 -4,4c-2.21,0 -4,-1.79 -4,-4v-4c0,-2.21 1.79,-4 4,-4h0c2.21,0 4,1.79 4,4V15z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M10,14h4v2h-4z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M10,10h4v2h-4z"/>
</vector>
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index a4a1b94..95aff9a 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -55,6 +55,7 @@
<hidden-api-whitelisted-app package="com.android.companiondevicemanager" />
<hidden-api-whitelisted-app package="com.android.customlocale2" />
<hidden-api-whitelisted-app package="com.android.defcontainer" />
+ <hidden-api-whitelisted-app package="com.android.development" />
<hidden-api-whitelisted-app package="com.android.documentsui" />
<hidden-api-whitelisted-app package="com.android.dreams.basic" />
<hidden-api-whitelisted-app package="com.android.egg" />
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 00dc22e..31abf92 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -59,23 +59,131 @@
import java.util.concurrent.atomic.AtomicBoolean;
/**
- * Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
+ * <p>A class for converting encoded images (like {@code PNG}, {@code JPEG},
+ * {@code WEBP}, {@code GIF}, or {@code HEIF}) into {@link Drawable} or
+ * {@link Bitmap} objects.
+ *
+ * <p>To use it, first create a {@link Source Source} using one of the
+ * {@code createSource} overloads. For example, to decode from a {@link File}, call
+ * {@link #createSource(File)} and pass the result to {@link #decodeDrawable(Source)}
+ * or {@link #decodeBitmap(Source)}:
+ *
+ * <pre class="prettyprint">
+ * File file = new File(...);
+ * ImageDecoder.Source source = ImageDecoder.createSource(file);
+ * Drawable drawable = ImageDecoder.decodeDrawable(source);
+ * </pre>
+ *
+ * <p>To change the default settings, pass the {@link Source Source} and an
+ * {@link OnHeaderDecodedListener OnHeaderDecodedListener} to
+ * {@link #decodeDrawable(Source, OnHeaderDecodedListener)} or
+ * {@link #decodeBitmap(Source, OnHeaderDecodedListener)}. For example, to
+ * create a sampled image with half the width and height of the original image,
+ * call {@link #setTargetSampleSize setTargetSampleSize(2)} inside
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}:
+ *
+ * <pre class="prettyprint">
+ * OnHeaderDecodedListener listener = new OnHeaderDecodedListener() {
+ * public void onHeaderDecoded(ImageDecoder decoder, ImageInfo info, Source source) {
+ * decoder.setTargetSampleSize(2);
+ * }
+ * };
+ * Drawable drawable = ImageDecoder.decodeDrawable(source, listener);
+ * </pre>
+ *
+ * <p>The {@link ImageInfo ImageInfo} contains information about the encoded image, like
+ * its width and height, and the {@link Source Source} can be used to match to a particular
+ * {@link Source Source} if a single {@link OnHeaderDecodedListener OnHeaderDecodedListener}
+ * is used with multiple {@link Source Source} objects.
+ *
+ * <p>The {@link OnHeaderDecodedListener OnHeaderDecodedListener} can also be implemented
+ * as a lambda:
+ *
+ * <pre class="prettyprint">
+ * Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ * decoder.setTargetSampleSize(2);
+ * });
+ * </pre>
+ *
+ * <p>If the encoded image is an animated {@code GIF} or {@code WEBP},
+ * {@link #decodeDrawable decodeDrawable} will return an {@link AnimatedImageDrawable}. To
+ * start its animation, call {@link AnimatedImageDrawable#start AnimatedImageDrawable.start()}:
+ *
+ * <pre class="prettyprint">
+ * Drawable drawable = ImageDecoder.decodeDrawable(source);
+ * if (drawable instanceof AnimatedImageDrawable) {
+ * ((AnimatedImageDrawable) drawable).start();
+ * }
+ * </pre>
+ *
+ * <p>By default, a {@link Bitmap} created by {@link ImageDecoder} (including
+ * one that is inside a {@link Drawable}) will be immutable (i.e.
+ * {@link Bitmap#isMutable Bitmap.isMutable()} returns {@code false}), and it
+ * will typically have {@code Config} {@link Bitmap.Config#HARDWARE}. Although
+ * these properties can be changed with {@link #setMutableRequired setMutableRequired(true)}
+ * (which is only compatible with {@link #decodeBitmap(Source)} and
+ * {@link #decodeBitmap(Source, OnHeaderDecodedListener)}) and {@link #setAllocator},
+ * it is also possible to apply custom effects regardless of the mutability of
+ * the final returned object by passing a {@link PostProcessor} to
+ * {@link #setPostProcessor setPostProcessor}. A {@link PostProcessor} can also be a lambda:
+ *
+ * <pre class="prettyprint">
+ * Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ * decoder.setPostProcessor((canvas) -> {
+ * // This will create rounded corners.
+ * Path path = new Path();
+ * path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ * int width = canvas.getWidth();
+ * int height = canvas.getHeight();
+ * path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+ * Paint paint = new Paint();
+ * paint.setAntiAlias(true);
+ * paint.setColor(Color.TRANSPARENT);
+ * paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ * canvas.drawPath(path, paint);
+ * return PixelFormat.TRANSLUCENT;
+ * });
+ * });
+ * </pre>
+ *
+ * <p>If the encoded image is incomplete or contains an error, or if an
+ * {@link Exception} occurs during decoding, a {@link DecodeException DecodeException}
+ * will be thrown. In some cases, the {@link ImageDecoder} may have decoded part of
+ * the image. In order to display the partial image, an
+ * {@link OnPartialImageListener OnPartialImageListener} must be passed to
+ * {@link #setOnPartialImageListener setOnPartialImageListener}. For example:
+ *
+ * <pre class="prettyprint">
+ * Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+ * decoder.setOnPartialImageListener((DecodeException e) -> {
+ * // Returning true indicates to create a Drawable or Bitmap even
+ * // if the whole image could not be decoded. Any remaining lines
+ * // will be blank.
+ * return true;
+ * });
+ * });
+ * </pre>
*/
public final class ImageDecoder implements AutoCloseable {
/** @hide **/
public static int sApiLevel;
/**
- * Source of the encoded image data.
+ * Source of encoded image data.
*
- * <p>This object references the data that will be used to decode a
- * Drawable or Bitmap in {@link #decodeDrawable} or {@link #decodeBitmap}.
- * Constructing a {@code Source} (with one of the overloads of
- * {@code createSource}) can be done on any thread because the construction
- * simply captures values. The real work is done in decodeDrawable or
- * decodeBitmap.</p>
+ * <p>References the data that will be used to decode a {@link Drawable}
+ * or {@link Bitmap} in {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}. Constructing a {@code Source} (with
+ * one of the overloads of {@code createSource}) can be done on any thread
+ * because the construction simply captures values. The real work is done
+ * in {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}.
*
- * <p>Further, a Source object can be reused with different settings, or
+ * <p>A {@code Source} object can be reused to create multiple versions of the
+ * same image. For example, to decode a full size image and its thumbnail,
+ * the same {@code Source} can be used once with no
+ * {@link OnHeaderDecodedListener OnHeaderDecodedListener} and once with an
+ * implementation of {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
+ * that calls {@link #setTargetSize} with smaller dimensions. One {@code Source}
* even used simultaneously in multiple threads.</p>
*/
public static abstract class Source {
@@ -418,7 +526,7 @@
}
/**
- * Contains information about the encoded image.
+ * Information about an encoded image.
*/
public static class ImageInfo {
private final Size mSize;
@@ -448,8 +556,8 @@
/**
* Whether the image is animated.
*
- * <p>Calling {@link #decodeDrawable} will return an
- * {@link AnimatedImageDrawable}.</p>
+ * <p>If {@code true}, {@link #decodeDrawable decodeDrawable} will
+ * return an {@link AnimatedImageDrawable}.</p>
*/
public boolean isAnimated() {
return mDecoder.mAnimated;
@@ -475,19 +583,25 @@
public static class IncompleteException extends IOException {};
/**
- * Optional listener supplied to {@link #decodeDrawable} or
- * {@link #decodeBitmap}.
+ * Interface for changing the default settings of a decode.
*
- * <p>This is necessary in order to change the default settings of the
- * decode.</p>
+ * <p>Supply an instance to
+ * {@link #decodeDrawable(Source, OnHeaderDecodedListener) decodeDrawable}
+ * or {@link #decodeBitmap(Source, OnHeaderDecodedListener) decodeBitmap},
+ * which will call {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
+ * (in the same thread) once the size is known. The implementation of
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded} can then
+ * change the decode settings as desired.
*/
public static interface OnHeaderDecodedListener {
/**
- * Called when the header is decoded and the size is known.
+ * Called by {@link ImageDecoder} when the header has been decoded and
+ * the image size is known.
*
- * @param decoder allows changing the default settings of the decode.
- * @param info Information about the encoded image.
- * @param source that created the decoder.
+ * @param decoder the object performing the decode, for changing
+ * its default settings.
+ * @param info information about the encoded image.
+ * @param source object that created {@code decoder}.
*/
public void onHeaderDecoded(@NonNull ImageDecoder decoder,
@NonNull ImageInfo info, @NonNull Source source);
@@ -570,7 +684,7 @@
}
/**
- * Retrieve the {@link Source} that was interrupted.
+ * Retrieve the {@link Source Source} that was interrupted.
*
* <p>This can be used for equality checking to find the Source which
* failed to completely decode.</p>
@@ -595,25 +709,36 @@
}
/**
- * Optional listener supplied to the ImageDecoder.
+ * Interface for inspecting a {@link DecodeException DecodeException}
+ * and potentially preventing it from being thrown.
*
- * Without this listener, errors will throw {@link java.io.IOException}.
+ * <p>If an instance is passed to
+ * {@link #setOnPartialImageListener setOnPartialImageListener}, a
+ * {@link DecodeException DecodeException} that would otherwise have been
+ * thrown can be inspected inside
+ * {@link OnPartialImageListener#onPartialImage onPartialImage}.
+ * If {@link OnPartialImageListener#onPartialImage onPartialImage} returns
+ * {@code true}, a partial image will be created.
*/
public static interface OnPartialImageListener {
/**
- * Called when there is only a partial image to display.
+ * Called by {@link ImageDecoder} when there is only a partial image to
+ * display.
*
- * If decoding is interrupted after having decoded a partial image,
- * this listener lets the client know that and allows them to
- * optionally finish the rest of the decode/creation process to create
- * a partial {@link Drawable}/{@link Bitmap}.
+ * <p>If decoding is interrupted after having decoded a partial image,
+ * this method will be called. The implementation can inspect the
+ * {@link DecodeException DecodeException} and optionally finish the
+ * rest of the decode creation process to create a partial {@link Drawable}
+ * or {@link Bitmap}.
*
- * @param e containing information about the decode interruption.
- * @return True to create and return a {@link Drawable}/{@link Bitmap}
- * with partial data. False (which is the default) to abort the
- * decode and throw {@code e}.
+ * @param exception exception containing information about the
+ * decode interruption.
+ * @return {@code true} to create and return a {@link Drawable} or
+ * {@link Bitmap} with partial data. {@code false} (which is the
+ * default) to abort the decode and throw {@code e}. Any undecoded
+ * lines in the image will be blank.
*/
- boolean onPartialImage(@NonNull DecodeException e);
+ boolean onPartialImage(@NonNull DecodeException exception);
};
// Fields
@@ -679,12 +804,13 @@
}
/**
- * Create a new {@link Source} from a resource.
+ * Create a new {@link Source Source} from a resource.
*
* @param res the {@link Resources} object containing the image data.
* @param resId resource ID of the image data.
* @return a new Source object, which can be passed to
- * {@link #decodeDrawable} or {@link #decodeBitmap}.
+ * {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}.
*/
@AnyThread
@NonNull
@@ -694,12 +820,20 @@
}
/**
- * Create a new {@link Source} from a {@link android.net.Uri}.
+ * Create a new {@link Source Source} from a {@link android.net.Uri}.
+ *
+ * <h5>Accepts the following URI schemes:</h5>
+ * <ul>
+ * <li>content ({@link ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+ * <li>file ({@link ContentResolver#SCHEME_FILE})</li>
+ * </ul>
*
* @param cr to retrieve from.
* @param uri of the image file.
* @return a new Source object, which can be passed to
- * {@link #decodeDrawable} or {@link #decodeBitmap}.
+ * {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}.
*/
@AnyThread
@NonNull
@@ -721,7 +855,7 @@
}
/**
- * Create a new {@link Source} from a file in the "assets" directory.
+ * Create a new {@link Source Source} from a file in the "assets" directory.
*/
@AnyThread
@NonNull
@@ -730,12 +864,15 @@
}
/**
- * Create a new {@link Source} from a byte array.
+ * Create a new {@link Source Source} from a byte array.
*
* @param data byte array of compressed image data.
* @param offset offset into data for where the decoder should begin
* parsing.
* @param length number of bytes, beginning at offset, to parse.
+ * @return a new Source object, which can be passed to
+ * {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}.
* @throws NullPointerException if data is null.
* @throws ArrayIndexOutOfBoundsException if offset and length are
* not within data.
@@ -767,16 +904,20 @@
}
/**
- * Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
+ * Create a new {@link Source Source} from a {@link java.nio.ByteBuffer}.
*
- * <p>Decoding will start from {@link java.nio.ByteBuffer#position()}. The
- * position of {@code buffer} will not be affected.</p>
+ * <p>Decoding will start from {@link java.nio.ByteBuffer#position() buffer.position()}.
+ * The position of {@code buffer} will not be affected.</p>
*
- * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable}, and
- * the encoded image is animated, the returned {@link AnimatedImageDrawable}
+ * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable decodeDrawable},
+ * and the encoded image is animated, the returned {@link AnimatedImageDrawable}
* will continue reading from the {@code buffer}, so its contents must not
* be modified, even after the {@code AnimatedImageDrawable} is returned.
* {@code buffer}'s contents should never be modified during decode.</p>
+ *
+ * @return a new Source object, which can be passed to
+ * {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}.
*/
@AnyThread
@NonNull
@@ -812,7 +953,11 @@
}
/**
- * Create a new {@link Source} from a {@link java.io.File}.
+ * Create a new {@link Source Source} from a {@link java.io.File}.
+ *
+ * @return a new Source object, which can be passed to
+ * {@link #decodeDrawable decodeDrawable} or
+ * {@link #decodeBitmap decodeBitmap}.
*/
@AnyThread
@NonNull
@@ -863,14 +1008,17 @@
* Specify the size of the output {@link Drawable} or {@link Bitmap}.
*
* <p>By default, the output size will match the size of the encoded
- * image, which can be retrieved from the {@link ImageInfo} in
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * image, which can be retrieved from the {@link ImageInfo ImageInfo} in
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
+ *
+ * <p>This will sample or scale the output to an arbitrary size that may
+ * be smaller or larger than the encoded size.</p>
*
* <p>Only the last call to this or {@link #setTargetSampleSize} is
* respected.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
* @param width must be greater than 0.
* @param height must be greater than 0.
@@ -924,13 +1072,13 @@
* Set the target size with a sampleSize.
*
* <p>By default, the output size will match the size of the encoded
- * image, which can be retrieved from the {@link ImageInfo} in
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * image, which can be retrieved from the {@link ImageInfo ImageInfo} in
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
* <p>Requests the decoder to subsample the original image, returning a
- * smaller image to save memory. The sample size is the number of pixels
+ * smaller image to save memory. The {@code sampleSize} is the number of pixels
* in either dimension that correspond to a single pixel in the output.
- * For example, sampleSize == 4 returns an image that is 1/4 the
+ * For example, {@code sampleSize == 4} returns an image that is 1/4 the
* width/height of the original, and 1/16 the number of pixels.</p>
*
* <p>Must be greater than or equal to 1.</p>
@@ -938,7 +1086,7 @@
* <p>Only the last call to this or {@link #setTargetSize} is respected.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
* @param sampleSize Sampling rate of the encoded image.
*/
@@ -960,7 +1108,8 @@
* Will typically result in a {@link Bitmap.Config#HARDWARE}
* allocation, but may be software for small images. In addition, this will
* switch to software when HARDWARE is incompatible, e.g.
- * {@link #setMutableRequired}, {@link #setDecodeAsAlphaMaskEnabled}.
+ * {@link #setMutableRequired setMutableRequired(true)} or
+ * {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)}.
*/
public static final int ALLOCATOR_DEFAULT = 0;
@@ -983,9 +1132,10 @@
* Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
*
* When this is combined with incompatible options, like
- * {@link #setMutableRequired} or {@link #setDecodeAsAlphaMaskEnabled},
- * {@link #decodeDrawable} / {@link #decodeBitmap} will throw an
- * {@link java.lang.IllegalStateException}.
+ * {@link #setMutableRequired setMutableRequired(true)} or
+ * {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)},
+ * {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}
+ * will throw an {@link java.lang.IllegalStateException}.
*/
public static final int ALLOCATOR_HARDWARE = 3;
@@ -1002,7 +1152,7 @@
* <p>This is ignored for animated drawables.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
* @param allocator Type of allocator to use.
*/
@@ -1029,13 +1179,13 @@
* {@link android.view.View} system (i.e. to a {@link Canvas}). Calling
* this method with a value of {@code true} will result in
* {@link #decodeBitmap} returning a {@link Bitmap} with unpremultiplied
- * pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with
- * {@link #decodeDrawable}; attempting to decode an unpremultiplied
- * {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
- * </p>
+ * pixels. See {@link Bitmap#isPremultiplied Bitmap.isPremultiplied()}.
+ * This is incompatible with {@link #decodeDrawable decodeDrawable};
+ * attempting to decode an unpremultiplied {@link Drawable} will throw an
+ * {@link java.lang.IllegalStateException}. </p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
public void setUnpremultipliedRequired(boolean unpremultipliedRequired) {
mUnpremultipliedRequired = unpremultipliedRequired;
@@ -1072,6 +1222,9 @@
* {@link Bitmap}. For a {@code Drawable} or an immutable {@code Bitmap},
* this is the only way to process the image after decoding.</p>
*
+ * <p>If combined with {@link #setTargetSize} and/or {@link #setCrop},
+ * {@link PostProcessor#onPostProcess} occurs last.</p>
+ *
* <p>If set on a nine-patch image, the nine-patch data is ignored.</p>
*
* <p>For an animated image, the drawing commands drawn on the
@@ -1079,11 +1232,11 @@
* frame.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
*/
- public void setPostProcessor(@Nullable PostProcessor p) {
- mPostProcessor = p;
+ public void setPostProcessor(@Nullable PostProcessor postProcessor) {
+ mPostProcessor = postProcessor;
}
/**
@@ -1098,18 +1251,18 @@
* Set (replace) the {@link OnPartialImageListener} on this object.
*
* <p>Will be called if there is an error in the input. Without one, an
- * error will result in an Exception being thrown.</p>
+ * error will result in an {@code Exception} being thrown.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
*/
- public void setOnPartialImageListener(@Nullable OnPartialImageListener l) {
- mOnPartialImageListener = l;
+ public void setOnPartialImageListener(@Nullable OnPartialImageListener listener) {
+ mOnPartialImageListener = listener;
}
/**
- * Return the {@link OnPartialImageListener} currently set.
+ * Return the {@link OnPartialImageListener OnPartialImageListener} currently set.
*/
@Nullable
public OnPartialImageListener getOnPartialImageListener() {
@@ -1122,14 +1275,14 @@
* <p>{@code subset} must be contained within the size set by
* {@link #setTargetSize} or the bounds of the image if setTargetSize was
* not called. Otherwise an {@link IllegalStateException} will be thrown by
- * {@link #decodeDrawable}/{@link #decodeBitmap}.</p>
+ * {@link #decodeDrawable decodeDrawable}/{@link #decodeBitmap decodeBitmap}.</p>
*
* <p>NOT intended as a replacement for
- * {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
- * but merely crops the output.</p>
+ * {@link BitmapRegionDecoder#decodeRegion BitmapRegionDecoder.decodeRegion()}.
+ * This supports all formats, but merely crops the output.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
*/
public void setCrop(@Nullable Rect subset) {
@@ -1151,7 +1304,7 @@
* rectangle during decode. Otherwise it will not be modified.
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*
* @hide
*/
@@ -1162,21 +1315,22 @@
/**
* Specify whether the {@link Bitmap} should be mutable.
*
- * <p>By default, a {@link Bitmap} created will be immutable, but that can
- * be changed with this call.</p>
+ * <p>By default, a {@link Bitmap} created by {@link #decodeBitmap decodeBitmap}
+ * will be immutable i.e. {@link Bitmap#isMutable() Bitmap.isMutable()} returns
+ * {@code false}. This can be changed with {@code setMutableRequired(true)}.
*
* <p>Mutable Bitmaps are incompatible with {@link #ALLOCATOR_HARDWARE},
* because {@link Bitmap.Config#HARDWARE} Bitmaps cannot be mutable.
* Attempting to combine them will throw an
* {@link java.lang.IllegalStateException}.</p>
*
- * <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable},
+ * <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable decodeDrawable},
* which would require retrieving the Bitmap from the returned Drawable in
* order to modify. Attempting to decode a mutable {@link Drawable} will
* throw an {@link java.lang.IllegalStateException}.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
public void setMutableRequired(boolean mutable) {
mMutable = mutable;
@@ -1192,7 +1346,7 @@
}
/**
- * Return whether the {@link Bitmap} will be mutable.
+ * Return whether the decoded {@link Bitmap} will be mutable.
*/
public boolean isMutableRequired() {
return mMutable;
@@ -1219,7 +1373,7 @@
* the memory used.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
public void setConserveMemory(boolean conserveMemory) {
mConserveMemory = conserveMemory;
@@ -1244,12 +1398,12 @@
* no effect.</p>
*
* <p>This is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
- * combine them will result in {@link #decodeDrawable}/
- * {@link #decodeBitmap} throwing an
+ * combine them will result in {@link #decodeDrawable decodeDrawable}/
+ * {@link #decodeBitmap decodeBitmap} throwing an
* {@link java.lang.IllegalStateException}.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
public void setDecodeAsAlphaMaskEnabled(boolean enabled) {
mDecodeAsAlphaMask = enabled;
@@ -1304,21 +1458,22 @@
/**
* Specify the desired {@link ColorSpace} for the output.
*
- * <p>If non-null, the decoder will try to decode into this
- * color space. If it is null, which is the default, or the request cannot
- * be met, the decoder will pick either the color space embedded in the
- * image or the color space best suited for the requested image
- * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for
- * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
+ * <p>If non-null, the decoder will try to decode into {@code colorSpace}.
+ * If it is null, which is the default, or the request cannot be met, the
+ * decoder will pick either the color space embedded in the image or the
+ * {@link ColorSpace} best suited for the requested image configuration
+ * (for instance {@link ColorSpace.Named#SRGB sRGB} for the
+ * {@link Bitmap.Config#ARGB_8888} configuration).</p>
*
* <p>{@link Bitmap.Config#RGBA_F16} always uses the
- * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
+ * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space.
* Bitmaps in other configurations without an embedded color space are
* assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
*
* <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
* currently supported. An <code>IllegalArgumentException</code> will
- * be thrown by the decode methods when setting a non-RGB color space
+ * be thrown by {@link #decodeDrawable decodeDrawable}/
+ * {@link #decodeBitmap decodeBitmap} when setting a non-RGB color space
* such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
*
* <p class="note">The specified color space's transfer function must be
@@ -1328,12 +1483,20 @@
* specified color space returns null.</p>
*
* <p>Like all setters on ImageDecoder, this must be called inside
- * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+ * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
*/
public void setTargetColorSpace(ColorSpace colorSpace) {
mDesiredColorSpace = colorSpace;
}
+ /**
+ * Closes this resource, relinquishing any underlying resources. This method
+ * is invoked automatically on objects managed by the try-with-resources
+ * statement.
+ *
+ * <p>This is an implementation detail of {@link ImageDecoder}, and should
+ * never be called manually.</p>
+ */
@Override
public void close() {
mCloseGuard.close();
@@ -1421,7 +1584,7 @@
* Create a {@link Drawable} from a {@code Source}.
*
* @param src representing the encoded image.
- * @param listener for learning the {@link ImageInfo} and changing any
+ * @param listener for learning the {@link ImageInfo ImageInfo} and changing any
* default settings on the {@code ImageDecoder}. This will be called on
* the same thread as {@code decodeDrawable} before that method returns.
* This is required in order to change any of the default settings.
@@ -1503,8 +1666,8 @@
/**
* Create a {@link Drawable} from a {@code Source}.
*
- * <p>Since there is no {@link OnHeaderDecodedListener}, the default
- * settings will be used. In order to change any settings, call
+ * <p>Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener},
+ * the default settings will be used. In order to change any settings, call
* {@link #decodeDrawable(Source, OnHeaderDecodedListener)} instead.</p>
*
* @param src representing the encoded image.
@@ -1523,7 +1686,7 @@
* Create a {@link Bitmap} from a {@code Source}.
*
* @param src representing the encoded image.
- * @param listener for learning the {@link ImageInfo} and changing any
+ * @param listener for learning the {@link ImageInfo ImageInfo} and changing any
* default settings on the {@code ImageDecoder}. This will be called on
* the same thread as {@code decodeBitmap} before that method returns.
* This is required in order to change any of the default settings.
@@ -1616,8 +1779,8 @@
/**
* Create a {@link Bitmap} from a {@code Source}.
*
- * <p>Since there is no {@link OnHeaderDecodedListener}, the default
- * settings will be used. In order to change any settings, call
+ * <p>Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener},
+ * the default settings will be used. In order to change any settings, call
* {@link #decodeBitmap(Source, OnHeaderDecodedListener)} instead.</p>
*
* @param src representing the encoded image.
diff --git a/graphics/java/android/graphics/PostProcessor.java b/graphics/java/android/graphics/PostProcessor.java
index b1712e9..6fed39b 100644
--- a/graphics/java/android/graphics/PostProcessor.java
+++ b/graphics/java/android/graphics/PostProcessor.java
@@ -16,25 +16,26 @@
package android.graphics;
-import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.graphics.drawable.AnimatedImageDrawable;
import android.graphics.drawable.Drawable;
/**
* Helper interface for adding custom processing to an image.
*
- * <p>The image being processed may be a {@link Drawable}, {@link Bitmap} or frame
- * of an animated image produced by {@link ImageDecoder}. This is called before
- * the requested object is returned.</p>
+ * <p>The image being processed may be a {@link Drawable}, a {@link Bitmap}, or
+ * a frame of an {@link AnimatedImageDrawable} produced by {@link ImageDecoder}.
+ * This is called before the requested object is returned.</p>
*
- * <p>This custom processing also applies to image types that are otherwise
- * immutable, such as {@link Bitmap.Config#HARDWARE}.</p>
+ * <p>This custom processing can even be applied to images that will be returned
+ * as immutable objects, such as a {@link Bitmap} with {@code Config}
+ * {@link Bitmap.Config#HARDWARE} returned by {@link ImageDecoder}.</p>
*
- * <p>On an animated image, the callback will only be called once, but the drawing
- * commands will be applied to each frame, as if the {@code Canvas} had been
- * returned by {@link Picture#beginRecording}.<p>
+ * <p>On an {@link AnimatedImageDrawable}, the callback will only be called once,
+ * but the drawing commands will be applied to each frame, as if the {@link Canvas}
+ * had been returned by {@link Picture#beginRecording Picture.beginRecording}.<p>
*
- * <p>Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor}.</p>
+ * <p>Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor setPostProcessor}.</p>
*/
public interface PostProcessor {
/**
@@ -43,43 +44,44 @@
* <p>Drawing to the {@link Canvas} will behave as if the initial processing
* (e.g. decoding) already exists in the Canvas. An implementation can draw
* effects on top of this, or it can even draw behind it using
- * {@link PorterDuff.Mode#DST_OVER}. A common effect is to add transparency
- * to the corners to achieve rounded corners. That can be done with the
- * following code:</p>
+ * {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER}. A common
+ * effect is to add transparency to the corners to achieve rounded corners.
+ * That can be done with the following code:</p>
*
- * <code>
- * Path path = new Path();
- * path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
- * int width = canvas.getWidth();
- * int height = canvas.getHeight();
- * path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
- * Paint paint = new Paint();
- * paint.setAntiAlias(true);
- * paint.setColor(Color.TRANSPARENT);
- * paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- * canvas.drawPath(path, paint);
- * return PixelFormat.TRANSLUCENT;
- * </code>
+ * <pre class="prettyprint">
+ * Path path = new Path();
+ * path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ * int width = canvas.getWidth();
+ * int height = canvas.getHeight();
+ * path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+ * Paint paint = new Paint();
+ * paint.setAntiAlias(true);
+ * paint.setColor(Color.TRANSPARENT);
+ * paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ * canvas.drawPath(path, paint);
+ * return PixelFormat.TRANSLUCENT;
+ * </pre>
*
*
* @param canvas The {@link Canvas} to draw to.
* @return Opacity of the result after drawing.
- * {@link PixelFormat#UNKNOWN} means that the implementation did not
- * change whether the image has alpha. Return this unless you added
- * transparency (e.g. with the code above, in which case you should
- * return {@code PixelFormat.TRANSLUCENT}) or you forced the image to
- * be opaque (e.g. by drawing everywhere with an opaque color and
- * {@code PorterDuff.Mode.DST_OVER}, in which case you should return
- * {@code PixelFormat.OPAQUE}).
- * {@link PixelFormat#TRANSLUCENT} means that the implementation added
- * transparency. This is safe to return even if the image already had
- * transparency. This is also safe to return if the result is opaque,
- * though it may draw more slowly.
- * {@link PixelFormat#OPAQUE} means that the implementation forced the
- * image to be opaque. This is safe to return even if the image was
- * already opaque.
- * {@link PixelFormat#TRANSPARENT} (or any other integer) is not
- * allowed, and will result in throwing an
+ * {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN} means that the
+ * implementation did not change whether the image has alpha. Return
+ * this unless you added transparency (e.g. with the code above, in
+ * which case you should return
+ * {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT}) or you
+ * forced the image to be opaque (e.g. by drawing everywhere with an
+ * opaque color and {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER},
+ * in which case you should return {@link PixelFormat#OPAQUE PixelFormat.OPAQUE}).
+ * {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT} means that
+ * the implementation added transparency. This is safe to return even
+ * if the image already had transparency. This is also safe to return
+ * if the result is opaque, though it may draw more slowly.
+ * {@link PixelFormat#OPAQUE PixelFormat.OPAQUE} means that the
+ * implementation forced the image to be opaque. This is safe to return
+ * even if the image was already opaque.
+ * {@link PixelFormat#TRANSPARENT PixelFormat.TRANSPARENT} (or any other
+ * integer) is not allowed, and will result in throwing an
* {@link java.lang.IllegalArgumentException}.
*/
@PixelFormat.Opacity
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 32d4c77..3ca9295 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -151,7 +151,12 @@
mGrContext->freeGpuResources();
break;
case TrimMemoryMode::UiHidden:
- mGrContext->purgeUnlockedResources(mMaxResourceBytes - mBackgroundResourceBytes, true);
+ // Here we purge all the unlocked scratch resources and then toggle the resources cache
+ // limits between the background and max amounts. This causes the unlocked resources
+ // that have persistent data to be purged in LRU order.
+ mGrContext->purgeUnlockedResources(true);
+ mGrContext->setResourceCacheLimits(mMaxResources, mBackgroundResourceBytes);
+ mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
break;
}
}
@@ -161,7 +166,10 @@
return;
}
mGrContext->flush();
- mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
+ // Here we purge all the unlocked scratch resources (leaving those resources w/ persistent data)
+ // and then purge those w/ persistent data based on age.
+ mGrContext->purgeUnlockedResources(true);
+ mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(10));
}
sp<skiapipeline::VectorDrawableAtlas> CacheManager::acquireVectorDrawableAtlas() {
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index b1106f0..c235715 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -20,6 +20,8 @@
#include "renderthread/EglManager.h"
#include "tests/common/TestUtils.h"
+#include <SkImagePriv.h>
+
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
@@ -49,7 +51,12 @@
surfaces.push_back(surface);
}
- ASSERT_TRUE(1 < surfaces.size());
+ // create an image and pin it so that we have something with a unique key in the cache
+ sk_sp<Bitmap> bitmap =
+ Bitmap::allocateHeapBitmap(SkImageInfo::MakeA8(displayInfo.w, displayInfo.h));
+ sk_sp<SkColorFilter> filter;
+ sk_sp<SkImage> image = bitmap->makeImage(&filter);
+ ASSERT_TRUE(SkImage_pinAsTexture(image.get(), grContext));
// attempt to trim all memory while we still hold strong refs
renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
@@ -61,11 +68,14 @@
surfaces[i].reset();
}
+ // unpin the image which should add a unique purgeable key to the cache
+ SkImage_unpinAsTexture(image.get(), grContext);
+
// verify that we have enough purgeable bytes
const size_t purgeableBytes = grContext->getResourceCachePurgeableBytes();
ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() < purgeableBytes);
- // UI hidden and make sure only some got purged
+ // UI hidden and make sure only some got purged (unique should remain)
renderThread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::UiHidden);
ASSERT_TRUE(0 < grContext->getResourceCachePurgeableBytes());
ASSERT_TRUE(renderThread.cacheManager().getBackgroundCacheSize() > getCacheUsage(grContext));
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index fa3f99a..1276881 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -89,6 +89,10 @@
ProviderProperties getProviderProperties(String provider);
String getNetworkProviderPackage();
+ boolean isProviderEnabledForUser(String provider, int userId);
+ boolean setProviderEnabledForUser(String provider, boolean enabled, int userId);
+ boolean isLocationEnabledForUser(int userId);
+ void setLocationEnabledForUser(boolean enabled, int userId);
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
void removeTestProvider(String provider, String opPackageName);
void setTestProviderLocation(String provider, in Location loc, String opPackageName);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index a523958..38286a3 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1249,40 +1249,11 @@
@SystemApi
@RequiresPermission(WRITE_SECURE_SETTINGS)
public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
- final List<String> allProvidersList = getAllProviders();
- // Update all providers on device plus gps and network provider when disabling location.
- Set<String> allProvidersSet = new ArraySet<>(allProvidersList.size() + 2);
- allProvidersSet.addAll(allProvidersList);
- // When disabling location, disable gps and network provider that could have been enabled by
- // location mode api.
- if (enabled == false) {
- allProvidersSet.add(GPS_PROVIDER);
- allProvidersSet.add(NETWORK_PROVIDER);
+ try {
+ mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- if (allProvidersSet.isEmpty()) {
- return;
- }
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- final String prefix = enabled ? "+" : "-";
- StringBuilder locationProvidersAllowed = new StringBuilder();
- for (String provider : allProvidersSet) {
- checkProvider(provider);
- if (provider.equals(PASSIVE_PROVIDER)) {
- continue;
- }
- locationProvidersAllowed.append(prefix);
- locationProvidersAllowed.append(provider);
- locationProvidersAllowed.append(",");
- }
- // Remove the trailing comma
- locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
- Settings.Secure.putStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- locationProvidersAllowed.toString(),
- userHandle.getIdentifier());
}
/**
@@ -1295,22 +1266,11 @@
*/
@SystemApi
public boolean isLocationEnabledForUser(UserHandle userHandle) {
- final String allowedProviders = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
- userHandle.getIdentifier());
- if (allowedProviders == null) {
- return false;
+ try {
+ return mService.isLocationEnabledForUser(userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- final List<String> providerList = Arrays.asList(allowedProviders.split(","));
- for(String provider : getAllProviders()) {
- if (provider.equals(PASSIVE_PROVIDER)) {
- continue;
- }
- if (providerList.contains(provider)) {
- return true;
- }
- }
- return false;
}
/**
@@ -1362,9 +1322,12 @@
@SystemApi
public boolean isProviderEnabledForUser(String provider, UserHandle userHandle) {
checkProvider(provider);
- String allowedProviders = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED, userHandle.getIdentifier());
- return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
+
+ try {
+ return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -1383,16 +1346,13 @@
public boolean setProviderEnabledForUser(
String provider, boolean enabled, UserHandle userHandle) {
checkProvider(provider);
- // to ensure thread safety, we write the provider name with a '+' or '-'
- // and let the SettingsProvider handle it rather than reading and modifying
- // the list of enabled providers.
- if (enabled) {
- provider = "+" + provider;
- } else {
- provider = "-" + provider;
+
+ try {
+ return mService.setProviderEnabledForUser(
+ provider, enabled, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- return Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider, userHandle.getIdentifier());
}
/**
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 7c97ca61..e217ace 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -22,3 +22,6 @@
twickham@google.com
winsonc@google.com
+#Android Auto
+stenning@google.com
+
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml b/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml
index 6edae4b..1f6b24b 100644
--- a/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml
+++ b/packages/SystemUI/res-keyguard/drawable/ic_backspace_black_24dp.xml
@@ -21,5 +21,5 @@
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
- android:pathData="M22,3H7C6.31,3 5.77,3.35 5.41,3.88l-5.04,7.57c-0.22,0.34 -0.22,0.77 0,1.11l5.04,7.56C5.77,20.64 6.31,21 7,21h15c1.1,0 2,-0.9 2,-2V5C24,3.9 23.1,3 22,3zM18.3,16.3L18.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L14,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0h0c-0.39,-0.39 -0.39,-1.02 0,-1.41L12.59,12L9.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41l0,0c0.39,-0.39 1.02,-0.39 1.41,0L14,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0v0c0.39,0.39 0.39,1.02 0,1.41L15.41,12l2.89,2.89C18.68,15.27 18.68,15.91 18.3,16.3z"/>
+ android:pathData="M9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59L17.59,17L14,13.41L10.41,17L9,15.59zM21,6H8l-4.5,6L8,18h13V6M21,4c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H8c-0.63,0 -1.22,-0.3 -1.6,-0.8L1,12l5.4,-7.2C6.78,4.3 7.37,4 8,4H21L21,4z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_account_circle.xml b/packages/SystemUI/res/drawable/ic_account_circle.xml
deleted file mode 100644
index 3c5f01b..0000000
--- a/packages/SystemUI/res/drawable/ic_account_circle.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="48.0dp"
- android:height="48.0dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
- <path
- android:pathData="M24,0C10.8,0 0,10.8 0,24s10.8,24 24,24s24,-10.8 24,-24S37.200001,0 24,0zM24,7.2c3.96,0 7.2,3.24 7.2,7.2s-3.24,7.2 -7.2,7.2s-7.2,-3.24 -7.2,-7.2S20.040001,7.2 24,7.2zM24,41.279999c-6,0 -11.28,-3.12 -14.4,-7.68c0.12,-4.8 9.6,-7.44 14.4,-7.44s14.28,2.64 14.4,7.44C35.279999,38.16 30,41.279999 24,41.279999z"
- android:fillColor="?attr/wallpaperTextColor"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
index 8281836..6f3da75 100644
--- a/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
+++ b/packages/SystemUI/res/drawable/ic_brightness_thumb.xml
@@ -18,10 +18,12 @@
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
+
<path
- android:pathData="m18.250000,12.000000a6.250000,6.250000 0.000000,1.000000 1.000000,-12.500000 0.000000,6.250000 6.250000,0.000000 1.000000,1.000000 12.500000,0.000000z"
- android:fillColor="@android:color/transparent" />
+ android:pathData="M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z"
+ android:fillColor="?android:attr/colorPrimary" />
+
<path
- android:pathData="M20,8.69L20,5c0,-0.55 -0.45,-1 -1,-1h-3.69l-2.6,-2.6a0.996,0.996 0,0 0,-1.41 0L8.69,4L5,4c-0.55,0 -1,0.45 -1,1v3.69l-2.6,2.6a0.996,0.996 0,0 0,0 1.41L4,15.3L4,19c0,0.55 0.45,1 1,1h3.69l2.6,2.6c0.39,0.39 1.02,0.39 1.41,0l2.6,-2.6L19,20c0.55,0 1,-0.45 1,-1v-3.69l2.6,-2.6a0.996,0.996 0,0 0,0 -1.41L20,8.69zM12,18.08c-3.36,0 -6.08,-2.73 -6.08,-6.08S8.64,5.92 12,5.92s6.08,2.73 6.08,6.08 -2.72,6.08 -6.08,6.08zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z"
+ android:pathData=" M20,8.69 V4h-4.69L12,0.69L8.69,4H4v4.69L0.69,12L4,15.31V20h4.69L12,23.31L15.31,20H20v-4.69L23.31,12L20,8.69z M18,14.48V18h-3.52L12,20.48L9.52,18H6v-3.52L3.52,12L6,9.52V6h3.52L12,3.52L14.48,6H18v3.52L20.48,12L18,14.48z M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5s5,-2.24 5,-5S14.76,7 12,7z"
android:fillColor="?android:attr/colorControlActivated" />
</vector>
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
index 6f153c1..78304fd 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -41,16 +41,4 @@
</FrameLayout>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="horizontal"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 3e60794..953abc7 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -46,16 +46,4 @@
</com.android.systemui.statusbar.phone.NearestTouchFrame>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="horizontal"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 39cdff4..0e17e5b5 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -46,16 +46,4 @@
</com.android.systemui.statusbar.phone.NearestTouchFrame>
- <com.android.systemui.statusbar.policy.DeadZone
- android:id="@+id/deadzone"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_gravity="top"
- systemui:minSize="@dimen/navigation_bar_deadzone_size"
- systemui:maxSize="@dimen/navigation_bar_deadzone_size_max"
- systemui:holdTime="@integer/navigation_bar_deadzone_hold"
- systemui:decayTime="@integer/navigation_bar_deadzone_decay"
- systemui:orientation="vertical"
- />
-
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 72ff653..8c57ae8 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -57,6 +57,8 @@
android:layout_marginBottom="@dimen/qs_footer_height"
android:elevation="4dp"
android:background="@android:color/transparent"
+ android:focusable="true"
+ android:accessibilityTraversalBefore="@id/qs_carrier_text"
/>
<include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 54baa4a..5229f9b 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -41,14 +41,13 @@
android:visibility="invisible">
<ImageView
- android:id="@+id/next_alarm_icon"
+ android:id="@+id/ringer_mode_icon"
android:layout_width="@dimen/qs_header_alarm_icon_size"
android:layout_height="@dimen/qs_header_alarm_icon_size"
- android:src="@drawable/stat_sys_alarm"
android:tint="?android:attr/textColorPrimary" />
<TextView
- android:id="@+id/next_alarm_text"
+ android:id="@+id/ringer_mode_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
@@ -64,13 +63,14 @@
android:backgroundTint="?android:attr/textColorPrimary" />
<ImageView
- android:id="@+id/ringer_mode_icon"
+ android:id="@+id/next_alarm_icon"
android:layout_width="@dimen/qs_header_alarm_icon_size"
android:layout_height="@dimen/qs_header_alarm_icon_size"
+ android:src="@drawable/stat_sys_alarm"
android:tint="?android:attr/textColorPrimary" />
<TextView
- android:id="@+id/ringer_mode_text"
+ android:id="@+id/next_alarm_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 9d336e2..f0138a6 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -60,7 +60,11 @@
<include layout="@layout/heads_up_status_bar_layout" />
+ <!-- The alpha of the left side is controlled by PhoneStatusBarTransitions, and the
+ individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK and
+ DISABLE_NOTIFICATION_ICONS, respectively -->
<LinearLayout
+ android:id="@+id/status_bar_left_side"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:clipChildren="false"
@@ -76,8 +80,6 @@
android:gravity="center_vertical|start"
/>
- <!-- The alpha of this area is controlled from both PhoneStatusBarTransitions and
- PhoneStatusBar (DISABLE_NOTIFICATION_ICONS). -->
<com.android.systemui.statusbar.AlphaOptimizedFrameLayout
android:id="@+id/notification_icon_area"
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index f7e2344..63bbe62 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -28,4 +28,7 @@
<!-- We have only space for one notification on phone landscape layouts. -->
<integer name="keyguard_max_notification_count">1</integer>
+
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">1</integer>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 67dabdb..f91af03 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,4 +35,7 @@
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">290</integer>
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">0</integer>
+
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 711d550..f49d3de4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -93,6 +93,9 @@
<integer name="navigation_bar_deadzone_hold">333</integer>
<integer name="navigation_bar_deadzone_decay">333</integer>
+ <!-- orientation of the dead zone when touches have recently occurred elsewhere on screen -->
+ <integer name="navigation_bar_deadzone_orientation">0</integer>
+
<bool name="config_dead_zone_flash">false</bool>
<!-- Whether to enable dimming navigation buttons when wallpaper is not visible, should be
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4074042..da6ecc3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1335,6 +1335,11 @@
<string name="volume_ringer_status_vibrate">Vibrate</string>
<string name="volume_ringer_status_silent">Mute</string>
+ <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] -->
+ <string name="qs_status_phone_vibrate">Phone on vibrate</string>
+ <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] -->
+ <string name="qs_status_phone_muted">Phone muted</string>
+
<string name="volume_stream_muted" translatable="false">%s silent</string>
<string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
<string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 8cff56d..8e59842 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Handler;
@@ -39,6 +40,7 @@
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.GraphicBufferCompat;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -71,11 +73,13 @@
private final DeviceProvisionedController mDeviceProvisionedController
= Dependency.get(DeviceProvisionedController.class);
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
+ private final Intent mQuickStepIntent;
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private CharSequence mOnboardingText;
private @InteractionType int mInteractionFlags;
+ private boolean mIsEnabled;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -130,14 +134,23 @@
});
}
} finally {
+ Prefs.putInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, mInteractionFlags);
Binder.restoreCallingIdentity(token);
}
}
};
- private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ updateEnabledState();
+
+ // When launcher service is disabled, reset interaction flags because it is inactive
+ if (!isEnabled()) {
+ mInteractionFlags = 0;
+ Prefs.remove(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS);
+ }
+
// Reconnect immediately, instead of waiting for resume to arrive.
startConnectionToCurrentUser();
}
@@ -196,17 +209,21 @@
mConnectionBackoffAttempts = 0;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
com.android.internal.R.string.config_recentsComponentName));
+ mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
+ .setPackage(mRecentsComponentName.getPackageName());
+ mInteractionFlags = Prefs.getInt(mContext, Prefs.Key.QUICK_STEP_INTERACTION_FLAGS, 0);
// Listen for the package update changes.
if (SystemServicesProxy.getInstance(context)
.isSystemUser(mDeviceProvisionedController.getCurrentUser())) {
+ updateEnabledState();
mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
PatternMatcher.PATTERN_LITERAL);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- mContext.registerReceiver(mLauncherAddedReceiver, filter);
+ mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
}
}
@@ -222,7 +239,7 @@
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+ if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -248,6 +265,7 @@
public void addCallback(OverviewProxyListener listener) {
mConnectionCallbacks.add(listener);
listener.onConnectionChanged(mOverviewProxy != null);
+ listener.onInteractionFlagsChanged(mInteractionFlags);
}
@Override
@@ -256,7 +274,11 @@
}
public boolean shouldShowSwipeUpUI() {
- return getProxy() != null && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
+ return isEnabled() && ((mInteractionFlags & FLAG_DISABLE_SWIPE_UP) == 0);
+ }
+
+ public boolean isEnabled() {
+ return mIsEnabled;
}
public IOverviewProxy getProxy() {
@@ -292,6 +314,11 @@
}
}
+ private void updateEnabledState() {
+ mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, 0,
+ ActivityManagerWrapper.getInstance().getCurrentUserId()) != null;
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(TAG_OPS + " state:");
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 2a27147..7f7a769 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -54,7 +54,8 @@
Key.HAS_SEEN_RECENTS_ONBOARDING,
Key.SEEN_RINGER_GUIDANCE_COUNT,
Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
- Key.TOUCHED_RINGER_TOGGLE
+ Key.TOUCHED_RINGER_TOGGLE,
+ Key.QUICK_STEP_INTERACTION_FLAGS
})
public @interface Key {
@Deprecated
@@ -93,6 +94,7 @@
String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed";
String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
+ String QUICK_STEP_INTERACTION_FLAGS = "QuickStepInteractionFlags";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
index e18ac74..cdf4ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -16,6 +16,9 @@
package com.android.systemui.classifier;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
import android.view.MotionEvent;
import java.util.ArrayList;
@@ -49,13 +52,18 @@
public class AnglesClassifier extends StrokeClassifier {
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+ public static final boolean VERBOSE = SystemProperties.getBoolean("debug.falsing_log.ang",
+ Build.IS_DEBUGGABLE);
+
+ private static String TAG = "ANG";
+
public AnglesClassifier(ClassifierData classifierData) {
mClassifierData = classifierData;
}
@Override
public String getTag() {
- return "ANG";
+ return TAG;
}
@Override
@@ -170,18 +178,31 @@
public float getAnglesVariance() {
float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesVariance: (first pass) " + anglesVariance);
+ FalsingLog.i(TAG, " - mFirstLength=" + mFirstLength);
+ FalsingLog.i(TAG, " - mLength=" + mLength);
+ }
if (mFirstLength < mLength / 2f) {
anglesVariance = Math.min(anglesVariance, mFirstAngleVariance
+ getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount));
+ if (VERBOSE) FalsingLog.i(TAG, "getAnglesVariance: (second pass) " + anglesVariance);
}
return anglesVariance;
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
+ if (VERBOSE) FalsingLog.i(TAG, "getAnglesPercentage: count==0, result=1");
return 1.0f;
}
- return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
+ final float result = (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesPercentage: left=" + mLeftAngles + " right="
+ + mRightAngles + " straight=" + mStraightAngles + " count=" + mAnglesCount
+ + " result=" + result);
+ }
+ return result;
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
index 6883dd0..5f6c1b7 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -20,8 +20,6 @@
public static float evaluate(float value, int type) {
final boolean secureUnlock = type == Classifier.BOUNCER_UNLOCK;
float evaluation = 0.0f;
- if (value > 0.05) evaluation++;
- if (value > 0.10) evaluation++;
if (value > 0.20) evaluation++;
if (value > 0.40 && !secureUnlock) evaluation++;
if (value > 0.80 && !secureUnlock) evaluation++;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
index 6df72b1..66f0cf6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -16,6 +16,8 @@
package com.android.systemui.classifier;
+import android.os.Build;
+import android.os.SystemProperties;
import android.view.MotionEvent;
import java.util.ArrayList;
@@ -34,6 +36,10 @@
* should be in this interval.
*/
public class SpeedAnglesClassifier extends StrokeClassifier {
+ public static final boolean VERBOSE = SystemProperties.getBoolean("debug.falsing_log.spd_ang",
+ Build.IS_DEBUGGABLE);
+ public static final String TAG = "SPD_ANG";
+
private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
public SpeedAnglesClassifier(ClassifierData classifierData) {
@@ -42,7 +48,7 @@
@Override
public String getTag() {
- return "SPD_ANG";
+ return TAG;
}
@Override
@@ -135,14 +141,24 @@
}
public float getAnglesVariance() {
- return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+ final float v = mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesVariance: sum^2=" + mSumSquares
+ + " count=" + mCount + " result=" + v);
+ }
+ return v;
}
public float getAnglesPercentage() {
if (mAnglesCount == 0.0f) {
return 1.0f;
}
- return (mAcceleratingAngles) / mAnglesCount;
+ final float v = (mAcceleratingAngles) / mAnglesCount;
+ if (VERBOSE) {
+ FalsingLog.i(TAG, "getAnglesPercentage: angles=" + mAcceleratingAngles
+ + " count=" + mAnglesCount + " result=" + v);
+ }
+ return v;
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 5c0576d..a0bdcd0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -325,6 +325,9 @@
return;
}
bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
+ // In landscape mode, PIP window can go offset while launching IME. We want to align the
+ // the top of the PIP window with the top of the movement bounds in that case.
+ bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top));
mMotionHelper.animateToOffset(bounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index df65d1f..224c367 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -172,11 +172,11 @@
boolean ringerVisible = false;
if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
- mRingerModeTextView.setText(R.string.volume_ringer_status_vibrate);
+ mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
ringerVisible = true;
} else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
- mRingerModeTextView.setText(R.string.volume_ringer_status_silent);
+ mRingerModeTextView.setText(R.string.qs_status_phone_muted);
ringerVisible = true;
}
mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index eb95866..20e3cee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -44,4 +44,9 @@
public TextView getAppLabel() {
return mSecondLine;
}
+
+ @Override
+ protected boolean animationsEnabled() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 0f83078..e7e756f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -16,6 +16,8 @@
import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -127,7 +129,6 @@
}
protected void setIcon(ImageView iv, QSTile.State state) {
- updateIcon(iv, state);
if (state.disabledByPolicy) {
iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
} else {
@@ -137,7 +138,7 @@
int color = getColor(state.state);
mState = state.state;
if (iv.isShown() && mTint != 0) {
- animateGrayScale(mTint, color, iv);
+ animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state));
mTint = color;
} else {
if (iv instanceof AlphaControlledSlashImageView) {
@@ -147,7 +148,10 @@
setTint(iv, color);
}
mTint = color;
+ updateIcon(iv, state);
}
+ } else {
+ updateIcon(iv, state);
}
}
@@ -155,12 +159,13 @@
return getColorForState(getContext(), state);
}
- public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+ private void animateGrayScale(int fromColor, int toColor, ImageView iv,
+ final Runnable endRunnable) {
if (iv instanceof AlphaControlledSlashImageView) {
((AlphaControlledSlashImageView)iv)
.setFinalImageTintList(ColorStateList.valueOf(toColor));
}
- if (ValueAnimator.areAnimatorsEnabled()) {
+ if (mAnimationEnabled && ValueAnimator.areAnimatorsEnabled()) {
final float fromAlpha = Color.alpha(fromColor);
final float toAlpha = Color.alpha(toColor);
final float fromChannel = Color.red(fromColor);
@@ -175,10 +180,16 @@
setTint(iv, Color.argb(alpha, channel, channel, channel));
});
-
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.run();
+ }
+ });
anim.start();
} else {
setTint(iv, toColor);
+ endRunnable.run();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 09d928f..cc60f87 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -179,7 +179,7 @@
protected void handleStateChanged(QSTile.State state) {
int circleColor = getCircleColor(state.state);
if (circleColor != mCircleColor) {
- if (mBg.isShown()) {
+ if (mBg.isShown() && animationsEnabled()) {
ValueAnimator animator = ValueAnimator.ofArgb(mCircleColor, circleColor)
.setDuration(QS_ANIM_LENGTH);
animator.addUpdateListener(animation -> mBg.setImageTintList(ColorStateList.valueOf(
@@ -205,6 +205,10 @@
}
}
+ protected boolean animationsEnabled() {
+ return true;
+ }
+
private int getCircleColor(int state) {
switch (state) {
case Tile.STATE_ACTIVE:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 8a1e4da..d8f7b71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -41,6 +41,7 @@
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
@@ -60,6 +61,7 @@
protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
private final ActivityStarter mActivityStarter;
+ private boolean mExpectDisabled;
public WifiTile(QSHost host) {
super(host);
@@ -120,6 +122,15 @@
// Immediately enter transient state when turning on wifi.
refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
mController.setWifiEnabled(!wifiEnabled);
+ mExpectDisabled = wifiEnabled;
+ if (mExpectDisabled) {
+ mHandler.postDelayed(() -> {
+ if (mExpectDisabled) {
+ mExpectDisabled = false;
+ refreshState();
+ }
+ }, QSIconViewImpl.QS_ANIM_LENGTH);
+ }
}
@Override
@@ -143,11 +154,13 @@
@Override
protected void handleUpdateState(SignalState state, Object arg) {
if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
- final CallbackInfo cb;
- if (arg != null && arg instanceof CallbackInfo) {
- cb = (CallbackInfo) arg;
- } else {
- cb = mSignalCallback.mInfo;
+ final CallbackInfo cb = mSignalCallback.mInfo;
+ if (mExpectDisabled) {
+ if (cb.enabled) {
+ return; // Ignore updates until disabled event occurs.
+ } else {
+ mExpectDisabled = false;
+ }
}
boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null);
@@ -288,7 +301,7 @@
if (isShowingDetail()) {
mDetailAdapter.updateItems();
}
- refreshState(mInfo);
+ refreshState();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 19da3db..6fcb1c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -126,7 +126,7 @@
@Override
public void onTaskStackChangedBackground() {
// Skip background preloading recents in SystemUI if the overview services is bound
- if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ if (Dependency.get(OverviewProxyService.class).isEnabled()) {
return;
}
@@ -300,7 +300,7 @@
public void onBootCompleted() {
// Skip preloading tasks if we are already bound to the service
- if (Dependency.get(OverviewProxyService.class).getProxy() != null) {
+ if (Dependency.get(OverviewProxyService.class).isEnabled()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3530e0b..3fb1137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -182,27 +182,6 @@
// By default, the BatteryMeterView should not be visible. It will be toggled
// when a device has connected by bluetooth.
mBatteryMeterView.setVisibility(View.GONE);
-
- ViewStub stub = fragment.getView().findViewById(R.id.connected_device_signals_stub);
- View signalsView = stub.inflate();
-
- // When a ViewStub if inflated, it does not respect the margins on the
- // inflated view.
- // As a result, manually add the ending margin.
- ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
- mContext.getResources().getDimensionPixelOffset(
- R.dimen.status_bar_connected_device_signal_margin_end));
-
- if (mConnectedDeviceSignalController != null) {
- mConnectedDeviceSignalController.stopListening();
- }
- mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
- signalsView);
- mConnectedDeviceSignalController.startListening();
-
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
- }
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 75b31c5..9fcb090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar.phone;
+import static android.app.StatusBarManager.DISABLE_CLOCK;
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
@@ -96,6 +97,7 @@
mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area);
mClockView = mStatusBar.findViewById(R.id.clock);
showSystemIconArea(false);
+ showClock(false);
initEmergencyCryptkeeperText();
initOperatorName();
}
@@ -163,6 +165,13 @@
showNotificationIconArea(animate);
}
}
+ if ((diff1 & DISABLE_CLOCK) != 0) {
+ if ((state1 & DISABLE_CLOCK) != 0) {
+ hideClock(animate);
+ } else {
+ showClock(animate);
+ }
+ }
}
protected int adjustDisableFlags(int state) {
@@ -171,6 +180,7 @@
&& shouldHideNotificationIcons()) {
state |= DISABLE_NOTIFICATION_ICONS;
state |= DISABLE_SYSTEM_INFO;
+ state |= DISABLE_CLOCK;
}
if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
if (mNetworkController.hasEmergencyCryptKeeperText()) {
@@ -195,11 +205,17 @@
public void hideSystemIconArea(boolean animate) {
animateHide(mSystemIconArea, animate);
- animateHide(mClockView, animate);
}
public void showSystemIconArea(boolean animate) {
animateShow(mSystemIconArea, animate);
+ }
+
+ public void hideClock(boolean animate) {
+ animateHide(mClockView, animate);
+ }
+
+ public void showClock(boolean animate) {
animateShow(mClockView, animate);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f216695..4c4eb60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -124,7 +124,7 @@
private TintedKeyButtonDrawable mRotateSuggestionIcon;
private GestureHelper mGestureHelper;
- private DeadZone mDeadZone;
+ private final DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
private final OverviewProxyService mOverviewProxyService;
@@ -263,6 +263,7 @@
new ButtonDispatcher(R.id.accessibility_button));
mButtonDispatchers.put(R.id.rotate_suggestion,
new ButtonDispatcher(R.id.rotate_suggestion));
+ mDeadZone = new DeadZone(this);
}
public BarTransitions getBarTransitions() {
@@ -297,6 +298,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
+ if (mDeadZone.onTouchEvent(event)) {
+ // Consumed the touch event
+ return true;
+ }
switch (event.getActionMasked()) {
case ACTION_DOWN:
int x = (int) event.getX();
@@ -319,6 +324,10 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (mDeadZone.onTouchEvent(event)) {
+ // Consumed the touch event
+ return true;
+ }
if (mGestureHelper.onTouchEvent(event)) {
return true;
}
@@ -389,7 +398,7 @@
public boolean isQuickScrubEnabled() {
return SystemProperties.getBoolean("persist.quickstep.scrub.enabled", true)
- && mOverviewProxyService.getProxy() != null && isOverviewEnabled()
+ && mOverviewProxyService.isEnabled() && isOverviewEnabled()
&& ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
}
@@ -587,7 +596,7 @@
// recents buttons when disconnected from launcher service in screen pinning mode,
// as they are used for exiting.
final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
- if (mOverviewProxyService.getProxy() != null) {
+ if (mOverviewProxyService.isEnabled()) {
// Use interaction flags to show/hide navigation buttons but will be shown if required
// to exit screen pinning.
final int flags = mOverviewProxyService.getInteractionFlags();
@@ -818,6 +827,7 @@
@Override
protected void onDraw(Canvas canvas) {
mGestureHelper.onDraw(canvas);
+ mDeadZone.onDraw(canvas);
super.onDraw(canvas);
}
@@ -889,10 +899,8 @@
public void reorient() {
updateCurrentView();
- mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone);
-
((NavigationBarFrame) getRootView()).setDeadZone(mDeadZone);
- mDeadZone.setDisplayRotation(mCurrentRotation);
+ mDeadZone.onConfigurationChanged(mCurrentRotation);
// force the low profile & disabled states into compliance
mBarTransitions.init();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 04cb620..304a499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -488,7 +488,7 @@
mUpdateFlingVelocity = vel;
}
} else if (mPanelClosedOnDown && !mHeadsUpManager.hasPinnedHeadsUp() && !mTracking
- && !mStatusBar.isBouncerShowing()) {
+ && !mStatusBar.isBouncerShowing() && !mStatusBar.isKeyguardFadingAway()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
// Lets show the user that he can actually expand the panel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index 12bdfc6..a7d5aca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -43,10 +43,9 @@
}
public void init() {
- mLeftSide = mView.findViewById(R.id.notification_icon_area);
+ mLeftSide = mView.findViewById(R.id.status_bar_left_side);
mStatusIcons = mView.findViewById(R.id.statusIcons);
mBattery = mView.findViewById(R.id.battery);
- mClock = mView.findViewById(R.id.clock);
applyModeBackground(-1, getMode(), false /*animate*/);
applyMode(getMode(), false /*animate*/);
}
@@ -89,8 +88,7 @@
anims.playTogether(
animateTransitionTo(mLeftSide, newAlpha),
animateTransitionTo(mStatusIcons, newAlpha),
- animateTransitionTo(mBattery, newAlphaBC),
- animateTransitionTo(mClock, newAlphaBC)
+ animateTransitionTo(mBattery, newAlphaBC)
);
if (isLightsOut(mode)) {
anims.setDuration(LIGHTS_OUT_DURATION);
@@ -101,7 +99,6 @@
mLeftSide.setAlpha(newAlpha);
mStatusIcons.setAlpha(newAlpha);
mBattery.setAlpha(newAlphaBC);
- mClock.setAlpha(newAlphaBC);
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index a51cd93..af77804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -168,8 +168,8 @@
}
private boolean handleTouchEvent(MotionEvent event) {
- if (!mNavigationBarView.isQuickScrubEnabled()
- && !mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+ if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
+ && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */);
return false;
}
@@ -199,7 +199,7 @@
break;
}
case MotionEvent.ACTION_MOVE: {
- if (mQuickStepStarted || !mAllowGestureDetection){
+ if (mQuickStepStarted || !mAllowGestureDetection || mHomeButtonView == null){
break;
}
int x = (int) event.getX();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 750d2a5..f7a97be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1425,11 +1425,15 @@
}
public void addQsTile(ComponentName tile) {
- mQSPanel.getHost().addTile(tile);
+ if (mQSPanel.getHost() != null) {
+ mQSPanel.getHost().addTile(tile);
+ }
}
public void remQsTile(ComponentName tile) {
- mQSPanel.getHost().removeTile(tile);
+ if (mQSPanel.getHost() != null) {
+ mQSPanel.getHost().removeTile(tile);
+ }
}
public void clickTile(ComponentName tile) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 06040e2..4a11754 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -17,18 +17,16 @@
package com.android.systemui.statusbar.policy;
import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
+import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.SystemClock;
-import android.util.AttributeSet;
import android.util.Slog;
import android.view.MotionEvent;
import android.view.Surface;
-import android.view.View;
import com.android.systemui.R;
import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.StatusBar;
/**
@@ -38,7 +36,7 @@
* outside the navigation bar (since this is when accidental taps are more likely), then contracts
* back over time (since a later tap might be intended for the top of the bar).
*/
-public class DeadZone extends View {
+public class DeadZone {
public static final String TAG = "DeadZone";
public static final boolean DEBUG = false;
@@ -47,6 +45,7 @@
private static final boolean CHATTY = true; // print to logcat when we eat a click
private final StatusBar mStatusBar;
+ private final NavigationBarView mNavigationBarView;
private boolean mShouldFlash;
private float mFlashFrac = 0f;
@@ -67,31 +66,11 @@
}
};
- public DeadZone(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DeadZone(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DeadZone,
- defStyle, 0);
-
- mHold = a.getInteger(R.styleable.DeadZone_holdTime, 0);
- mDecay = a.getInteger(R.styleable.DeadZone_decayTime, 0);
-
- mSizeMin = a.getDimensionPixelSize(R.styleable.DeadZone_minSize, 0);
- mSizeMax = a.getDimensionPixelSize(R.styleable.DeadZone_maxSize, 0);
-
- int index = a.getInt(R.styleable.DeadZone_orientation, -1);
- mVertical = (index == VERTICAL);
-
- if (DEBUG)
- Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
- + (mVertical ? " vertical" : " horizontal"));
-
- setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
- mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
+ public DeadZone(NavigationBarView view) {
+ mNavigationBarView = view;
+ mStatusBar = SysUiServiceProvider.getComponent(mNavigationBarView.getContext(),
+ StatusBar.class);
+ onConfigurationChanged(HORIZONTAL);
}
static float lerp(float a, float b, float f) {
@@ -112,11 +91,29 @@
public void setFlashOnTouchCapture(boolean dbg) {
mShouldFlash = dbg;
mFlashFrac = 0f;
- postInvalidate();
+ mNavigationBarView.postInvalidate();
+ }
+
+ public void onConfigurationChanged(int rotation) {
+ mDisplayRotation = rotation;
+
+ final Resources res = mNavigationBarView.getResources();
+ mHold = res.getInteger(R.integer.navigation_bar_deadzone_hold);
+ mDecay = res.getInteger(R.integer.navigation_bar_deadzone_decay);
+
+ mSizeMin = res.getDimensionPixelSize(R.dimen.navigation_bar_deadzone_size);
+ mSizeMax = res.getDimensionPixelSize(R.dimen.navigation_bar_deadzone_size_max);
+ int index = res.getInteger(R.integer.navigation_bar_deadzone_orientation);
+ mVertical = (index == VERTICAL);
+
+ if (DEBUG) {
+ Slog.v(TAG, this + " size=[" + mSizeMin + "-" + mSizeMax + "] hold=" + mHold
+ + (mVertical ? " vertical" : " horizontal"));
+ }
+ setFlashOnTouchCapture(res.getBoolean(R.bool.config_dead_zone_flash));
}
// I made you a touch event...
- @Override
public boolean onTouchEvent(MotionEvent event) {
if (DEBUG) {
Slog.v(TAG, this + " onTouch: " + MotionEvent.actionToString(event.getAction()));
@@ -143,7 +140,7 @@
final boolean consumeEvent;
if (mVertical) {
if (mDisplayRotation == Surface.ROTATION_270) {
- consumeEvent = event.getX() > getWidth() - size;
+ consumeEvent = event.getX() > mNavigationBarView.getWidth() - size;
} else {
consumeEvent = event.getX() < size;
}
@@ -155,8 +152,8 @@
Slog.v(TAG, "consuming errant click: (" + event.getX() + "," + event.getY() + ")");
}
if (mShouldFlash) {
- post(mDebugFlash);
- postInvalidate();
+ mNavigationBarView.post(mDebugFlash);
+ mNavigationBarView.postInvalidate();
}
return true; // ...but I eated it
}
@@ -168,19 +165,18 @@
mLastPokeTime = event.getEventTime();
if (DEBUG)
Slog.v(TAG, "poked! size=" + getSize(mLastPokeTime));
- if (mShouldFlash) postInvalidate();
+ if (mShouldFlash) mNavigationBarView.postInvalidate();
}
public void setFlash(float f) {
mFlashFrac = f;
- postInvalidate();
+ mNavigationBarView.postInvalidate();
}
public float getFlash() {
return mFlashFrac;
}
- @Override
public void onDraw(Canvas can) {
if (!mShouldFlash || mFlashFrac <= 0f) {
return;
@@ -202,10 +198,6 @@
if (DEBUG && size > mSizeMin)
// crazy aggressive redrawing here, for debugging only
- postInvalidateDelayed(100);
- }
-
- public void setDisplayRotation(int rotation) {
- mDisplayRotation = rotation;
+ mNavigationBarView.postInvalidateDelayed(100);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 5d7e938..44c2757 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -200,7 +200,7 @@
}
public boolean onTouchEvent(MotionEvent ev) {
- final boolean isProxyConnected = mOverviewProxyService.getProxy() != null;
+ final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
final int action = ev.getAction();
int x, y;
if (action == MotionEvent.ACTION_DOWN) {
@@ -226,7 +226,7 @@
// Provide the same haptic feedback that the system offers for virtual keys.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
- if (!isProxyConnected) {
+ if (!showSwipeUI) {
playSoundEffect(SoundEffectConstants.CLICK);
}
removeCallbacks(mCheckLongPress);
@@ -255,7 +255,7 @@
final boolean doIt = isPressed() && !mLongClicked;
setPressed(false);
final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
- if (isProxyConnected) {
+ if (showSwipeUI) {
if (doIt) {
if (doHapticFeedback) {
mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 2edcd01..9e8fa22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -89,15 +89,11 @@
assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
- assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.clock)
- .getVisibility());
fragment.disable(0, 0, false);
assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area)
.getVisibility());
- assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock)
- .getVisibility());
}
@Test
@@ -115,4 +111,20 @@
Mockito.verify(mNotificationAreaInner, atLeast(1)).setVisibility(eq(View.VISIBLE));
}
+
+ @Test
+ public void testDisableClock() throws Exception {
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment;
+ fragment.initNotificationIconArea(mMockNotificiationAreaController);
+ fragment.disable(StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+
+ fragment.disable(0, 0, false);
+
+ assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.clock).getVisibility());
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c6878d7..c66c7b0 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5562,6 +5562,16 @@
// OS: P
PREVIOUSLY_CONNECTED_DEVICES = 1370;
+ // ACTION: A Settings Slice is requested
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_SETTINGS_SLICE_REQUESTED = 1371;
+
+ // ACTION: A Settings Slice is updated with new value
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_SETTINGS_SLICE_CHANGED = 1372;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 861ae83..a1ef1ed 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -910,7 +910,12 @@
private Tethering makeTethering() {
// TODO: Move other elements into @Overridden getters.
- final TetheringDependencies deps = new TetheringDependencies();
+ final TetheringDependencies deps = new TetheringDependencies() {
+ @Override
+ public boolean isTetheringSupported() {
+ return ConnectivityService.this.isTetheringSupported();
+ }
+ };
return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index bde6bd8..cd90e3f 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -24,6 +24,8 @@
import static android.system.OsConstants.SOCK_DGRAM;
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.IIpSecService;
@@ -42,6 +44,7 @@
import android.net.TrafficStats;
import android.net.util.NetdService;
import android.os.Binder;
+import android.os.DeadSystemException;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -974,6 +977,13 @@
return service;
}
+ @NonNull
+ private AppOpsManager getAppOpsManager() {
+ AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps");
+ return appOps;
+ }
+
/** @hide */
@VisibleForTesting
public IpSecService(Context context, IpSecServiceConfiguration config) {
@@ -1240,7 +1250,9 @@
*/
@Override
public synchronized IpSecTunnelInterfaceResponse createTunnelInterface(
- String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) {
+ String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
+ String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
checkNotNull(binder, "Null Binder passed to createTunnelInterface");
checkNotNull(underlyingNetwork, "No underlying network was specified");
checkInetAddress(localAddr);
@@ -1320,8 +1332,8 @@
*/
@Override
public synchronized void addAddressToTunnelInterface(
- int tunnelResourceId, LinkAddress localAddr) {
- enforceNetworkStackPermission();
+ int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
@@ -1352,10 +1364,10 @@
*/
@Override
public synchronized void removeAddressFromTunnelInterface(
- int tunnelResourceId, LinkAddress localAddr) {
- enforceNetworkStackPermission();
- UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+ int tunnelResourceId, LinkAddress localAddr, String callingPackage) {
+ enforceTunnelPermissions(callingPackage);
+ UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
// Get tunnelInterface record; if no such interface is found, will throw
// IllegalArgumentException
TunnelInterfaceRecord tunnelInterfaceInfo =
@@ -1383,7 +1395,9 @@
* server
*/
@Override
- public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException {
+ public synchronized void deleteTunnelInterface(
+ int resourceId, String callingPackage) throws RemoteException {
+ enforceTunnelPermissions(callingPackage);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
releaseResource(userRecord.mTunnelInterfaceRecords, resourceId);
}
@@ -1469,7 +1483,6 @@
case IpSecTransform.MODE_TRANSPORT:
break;
case IpSecTransform.MODE_TUNNEL:
- enforceNetworkStackPermission();
break;
default:
throw new IllegalArgumentException(
@@ -1477,9 +1490,20 @@
}
}
- private void enforceNetworkStackPermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
- "IpSecService");
+ private void enforceTunnelPermissions(String callingPackage) {
+ checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
+ switch (getAppOpsManager().noteOp(
+ AppOpsManager.OP_MANAGE_IPSEC_TUNNELS,
+ Binder.getCallingUid(), callingPackage)) {
+ case AppOpsManager.MODE_DEFAULT:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService");
+ break;
+ case AppOpsManager.MODE_ALLOWED:
+ return;
+ default:
+ throw new SecurityException("Request to ignore AppOps for non-legacy API");
+ }
}
private void createOrUpdateTransform(
@@ -1535,8 +1559,12 @@
* result in all of those sockets becoming unable to send or receive data.
*/
@Override
- public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
- throws RemoteException {
+ public synchronized IpSecTransformResponse createTransform(
+ IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
+ checkNotNull(c);
+ if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
+ enforceTunnelPermissions(callingPackage);
+ }
checkIpSecConfig(c);
checkNotNull(binder, "Null Binder passed to createTransform");
final int resourceId = mNextResourceId++;
@@ -1657,8 +1685,9 @@
*/
@Override
public synchronized void applyTunnelModeTransform(
- int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
- enforceNetworkStackPermission();
+ int tunnelResourceId, int direction,
+ int transformResourceId, String callingPackage) throws RemoteException {
+ enforceTunnelPermissions(callingPackage);
checkDirection(direction);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 26b83f5..fb5fba0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1344,13 +1344,7 @@
* @param provider the name of the location provider
*/
private boolean isAllowedByCurrentUserSettingsLocked(String provider) {
- if (mEnabledProviders.contains(provider)) {
- return true;
- }
- if (mDisabledProviders.contains(provider)) {
- return false;
- }
- return isLocationProviderEnabledForUser(provider, mCurrentUserId);
+ return isAllowedByUserSettingsLockedForUser(provider, mCurrentUserId);
}
/**
@@ -1359,13 +1353,33 @@
* processes belonging to background users.
*
* @param provider the name of the location provider
- * @param uid the requestor's UID
+ * @param userId the user id to query
*/
- private boolean isAllowedByUserSettingsLocked(String provider, int uid) {
+ private boolean isAllowedByUserSettingsLockedForUser(String provider, int userId) {
+ if (mEnabledProviders.contains(provider)) {
+ return true;
+ }
+ if (mDisabledProviders.contains(provider)) {
+ return false;
+ }
+ return isLocationProviderEnabledForUser(provider, userId);
+ }
+
+
+ /**
+ * Returns "true" if access to the specified location provider is allowed by the specified
+ * user's settings. Access to all location providers is forbidden to non-location-provider
+ * processes belonging to background users.
+ *
+ * @param provider the name of the location provider
+ * @param uid the requestor's UID
+ * @param userId the user id to query
+ */
+ private boolean isAllowedByUserSettingsLocked(String provider, int uid, int userId) {
if (!isCurrentProfile(UserHandle.getUserId(uid)) && !isUidALocationProvider(uid)) {
return false;
}
- return isAllowedByCurrentUserSettingsLocked(provider);
+ return isAllowedByUserSettingsLockedForUser(provider, userId);
}
/**
@@ -1572,7 +1586,8 @@
continue;
}
if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
- if (enabledOnly && !isAllowedByUserSettingsLocked(name, uid)) {
+ if (enabledOnly
+ && !isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) {
continue;
}
if (criteria != null && !LocationProvider.propertiesMeetCriteria(
@@ -2098,7 +2113,7 @@
oldRecord.disposeLocked(false);
}
- boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid);
+ boolean isProviderEnabled = isAllowedByUserSettingsLocked(name, uid, mCurrentUserId);
if (isProviderEnabled) {
applyRequirementsLocked(name);
} else {
@@ -2219,7 +2234,7 @@
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) return null;
- if (!isAllowedByUserSettingsLocked(name, uid)) return null;
+ if (!isAllowedByUserSettingsLocked(name, uid, mCurrentUserId)) return null;
Location location;
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
@@ -2540,6 +2555,173 @@
}
/**
+ * Returns the current location enabled/disabled status for a user
+ *
+ * @param userId the id of the user
+ * @return true if location is enabled
+ */
+ @Override
+ public boolean isLocationEnabledForUser(int userId) {
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final String allowedProviders = Settings.Secure.getStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ userId);
+ if (allowedProviders == null) {
+ return false;
+ }
+ final List<String> providerList = Arrays.asList(allowedProviders.split(","));
+ for(String provider : mRealProviders.keySet()) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ if (providerList.contains(provider)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Enable or disable location for a user
+ *
+ * @param enabled true to enable location, false to disable location
+ * @param userId the id of the user
+ */
+ @Override
+ public void setLocationEnabledForUser(boolean enabled, int userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "Requires WRITE_SECURE_SETTINGS permission");
+
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final Set<String> allRealProviders = mRealProviders.keySet();
+ // Update all providers on device plus gps and network provider when disabling
+ // location
+ Set<String> allProvidersSet = new ArraySet<>(allRealProviders.size() + 2);
+ allProvidersSet.addAll(allRealProviders);
+ // When disabling location, disable gps and network provider that could have been
+ // enabled by location mode api.
+ if (enabled == false) {
+ allProvidersSet.add(LocationManager.GPS_PROVIDER);
+ allProvidersSet.add(LocationManager.NETWORK_PROVIDER);
+ }
+ if (allProvidersSet.isEmpty()) {
+ return;
+ }
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ final String prefix = enabled ? "+" : "-";
+ StringBuilder locationProvidersAllowed = new StringBuilder();
+ for (String provider : allProvidersSet) {
+ if (provider.equals(LocationManager.PASSIVE_PROVIDER)
+ || provider.equals(LocationManager.FUSED_PROVIDER)) {
+ continue;
+ }
+ locationProvidersAllowed.append(prefix);
+ locationProvidersAllowed.append(provider);
+ locationProvidersAllowed.append(",");
+ }
+ // Remove the trailing comma
+ locationProvidersAllowed.setLength(locationProvidersAllowed.length() - 1);
+ Settings.Secure.putStringForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ locationProvidersAllowed.toString(),
+ userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Returns the current enabled/disabled status of a location provider and user
+ *
+ * @param provider name of the provider
+ * @param userId the id of the user
+ * @return true if the provider exists and is enabled
+ */
+ @Override
+ public boolean isProviderEnabledForUser(String provider, int userId) {
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // so we discourage its use
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+
+ int uid = Binder.getCallingUid();
+ synchronized (mLock) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ return p != null
+ && isAllowedByUserSettingsLocked(provider, uid, userId);
+ }
+ }
+
+ /**
+ * Enable or disable a single location provider.
+ *
+ * @param provider name of the provider
+ * @param enabled true to enable the provider. False to disable the provider
+ * @param userId the id of the user to set
+ * @return true if the value was set, false on errors
+ */
+ @Override
+ public boolean setProviderEnabledForUser(String provider, boolean enabled, int userId) {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS,
+ "Requires WRITE_SECURE_SETTINGS permission");
+
+ // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
+ checkInteractAcrossUsersPermission(userId);
+
+ // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // so we discourage its use
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ // No such provider exists
+ if (!mProvidersByName.containsKey(provider)) return false;
+
+ // If it is a test provider, do not write to Settings.Secure
+ if (mMockProviders.containsKey(provider)) {
+ setTestProviderEnabled(provider, enabled);
+ return true;
+ }
+
+ // to ensure thread safety, we write the provider name with a '+' or '-'
+ // and let the SettingsProvider handle it rather than reading and modifying
+ // the list of enabled providers.
+ String providerChange = (enabled ? "+" : "-") + provider;
+ return Settings.Secure.putStringForUser(
+ mContext.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+ providerChange, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Read location provider status from Settings.Secure
*
* @param provider the location provider to query
@@ -2560,6 +2742,23 @@
}
/**
+ * Method for checking INTERACT_ACROSS_USERS permission if specified user id is not the same as
+ * current user id
+ *
+ * @param userId the user id to get or set value
+ */
+ private void checkInteractAcrossUsersPermission(int userId) {
+ int uid = Binder.getCallingUid();
+ if (UserHandle.getUserId(uid) != userId) {
+ if (ActivityManager.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, uid, -1, true)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+ }
+ }
+ }
+
+ /**
* Returns "true" if the UID belongs to a bound location provider.
*
* @param uid the uid
@@ -3076,7 +3275,11 @@
if (!canCallerAccessMockLocation(opPackageName)) {
return;
}
+ setTestProviderEnabled(provider, enabled);
+ }
+ /** Enable or disable a test location provider. */
+ private void setTestProviderEnabled(String provider, boolean enabled) {
synchronized (mLock) {
MockProvider mockProvider = mMockProviders.get(provider);
if (mockProvider == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e3e844a..f97c6d6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15224,7 +15224,17 @@
Binder.getCallingUid(),
eventType,
processName,
- Binder.getCallingPid());
+ Binder.getCallingPid(),
+ (r != null && r.info != null) ? r.info.packageName : "",
+ (r != null && r.info != null) ? (r.info.isInstantApp()
+ ? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
+ : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
+ : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+ r != null ? (r.isInterestingToUserLocked()
+ ? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
+ : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
+ : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
+ );
addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7ee20fa2..d5bb7ed 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -1041,7 +1041,15 @@
}
StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,
- activity == null ? "unknown": activity.shortComponentName, annotation);
+ activity == null ? "unknown": activity.shortComponentName, annotation,
+ (app.info != null) ? (app.info.isInstantApp()
+ ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
+ : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+ app != null ? (app.isInterestingToUserLocked()
+ ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
+ : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND)
+ : StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN);
mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 4eb1930..53a9544 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -20,9 +20,13 @@
import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
import android.app.usage.NetworkStatsManager;
import android.app.usage.NetworkStatsManager.UsageCallback;
@@ -31,24 +35,34 @@
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkIdentity;
+import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
+import android.os.BestClock;
import android.os.Handler;
+import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.util.DebugUtils;
+import android.util.Pair;
import android.util.Slog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsManagerInternal;
+import java.time.Clock;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
/**
* Manages multipath data budgets.
@@ -69,6 +83,8 @@
private final Context mContext;
private final Handler mHandler;
+ private final Clock mClock;
+ private final Dependencies mDeps;
private ConnectivityManager mCM;
private NetworkPolicyManager mNPM;
@@ -80,9 +96,28 @@
// STOPSHIP: replace this with a configurable mechanism.
private static final long DEFAULT_DAILY_MULTIPATH_QUOTA = 2_500_000;
+ /**
+ * Divider to calculate opportunistic quota from user-set data limit or warning: 5% of user-set
+ * limit.
+ */
+ private static final int OPQUOTA_USER_SETTING_DIVIDER = 20;
+
+ public static class Dependencies {
+ public Clock getClock() {
+ return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+ Clock.systemUTC());
+ }
+ }
+
public MultipathPolicyTracker(Context ctx, Handler handler) {
+ this(ctx, handler, new Dependencies());
+ }
+
+ public MultipathPolicyTracker(Context ctx, Handler handler, Dependencies deps) {
mContext = ctx;
mHandler = handler;
+ mClock = deps.getClock();
+ mDeps = deps;
// Because we are initialized by the ConnectivityService constructor, we can't touch any
// connectivity APIs. Service initialization is done in start().
}
@@ -128,9 +163,11 @@
private long mMultipathBudget;
private final NetworkTemplate mNetworkTemplate;
private final UsageCallback mUsageCallback;
+ private NetworkCapabilities mNetworkCapabilities;
public MultipathTracker(Network network, NetworkCapabilities nc) {
this.network = network;
+ this.mNetworkCapabilities = new NetworkCapabilities(nc);
try {
subId = Integer.parseInt(
((StringNetworkSpecifier) nc.getNetworkSpecifier()).toString());
@@ -167,32 +204,97 @@
updateMultipathBudget();
}
- private long getDailyNonDefaultDataUsage() {
- Calendar start = Calendar.getInstance();
- Calendar end = (Calendar) start.clone();
- start.set(Calendar.HOUR_OF_DAY, 0);
- start.set(Calendar.MINUTE, 0);
- start.set(Calendar.SECOND, 0);
- start.set(Calendar.MILLISECOND, 0);
+ public void setNetworkCapabilities(NetworkCapabilities nc) {
+ mNetworkCapabilities = new NetworkCapabilities(nc);
+ }
+ // TODO: calculate with proper timezone information
+ private long getDailyNonDefaultDataUsage() {
+ final ZonedDateTime end =
+ ZonedDateTime.ofInstant(mClock.instant(), ZoneId.systemDefault());
+ final ZonedDateTime start = end.truncatedTo(ChronoUnit.DAYS);
+
+ final long bytes = getNetworkTotalBytes(
+ start.toInstant().toEpochMilli(),
+ end.toInstant().toEpochMilli());
+ if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+ return bytes;
+ }
+
+ private long getNetworkTotalBytes(long start, long end) {
try {
- final long bytes = LocalServices.getService(NetworkStatsManagerInternal.class)
- .getNetworkTotalBytes(mNetworkTemplate, start.getTimeInMillis(),
- end.getTimeInMillis());
- if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
- return bytes;
+ return LocalServices.getService(NetworkStatsManagerInternal.class)
+ .getNetworkTotalBytes(mNetworkTemplate, start, end);
} catch (RuntimeException e) {
Slog.w(TAG, "Failed to get data usage: " + e);
return -1;
}
}
+ private NetworkIdentity getTemplateMatchingNetworkIdentity(NetworkCapabilities nc) {
+ return new NetworkIdentity(
+ ConnectivityManager.TYPE_MOBILE,
+ 0 /* subType, unused for template matching */,
+ subscriberId,
+ null /* networkId, unused for matching mobile networks */,
+ !nc.hasCapability(NET_CAPABILITY_NOT_ROAMING),
+ !nc.hasCapability(NET_CAPABILITY_NOT_METERED),
+ false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */);
+ }
+
+ private long getRemainingDailyBudget(long limitBytes,
+ Pair<ZonedDateTime, ZonedDateTime> cycle) {
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
+ final long totalBytes = getNetworkTotalBytes(start, end);
+ final long remainingBytes = totalBytes == -1 ? 0 : Math.max(0, limitBytes - totalBytes);
+ // 1 + ((end - now - 1) / millisInDay with integers is equivalent to:
+ // ceil((double)(end - now) / millisInDay)
+ final long remainingDays =
+ 1 + ((end - mClock.millis() - 1) / TimeUnit.DAYS.toMillis(1));
+
+ return remainingBytes / Math.max(1, remainingDays);
+ }
+
+ private long getUserPolicyOpportunisticQuotaBytes() {
+ // Keep the most restrictive applicable policy
+ long minQuota = Long.MAX_VALUE;
+ final NetworkIdentity identity = getTemplateMatchingNetworkIdentity(
+ mNetworkCapabilities);
+
+ final NetworkPolicy[] policies = mNPM.getNetworkPolicies();
+ for (NetworkPolicy policy : policies) {
+ if (hasActiveCycle(policy) && policy.template.matches(identity)) {
+ // Prefer user-defined warning, otherwise use hard limit
+ final long policyBytes = (policy.warningBytes == LIMIT_DISABLED)
+ ? policy.limitBytes : policy.warningBytes;
+
+ if (policyBytes != LIMIT_DISABLED) {
+ final long policyBudget = getRemainingDailyBudget(policyBytes,
+ policy.cycleIterator().next());
+ minQuota = Math.min(minQuota, policyBudget);
+ }
+ }
+ }
+
+ if (minQuota == Long.MAX_VALUE) {
+ return OPPORTUNISTIC_QUOTA_UNKNOWN;
+ }
+
+ return minQuota / OPQUOTA_USER_SETTING_DIVIDER;
+ }
+
void updateMultipathBudget() {
long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
.getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
- if (quota == NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN) {
+ // Fallback to user settings-based quota if not available from phone plan
+ if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
+ quota = getUserPolicyOpportunisticQuotaBytes();
+ }
+
+ if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
// STOPSHIP: replace this with a configurable mechanism.
quota = DEFAULT_DAILY_MULTIPATH_QUOTA;
if (DBG) Slog.d(TAG, "Setting quota: " + quota + " bytes");
@@ -262,6 +364,11 @@
}
}
+ private static boolean hasActiveCycle(NetworkPolicy policy) {
+ return policy.hasCycle() && policy.lastLimitSnooze <
+ policy.cycleIterator().next().first.toInstant().toEpochMilli();
+ }
+
// Only ever updated on the handler thread. Accessed from other binder threads to retrieve
// the tracker for a specific network.
private final ConcurrentHashMap <Network, MultipathTracker> mMultipathTrackers =
@@ -281,6 +388,7 @@
public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
MultipathTracker existing = mMultipathTrackers.get(network);
if (existing != null) {
+ existing.setNetworkCapabilities(nc);
existing.updateMultipathBudget();
return;
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 1bc7423..d37dd18 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,6 +19,27 @@
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
+import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_INVALID;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -45,7 +66,6 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.IpPrefix;
@@ -148,7 +168,7 @@
stateMachine = sm;
// Assume all state machines start out available and with no errors.
lastState = IControlsTethering.STATE_AVAILABLE;
- lastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ lastError = TETHER_ERROR_NO_ERROR;
}
public boolean isCurrentlyServing() {
@@ -216,7 +236,7 @@
final Handler smHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(smHandler,
- deps.getOffloadHardwareInterface(smHandler, mLog),
+ mDeps.getOffloadHardwareInterface(smHandler, mLog),
mContext.getContentResolver(), mNMService,
mLog);
mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
@@ -243,7 +263,7 @@
mStateReceiver = new StateReceiver();
filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
@@ -265,12 +285,6 @@
updateConfiguration();
}
- // We can't do this once in the Tethering() constructor and cache the value, because the
- // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
- private ConnectivityManager getConnectivityManager() {
- return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
private WifiManager getWifiManager() {
return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}
@@ -296,7 +310,7 @@
if (up) {
maybeTrackNewInterfaceLocked(iface);
} else {
- if (ifaceNameToType(iface) == ConnectivityManager.TETHERING_BLUETOOTH) {
+ if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
stopTrackingInterfaceLocked(iface);
} else {
// Ignore usb0 down after enabling RNDIS.
@@ -318,13 +332,13 @@
final TetheringConfiguration cfg = mConfig;
if (cfg.isWifi(iface)) {
- return ConnectivityManager.TETHERING_WIFI;
+ return TETHERING_WIFI;
} else if (cfg.isUsb(iface)) {
- return ConnectivityManager.TETHERING_USB;
+ return TETHERING_USB;
} else if (cfg.isBluetooth(iface)) {
- return ConnectivityManager.TETHERING_BLUETOOTH;
+ return TETHERING_BLUETOOTH;
}
- return ConnectivityManager.TETHERING_INVALID;
+ return TETHERING_INVALID;
}
@Override
@@ -426,26 +440,26 @@
boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
int result;
switch (type) {
- case ConnectivityManager.TETHERING_WIFI:
+ case TETHERING_WIFI:
result = setWifiTethering(enable);
- if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
- case ConnectivityManager.TETHERING_USB:
+ case TETHERING_USB:
result = setUsbTethering(enable);
- if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
- case ConnectivityManager.TETHERING_BLUETOOTH:
+ case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, receiver);
break;
default:
Log.w(TAG, "Invalid tether type.");
- sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
+ sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
}
}
@@ -456,7 +470,7 @@
}
private int setWifiTethering(final boolean enable) {
- int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ int rval = TETHER_ERROR_MASTER_ERROR;
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
@@ -464,7 +478,7 @@
final WifiManager mgr = getWifiManager();
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
- rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ rval = TETHER_ERROR_NO_ERROR;
}
}
} finally {
@@ -478,7 +492,7 @@
if (adapter == null || !adapter.isEnabled()) {
Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
(adapter == null));
- sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
+ sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
return;
}
@@ -491,12 +505,12 @@
((BluetoothPan) proxy).setBluetoothTethering(enable);
// TODO: Enabling bluetooth tethering can fail asynchronously here.
// We should figure out a way to bubble up that failure instead of sending success.
- int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
- ConnectivityManager.TETHER_ERROR_NO_ERROR :
- ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
+ ? TETHER_ERROR_NO_ERROR
+ : TETHER_ERROR_MASTER_ERROR;
sendTetherResult(receiver, result);
if (enable && isTetherProvisioningRequired()) {
- scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
+ scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
}
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
}
@@ -510,8 +524,8 @@
private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final long ident = Binder.clearCallingIdentity();
try {
@@ -534,7 +548,7 @@
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// If provisioning is successful, enable tethering, otherwise just send the error.
- if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (resultCode == TETHER_ERROR_NO_ERROR) {
enableTetheringInternal(type, true, receiver);
} else {
sendTetherResult(receiver, resultCode);
@@ -554,8 +568,8 @@
private void scheduleProvisioningRechecks(int type) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_SET_ALARM, true);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -572,9 +586,9 @@
private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
- intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_RUN_PROVISION, true);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -585,9 +599,9 @@
}
private void cancelTetherProvisioningRechecks(int type) {
- if (getConnectivityManager().isTetheringSupported()) {
+ if (mDeps.isTetheringSupported()) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -602,8 +616,8 @@
// TODO: De-duplicate with above code, where possible.
private void startProvisionIntent(int tetherType) {
final Intent startProvIntent = new Intent();
- startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
- startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
+ startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
+ startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
startProvIntent.setComponent(TETHER_SERVICE);
mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
}
@@ -618,13 +632,13 @@
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
// Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway.
if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ return TETHER_ERROR_UNAVAIL_IFACE;
}
// NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
// queue but not yet processed, this will be a no-op and it will not
@@ -633,7 +647,7 @@
// TODO: reexamine the threading and messaging model.
tetherState.stateMachine.sendMessage(
TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
}
@@ -643,22 +657,22 @@
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
if (!tetherState.isCurrentlyServing()) {
Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ return TETHER_ERROR_UNAVAIL_IFACE;
}
tetherState.stateMachine.sendMessage(
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
}
public void untetherAll() {
- stopTethering(ConnectivityManager.TETHERING_WIFI);
- stopTethering(ConnectivityManager.TETHERING_USB);
- stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
+ stopTethering(TETHERING_WIFI);
+ stopTethering(TETHERING_USB);
+ stopTethering(TETHERING_BLUETOOTH);
}
public int getLastTetherError(String iface) {
@@ -667,7 +681,7 @@
if (tetherState == null) {
Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
return tetherState.lastError;
}
@@ -675,7 +689,7 @@
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
- if (!getConnectivityManager().isTetheringSupported()) return;
+ if (!mDeps.isTetheringSupported()) return;
final ArrayList<String> availableList = new ArrayList<>();
final ArrayList<String> tetherList = new ArrayList<>();
@@ -692,7 +706,7 @@
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
String iface = mTetherStates.keyAt(i);
- if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
erroredList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
availableList.add(iface);
@@ -710,13 +724,13 @@
}
}
}
- final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
+ bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
+ bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+ bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
+ bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
if (DBG) {
Log.d(TAG, String.format(
@@ -839,7 +853,7 @@
if (action.equals(UsbManager.ACTION_USB_STATE)) {
handleUsbAction(intent);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ } else if (action.equals(CONNECTIVITY_ACTION)) {
handleConnectivityAction(intent);
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
handleWifiApAction(intent);
@@ -850,8 +864,8 @@
}
private void handleConnectivityAction(Intent intent) {
- final NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO);
+ final NetworkInfo networkInfo =
+ (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
if (networkInfo == null ||
networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
return;
@@ -887,14 +901,10 @@
synchronized (Tethering.this.mPublicSync) {
if (!usbConnected && mRndisEnabled) {
// Turn off tethering if it was enabled and there is a disconnect.
- tetherMatchingInterfaces(
- IControlsTethering.STATE_AVAILABLE,
- ConnectivityManager.TETHERING_USB);
+ tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
} else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured.
- tetherMatchingInterfaces(
- IControlsTethering.STATE_TETHERED,
- ConnectivityManager.TETHERING_USB);
+ tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
}
mRndisEnabled = usbConfigured && rndisEnabled;
}
@@ -975,7 +985,7 @@
for (int i = 0; i < mTetherStates.size(); i++) {
TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
- if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (tism.interfaceType() == TETHERING_WIFI) {
tism.unwanted();
return;
}
@@ -1003,7 +1013,7 @@
}
if (!TextUtils.isEmpty(ifname)) {
- maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
+ maybeTrackNewInterfaceLocked(ifname, TETHERING_WIFI);
changeInterfaceState(ifname, ipServingMode);
} else {
mLog.e(String.format(
@@ -1062,7 +1072,7 @@
Log.wtf(TAG, "Unknown interface state: " + requestedState);
return;
}
- if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (result != TETHER_ERROR_NO_ERROR) {
Log.e(TAG, "unable start or stop tethering on iface " + ifname);
return;
}
@@ -1104,7 +1114,7 @@
usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
: UsbManager.FUNCTION_NONE);
}
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
// TODO review API - figure out how to delete these entirely.
@@ -1143,7 +1153,7 @@
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
list.add(mTetherStates.keyAt(i));
}
}
@@ -1189,7 +1199,7 @@
}
String iface = mTetherStates.keyAt(i);
int interfaceType = ifaceNameToType(iface);
- if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
+ if (interfaceType != TETHERING_INVALID) {
tethered.add(interfaceType);
}
}
@@ -1439,7 +1449,7 @@
}
// If this is a Wi-Fi interface, notify WifiManager of the active serving state.
- if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (who.interfaceType() == TETHERING_WIFI) {
final WifiManager mgr = getWifiManager();
final String iface = who.interfaceName();
switch (mode) {
@@ -1463,8 +1473,8 @@
mForwardedDownstreams.remove(who);
// If this is a Wi-Fi interface, tell WifiManager of any errors.
- if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
- if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (who.interfaceType() == TETHERING_WIFI) {
+ if (who.lastError() != TETHER_ERROR_NO_ERROR) {
getWifiManager().updateInterfaceIpState(
who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
}
@@ -1669,7 +1679,7 @@
who.sendMessage(mErrorNotification);
break;
case CMD_CLEAR_ERROR:
- mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mErrorNotification = TETHER_ERROR_NO_ERROR;
transitionTo(mInitialState);
break;
default:
@@ -1931,7 +1941,7 @@
// If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
// Thus we give a chance for TetherMasterSM to recover to InitialState
// by sending CMD_CLEAR_ERROR
- if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ if (error == TETHER_ERROR_MASTER_ERROR) {
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
}
int which;
@@ -1975,7 +1985,7 @@
private void maybeTrackNewInterfaceLocked(final String iface) {
// If we don't care about this type of interface, ignore.
final int interfaceType = ifaceNameToType(iface);
- if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
+ if (interfaceType == TETHERING_INVALID) {
mLog.log(iface + " is not a tetherable iface, ignoring");
return;
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 66afb0f..0ac7a36 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -60,4 +60,8 @@
public INetd getNetdService() {
return NetdService.getInstance();
}
+
+ public boolean isTetheringSupported() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/net/watchlist/ReportEncoder.java b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
index 2a8f4d5..a482e05 100644
--- a/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
+++ b/services/core/java/com/android/server/net/watchlist/ReportEncoder.java
@@ -49,6 +49,7 @@
* Apply DP on watchlist results, and generate a serialized watchlist report ready to store
* in DropBox.
*/
+ @Nullable
static byte[] encodeWatchlistReport(WatchlistConfig config, byte[] userSecret,
List<String> appDigestList, WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
Map<String, Boolean> resultMap = PrivacyUtils.createDpEncodedReportMap(
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index d793842..8352ca6 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -16,6 +16,7 @@
package com.android.server.net.watchlist;
+import android.annotation.Nullable;
import android.os.FileUtils;
import android.util.AtomicFile;
import android.util.Log;
@@ -55,9 +56,6 @@
private static final String NETWORK_WATCHLIST_DB_FOR_TEST_PATH =
"/data/misc/network_watchlist/network_watchlist_for_test.xml";
- // Hash for null / unknown config, a 32 byte array filled with content 0x00
- private static final byte[] UNKNOWN_CONFIG_HASH = new byte[32];
-
private static class XmlTags {
private static final String WATCHLIST_CONFIG = "watchlist-config";
private static final String SHA256_DOMAIN = "sha256-domain";
@@ -228,16 +226,21 @@
return mIsSecureConfig;
}
+ @Nullable
+ /**
+ * Get watchlist config SHA-256 digest.
+ * Return null if watchlist config does not exist.
+ */
public byte[] getWatchlistConfigHash() {
if (!mXmlFile.exists()) {
- return UNKNOWN_CONFIG_HASH;
+ return null;
}
try {
return DigestUtils.getSha256Hash(mXmlFile);
} catch (IOException | NoSuchAlgorithmException e) {
Log.e(TAG, "Unable to get watchlist config hash", e);
}
- return UNKNOWN_CONFIG_HASH;
+ return null;
}
/**
@@ -271,8 +274,10 @@
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("Watchlist config hash: " + HexDump.toHexString(getWatchlistConfigHash()));
+ final byte[] hash = getWatchlistConfigHash();
+ pw.println("Watchlist config hash: " + (hash != null ? HexDump.toHexString(hash) : null));
pw.println("Domain CRC32 digest list:");
+ // mDomainDigests won't go from non-null to null so it's safe
if (mDomainDigests != null) {
mDomainDigests.crc32Digests.dump(fd, pw, args);
}
@@ -281,6 +286,7 @@
mDomainDigests.sha256Digests.dump(fd, pw, args);
}
pw.println("Ip CRC32 digest list:");
+ // mIpDigests won't go from non-null to null so it's safe
if (mIpDigests != null) {
mIpDigests.crc32Digests.dump(fd, pw, args);
}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index b331b9c..864ce5d 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -346,6 +346,7 @@
* @param ipAddresses Ip address that you want to search in watchlist.
* @return Ip address that exists in watchlist, null if it does not match anything.
*/
+ @Nullable
private String searchIpInWatchlist(String[] ipAddresses) {
for (String ipAddress : ipAddresses) {
if (isIpInWatchlist(ipAddress)) {
@@ -377,6 +378,7 @@
* @param host Host that we want to search.
* @return Domain that exists in watchlist, null if it does not match anything.
*/
+ @Nullable
private String searchAllSubDomainsInWatchlist(String host) {
if (host == null) {
return null;
@@ -392,6 +394,7 @@
/** Get all sub-domains in a host */
@VisibleForTesting
+ @Nullable
static String[] getAllSubDomains(String host) {
if (host == null) {
return null;
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
index 632ab81..c69934a 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -144,6 +144,7 @@
* Aggregate all records in database before input timestamp, and return a
* rappor encoded result.
*/
+ @Nullable
public AggregatedResult getAggregatedRecords(long untilTimestamp) {
final String selectStatement = WhiteListReportContract.TIMESTAMP + " < ?";
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index e20a510..c2f3ba0 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -86,7 +86,7 @@
}
}
- public void reloadSettings() {
+ private void reloadSettings() {
if (!mXmlFile.exists()) {
// No settings config
return;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 9d3f48b..45f1a2b 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -67,6 +67,8 @@
public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
/** Indicates that dexopt should convert to CompactDex. */
public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
+ /** Indicates that dexopt should generate an app image */
+ public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 5a7893a..320affb 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -267,7 +267,7 @@
final StringBuilder builder = new StringBuilder();
// The current version.
- builder.append("8 ");
+ builder.append("9 ");
builder.append("dexopt");
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 892fa12..ebab1a7 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -60,6 +60,7 @@
import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB;
import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX;
+import static com.android.server.pm.Installer.DEXOPT_GENERATE_APP_IMAGE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -521,6 +522,10 @@
return getDexFlags(pkg.applicationInfo, compilerFilter, options);
}
+ private boolean isAppImageEnabled() {
+ return SystemProperties.get("dalvik.vm.appimageformat", "").length() > 0;
+ }
+
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
int flags = info.flags;
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
@@ -547,6 +552,14 @@
case PackageManagerService.REASON_INSTALL:
generateCompactDex = false;
}
+ // Use app images only if it is enabled and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ // If the app didn't request for the splits to be loaded in isolation or if it does not
+ // declare inter-split dependencies, then all the splits will be loaded in the base
+ // apk class loader (in the order of their definition, otherwise disable app images
+ // because they are unsupported for multiple class loaders. b/7269679
+ boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null ||
+ !info.requestsIsolatedSplitLoading()) && isAppImageEnabled();
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -554,6 +567,7 @@
| (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
| (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0)
| (generateCompactDex ? DEXOPT_GENERATE_COMPACT_DEX : 0)
+ | (generateAppImage ? DEXOPT_GENERATE_APP_IMAGE : 0)
| hiddenApiFlag;
return adjustDexoptFlags(dexFlags);
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index fae0b24..d4625e9 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -379,7 +379,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG)
- Slog.d(TAG, "Time to poll something.");
+ Slog.d(TAG, "Time to trigger periodic alarm.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
@@ -455,13 +455,13 @@
public void setAlarmForSubscriberTriggering(long timestampMs) {
enforceCallingPermission();
if (DEBUG)
- Slog.d(TAG, "Setting periodic alarm at " + timestampMs);
+ Slog.d(TAG, "Setting periodic alarm in about " +
+ (timestampMs - SystemClock.elapsedRealtime()));
final long callingToken = Binder.clearCallingIdentity();
try {
// using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
// only fire when it awakens.
- // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index d190432..d5ff2dd 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -16,21 +16,21 @@
package android.net.apf;
+import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
-
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.getUint16;
import static com.android.internal.util.BitUtils.getUint32;
import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint16;
import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
-import android.os.SystemClock;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
-import android.net.apf.ApfGenerator;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpClient;
@@ -39,31 +39,29 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.net.util.InterfaceParams;
+import android.os.PowerManager;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
import android.system.PacketSocketAddress;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
-
import java.io.FileDescriptor;
import java.io.IOException;
-import java.lang.Thread;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-
import libcore.io.IoBridge;
/**
@@ -215,10 +213,6 @@
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int ICMP6_ROUTER_SOLICITATION = 133;
- private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
- private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
- private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
@@ -258,9 +252,26 @@
private long mUniqueCounter;
@GuardedBy("this")
private boolean mMulticastFilter;
+ @GuardedBy("this")
+ private boolean mInDozeMode;
private final boolean mDrop802_3Frames;
private final int[] mEthTypeBlackList;
+ // Detects doze mode state transitions.
+ private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
+ PowerManager powerManager =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ final boolean deviceIdle = powerManager.isDeviceIdleMode();
+ setDozeMode(deviceIdle);
+ }
+ }
+ };
+ private final Context mContext;
+
// Our IPv4 address, if we have just one, otherwise null.
@GuardedBy("this")
private byte[] mIPv4Address;
@@ -269,13 +280,14 @@
private int mIPv4PrefixLength;
@VisibleForTesting
- ApfFilter(ApfConfiguration config, InterfaceParams ifParams,
+ ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
IpClient.Callback ipClientCallback, IpConnectivityLog log) {
mApfCapabilities = config.apfCapabilities;
mIpClientCallback = ipClientCallback;
mInterfaceParams = ifParams;
mMulticastFilter = config.multicastFilter;
mDrop802_3Frames = config.ieee802_3Filter;
+ mContext = context;
// Now fill the black list from the passed array
mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
@@ -284,6 +296,10 @@
// TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
maybeStartFilter();
+
+ // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
+ mContext.registerReceiver(mDeviceIdleReceiver,
+ new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
}
private void log(String s) {
@@ -522,7 +538,7 @@
// to our packet socket. b/29586253
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
- getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
+ getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
throw new InvalidRaException("Not an ICMP6 router advertisement");
}
@@ -889,10 +905,11 @@
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
// Here's a basic summary of what the IPv6 filter program does:
//
- // if it's not ICMPv6:
- // if it's multicast and we're dropping multicast:
- // drop
- // pass
+ // if we're dropping multicast
+ // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
+ // if it's multicast:
+ // drop
+ // pass
// if it's ICMPv6 RS to any:
// drop
// if it's ICMPv6 NA to ff02::1:
@@ -902,28 +919,44 @@
// Drop multicast if the multicast filter is enabled.
if (mMulticastFilter) {
- // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
- String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
- gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
+ final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
+ final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
- // Drop all other packets sent to ff00::/8.
+ // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
+ // While awake, let all ICMPv6 multicasts through.
+ if (mInDozeMode) {
+ // Not ICMPv6? -> Proceed to multicast filtering
+ gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
+
+ // ICMPv6 but not ECHO? -> Skip the multicast filter.
+ // (ICMPv6 ECHO requests will go through the multicast filter below).
+ gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+ gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
+ } else {
+ gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
+ }
+
+ // Drop all other packets sent to ff00::/8 (multicast prefix).
+ gen.defineLabel(dropAllIPv6MulticastsLabel);
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
- // Not multicast and not ICMPv6. Pass.
+ // Not multicast. Pass.
gen.addJump(gen.PASS_LABEL);
- gen.defineLabel(skipIpv6MulticastFilterLabel);
+ gen.defineLabel(skipIPv6MulticastFilterLabel);
} else {
// If not ICMPv6, pass.
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
}
+ // If we got this far, the packet is ICMPv6. Drop some specific types.
+
// Add unsolicited multicast neighbor announcements filter
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
// Drop all router solicitations (b/32833400)
- gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, gen.DROP_LABEL);
// If not neighbor announcements, skip filter.
- gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
+ gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
// If to ff02::1, drop.
// TODO: Drop only if they don't contain the address of on-link neighbours.
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
@@ -1168,9 +1201,9 @@
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
* filtering using APF programs.
*/
- public static ApfFilter maybeCreate(ApfConfiguration config,
+ public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
- if (config == null || ifParams == null) return null;
+ if (context == null || config == null || ifParams == null) return null;
ApfCapabilities apfCapabilities = config.apfCapabilities;
if (apfCapabilities == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
@@ -1187,7 +1220,8 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog());
+
+ return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
}
public synchronized void shutdown() {
@@ -1197,12 +1231,11 @@
mReceiveThread = null;
}
mRas.clear();
+ mContext.unregisterReceiver(mDeviceIdleReceiver);
}
public synchronized void setMulticastFilter(boolean isEnabled) {
- if (mMulticastFilter == isEnabled) {
- return;
- }
+ if (mMulticastFilter == isEnabled) return;
mMulticastFilter = isEnabled;
if (!isEnabled) {
mNumProgramUpdatesAllowingMulticast++;
@@ -1210,6 +1243,13 @@
installNewProgramLocked();
}
+ @VisibleForTesting
+ public synchronized void setDozeMode(boolean isEnabled) {
+ if (mInDozeMode == isEnabled) return;
+ mInDozeMode = isEnabled;
+ installNewProgramLocked();
+ }
+
/** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
LinkAddress ipv4Address = null;
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 9863370..a184b22 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -1490,7 +1490,7 @@
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
apfConfig.ethTypeBlackList =
mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
- mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback);
+ mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 984c9f8..53fd01f 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -136,6 +136,8 @@
* - https://tools.ietf.org/html/rfc4861
*/
public static final int ICMPV6_HEADER_MIN_LEN = 4;
+ public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+ public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
public static final int ICMPV6_ROUTER_SOLICITATION = 133;
public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134;
public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
@@ -147,7 +149,6 @@
public static final int ICMPV6_ND_OPTION_TLLA = 2;
public static final int ICMPV6_ND_OPTION_MTU = 5;
- public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
/**
* UDP constants.
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
index 654acc2..678f018 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistConfigTests.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
@@ -114,13 +115,19 @@
}
@Test
- public void testWatchlistConfig_getWatchlistConfigHash() throws Exception {
+ public void testWatchlistConfig_getWatchlistConfigHash_hasConfig() throws Exception {
copyWatchlistConfigXml(mContext, TEST_XML_1, mTestXmlFile);
WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
assertEquals(TEST_XML_1_HASH, HexDump.toHexString(config.getWatchlistConfigHash()));
}
@Test
+ public void testWatchlistConfig_getWatchlistConfigHash_withoutConfig() throws Exception {
+ WatchlistConfig config = new WatchlistConfig(mTestXmlFile);
+ assertNull(config.getWatchlistConfigHash());
+ }
+
+ @Test
public void testWatchlistConfig_testDumpDoesNotCrash() throws Exception {
WatchlistConfig config = new WatchlistConfig(new File("/not_exist_path.xml"));
ByteArrayOutputStream bs = new ByteArrayOutputStream(2048);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 36333e4..3bf951d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2600,7 +2600,6 @@
}
/**
- *
* Request audio routing to a specific bluetooth device. Calling this method may result in
* the device routing audio to a different bluetooth device than the one specified if the
* bluetooth stack is unable to route audio to the requested device.
@@ -2611,13 +2610,13 @@
* Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
* self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
* <p>
- * See also {@link InCallService#requestBluetoothAudio(String)}
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * See also {@link InCallService#requestBluetoothAudio(BluetoothDevice)}
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
for (Listener l : mListeners) {
- l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
+ l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH,
+ bluetoothDevice.getAddress());
}
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index af65c65..bd25ab2 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -428,12 +428,11 @@
* A list of available devices can be obtained via
* {@link CallAudioState#getSupportedBluetoothDevices()}
*
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public final void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public final void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
if (mPhone != null) {
- mPhone.requestBluetoothAudio(bluetoothAddress);
+ mPhone.requestBluetoothAudio(bluetoothDevice.getAddress());
}
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 15e0632..e15d35b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -27,6 +27,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.app.ActivityThread;
import android.app.PendingIntent;
@@ -1067,6 +1068,13 @@
public static final int UNKNOWN_CARRIER_ID = -1;
/**
+ * An unknown carrier id list version.
+ * @hide
+ */
+ @TestApi
+ public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1;
+
+ /**
* Broadcast Action: The subscription carrier identity has changed.
* This intent could be sent on the following events:
* <ul>
@@ -7808,4 +7816,49 @@
}
}
}
+
+ /**
+ * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+ * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+ * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+ String gid2, String plmn, String spn) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setCarrierTestOverride(
+ getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ }
+
+ /**
+ * A test API to return installed carrier id list version
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ *
+ * @hide
+ */
+ @TestApi
+ public int getCarrierIdListVersion() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierIdListVersion(getSubId());
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return UNKNOWN_CARRIER_ID_LIST_VERSION;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fbb69ad..03fc84d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1486,4 +1486,17 @@
* screen is off) we want to turn on those indications even when the screen is off.
*/
void setRadioIndicationUpdateMode(int subId, int filters, int mode);
+
+ /**
+ * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+ * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+ * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+ */
+ void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
+ String gid2, String plmn, String spn);
+
+ /**
+ * A test API to return installed carrier id list version.
+ */
+ int getCarrierIdListVersion(int subId);
}
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 970596d..a946e50 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.Os;
@@ -69,11 +70,17 @@
private IpSecService mMockIpSecService;
private IpSecManager mIpSecManager;
+ private MockContext mMockContext = new MockContext() {
+ @Override
+ public String getOpPackageName() {
+ return "fooPackage";
+ }
+ };
@Before
public void setUp() throws Exception {
mMockIpSecService = mock(IpSecService.class);
- mIpSecManager = new IpSecManager(mMockIpSecService);
+ mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
}
/*
@@ -227,7 +234,7 @@
new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
when(mMockIpSecService.createTunnelInterface(
eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
- anyObject(), anyObject()))
+ anyObject(), anyObject(), anyString()))
.thenReturn(dummyResponse);
IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
@@ -245,7 +252,7 @@
assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
tunnelIntf.close();
- verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+ verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
}
@Test
@@ -255,10 +262,12 @@
tunnelIntf.addAddress(VTI_INNER_ADDRESS);
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
}
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 9b75a50..fef702e 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -16,6 +16,7 @@
package android.net.apf;
+import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.put;
@@ -26,6 +27,7 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -82,6 +84,7 @@
private static final int TIMEOUT_MS = 500;
@Mock IpConnectivityLog mLog;
+ @Mock Context mContext;
@Before
public void setUp() throws Exception {
@@ -633,9 +636,9 @@
private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
- public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
- IpConnectivityLog log) throws Exception {
- super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
+ public TestApfFilter(Context context, ApfConfiguration config,
+ IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception {
+ super(context, config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -757,6 +760,17 @@
private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
+ // Helper to initialize a default apfFilter.
+ private ApfFilter setupApfFilter(IpManager.Callback ipManagerCallback, ApfConfiguration config)
+ throws Exception {
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ apfFilter.setLinkProperties(lp);
+ return apfFilter;
+ }
+
@Test
public void testApfFilterIPv4() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -766,7 +780,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -818,7 +832,7 @@
public void testApfFilterIPv6() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -861,7 +875,7 @@
ApfConfiguration config = getDefaultConfig();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -925,7 +939,7 @@
apfFilter.shutdown();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
@@ -941,16 +955,47 @@
}
@Test
+ public void testApfFilterMulticastPingWhileDozing() throws Exception {
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, getDefaultConfig());
+
+ // Construct a multicast ICMPv6 ECHO request.
+ final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+ packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
+ put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
+
+ // Normally, we let multicast pings alone...
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ // ...and even while dozing...
+ apfFilter.setDozeMode(true);
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
+ apfFilter.setMulticastFilter(true);
+ assertDrop(ipManagerCallback.getApfProgram(), packet.array());
+
+ // However, we should still let through all other ICMPv6 types.
+ ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
+ raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
+ assertPass(ipManagerCallback.getApfProgram(), raPacket.array());
+
+ // Now wake up from doze mode to ensure that we no longer drop the packets.
+ // (The multicast filter is still enabled at this point).
+ apfFilter.setDozeMode(false);
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ apfFilter.shutdown();
+ }
+
+ @Test
public void testApfFilter802_3() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
-
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
@@ -970,8 +1015,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IEEE802.3 frame is dropped
@@ -992,18 +1036,13 @@
@Test
public void testApfFilterEthTypeBL() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
final int[] emptyBlackList = {};
final int[] ipv4BlackList = {ETH_P_IP};
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
@@ -1023,8 +1062,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4BlackList;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
@@ -1039,8 +1077,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4Ipv6BlackList;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
@@ -1081,7 +1118,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1205,7 +1242,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
@@ -1351,7 +1388,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
@@ -1372,7 +1409,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 410f754..e573d35 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.INetd;
import android.net.IpSecAlgorithm;
@@ -40,6 +41,7 @@
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.system.Os;
@@ -92,7 +94,28 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
};
- Context mMockContext;
+ AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+
+ MockContext mMockContext = new MockContext() {
+ @Override
+ public Object getSystemService(String name) {
+ switch(name) {
+ case Context.APP_OPS_SERVICE:
+ return mMockAppOps;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+ return;
+ }
+ throw new SecurityException("Unavailable permission requested");
+ }
+ };
+
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@@ -114,13 +137,22 @@
@Before
public void setUp() throws Exception {
- mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+ // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ // A system package will not be granted the app op, so this should fall back to
+ // a permissions check, which should pass.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
+ .thenReturn(AppOpsManager.MODE_DEFAULT);
+ // A mismatch between the package name and the UID will return MODE_IGNORED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
}
@Test
@@ -232,7 +264,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -267,7 +299,7 @@
ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -301,12 +333,12 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
// Attempting to create transform a second time with the same SPIs should throw an error...
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -314,7 +346,7 @@
// ... even if the transform is deleted
mIpSecService.deleteTransform(createTransformResp.resourceId);
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -327,7 +359,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -351,7 +383,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
mIpSecService.deleteTransform(createTransformResp.resourceId);
verify(mMockNetd, times(1))
@@ -398,7 +430,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -435,7 +467,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
int resourceId = createTransformResp.resourceId;
@@ -460,10 +492,10 @@
}
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr) {
+ String localAddr, String remoteAddr, String pkgName) {
IpSecTunnelInterfaceResponse createTunnelResp =
mIpSecService.createTunnelInterface(
- mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+ mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
assertNotNull(createTunnelResp);
assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
@@ -473,7 +505,7 @@
@Test
public void testCreateTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
// Check that we have stored the tracking object, and retrieve it
IpSecService.UserRecord userRecord =
@@ -495,12 +527,12 @@
@Test
public void testDeleteTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -516,7 +548,7 @@
@Test
public void testTunnelInterfaceBinderDeath() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -539,22 +571,34 @@
@Test
public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
+ mIpSecService.addAddressToTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceAddAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.removeAddressFromTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceDelAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
+ }
+ }
- mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceAddAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
-
- mIpSecService.removeAddressFromTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceDelAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
+ @Test
+ public void testAddTunnelFailsForBadPackageName() throws Exception {
+ try {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+ fail("Expected a SecurityException for badPackage.");
+ } catch (SecurityException expected) {
+ }
}
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 27f90f2..6142a7c 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -19,8 +19,14 @@
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -54,7 +60,6 @@
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
@@ -125,7 +130,6 @@
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
- @Mock private ConnectivityManager mConnectivityManager;
@Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService;
@Mock private INetworkPolicyManager mPolicyManager;
@@ -173,7 +177,6 @@
@Override
public Object getSystemService(String name) {
- if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
return super.getSystemService(name);
@@ -181,8 +184,15 @@
}
public class MockTetheringDependencies extends TetheringDependencies {
- private StateMachine upstreamNetworkMonitorMasterSM;
- private ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ StateMachine upstreamNetworkMonitorMasterSM;
+ ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ int isTetheringSupportedCalls;
+
+ public void reset() {
+ upstreamNetworkMonitorMasterSM = null;
+ ipv6CoordinatorNotifyList = null;
+ isTetheringSupportedCalls = 0;
+ }
@Override
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
@@ -222,11 +232,17 @@
return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
}
+
+ @Override
+ public boolean isTetheringSupported() {
+ isTetheringSupportedCalls++;
+ return true;
+ }
}
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
boolean with464xlat) {
- final NetworkInfo info = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, null, null);
+ final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_MOBILE_IFNAME);
@@ -308,7 +324,8 @@
}
};
mServiceContext.registerReceiver(mBroadcastReceiver,
- new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ new IntentFilter(ACTION_TETHER_STATE_CHANGED));
+ mTetheringDependencies.reset();
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
@@ -404,7 +421,7 @@
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
// Verify that ifname is in the whichExtra array of the tether state changed broadcast.
final Intent bcast = mIntents.get(0);
- assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+ assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
assertTrue(ifnames.contains(ifname));
mIntents.remove(bcast);
@@ -412,8 +429,6 @@
public void failingLocalOnlyHotspotLegacyApBroadcast(
boolean emulateInterfaceStatusChanged) throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
@@ -427,16 +442,14 @@
// then it creates a TetherInterfaceStateMachine and sends out a
// broadcast indicating that the interface is "available".
if (emulateInterfaceStatusChanged) {
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
}
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
private void prepareUsbTethering(NetworkState upstreamState) {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
@@ -454,7 +467,6 @@
prepareUsbTethering(upstreamState);
// This should produce no activity of any kind.
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Pretend we then receive USB configured broadcast.
@@ -481,8 +493,6 @@
public void workingLocalOnlyHotspotEnrichedApBroadcast(
boolean emulateInterfaceStatusChanged) throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
@@ -493,18 +503,17 @@
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).start();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyNoMoreInteractions(mConnectivityManager);
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
@@ -523,8 +532,7 @@
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
- assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
/**
@@ -648,7 +656,6 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failingWifiTetheringLegacyApBroadcast() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
@@ -656,7 +663,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -666,9 +672,8 @@
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
- verifyNoMoreInteractions(mConnectivityManager);
+ assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
@@ -676,7 +681,6 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
@@ -684,7 +688,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -695,21 +698,20 @@
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
verify(mUpstreamNetworkMonitor, times(1)).start();
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyNoMoreInteractions(mConnectivityManager);
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
/////
// We do not currently emulate any upstream being found.
@@ -723,7 +725,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, when tethering mode
@@ -743,14 +744,12 @@
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
- assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failureEnablingIpForwarding() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
@@ -759,7 +758,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -778,8 +776,9 @@
verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
verify(mNMService, times(1)).setIpForwardingEnabled(true);
// This never gets called because of the exception thrown above.
@@ -792,7 +791,6 @@
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
}