Merge "Merge caller targets and ranked targets." into qt-dev
diff --git a/api/current.txt b/api/current.txt
index 4bbae3b..03648ea 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23079,8 +23079,8 @@
method @NonNull public android.media.AudioAttributes.Builder setAllowedCapturePolicy(int);
method public android.media.AudioAttributes.Builder setContentType(int);
method public android.media.AudioAttributes.Builder setFlags(int);
+ method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
- method public android.media.AudioAttributes.Builder setMuteHapticChannels(boolean);
method public android.media.AudioAttributes.Builder setUsage(int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 76b8f66..c0da879 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -553,7 +553,7 @@
}
public class NotificationManager {
- method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
+ method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
@@ -1242,30 +1242,29 @@
package android.bluetooth {
public final class BluetoothAdapter {
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean addOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull java.util.concurrent.Executor, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
method public boolean disableBLE();
method public boolean enableBLE();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean enableNoAutoConnect();
method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean registerMetadataListener(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothAdapter.MetadataListener, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean unregisterMetadataListener(android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
field public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
}
- public abstract static class BluetoothAdapter.MetadataListener {
- ctor public BluetoothAdapter.MetadataListener();
- method public void onMetadataChanged(android.bluetooth.BluetoothDevice, int, String);
+ public static interface BluetoothAdapter.OnMetadataChangedListener {
+ method public void onMetadataChanged(@NonNull android.bluetooth.BluetoothDevice, int, @Nullable byte[]);
}
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setSilenceMode(boolean);
field public static final int ACCESS_ALLOWED = 1; // 0x1
@@ -1275,21 +1274,21 @@
field public static final int METADATA_COMPANION_APP = 4; // 0x4
field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
- field public static final int METADATA_IS_UNTHETHERED_HEADSET = 6; // 0x6
+ field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6
field public static final int METADATA_MAIN_ICON = 5; // 0x5
field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0
field public static final int METADATA_MAX_LENGTH = 2048; // 0x800
field public static final int METADATA_MODEL_NAME = 1; // 0x1
field public static final int METADATA_SOFTWARE_VERSION = 2; // 0x2
- field public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12; // 0xc
- field public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15; // 0xf
- field public static final int METADATA_UNTHETHERED_CASE_ICON = 9; // 0x9
- field public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10; // 0xa
- field public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13; // 0xd
- field public static final int METADATA_UNTHETHERED_LEFT_ICON = 7; // 0x7
- field public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11; // 0xb
- field public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14; // 0xe
- field public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8; // 0x8
+ field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc
+ field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf
+ field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9
+ field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa
+ field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd
+ field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7
+ field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb
+ field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe
+ field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8
}
public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
@@ -6631,8 +6630,8 @@
method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+ method public void onAllowedAdjustmentsChanged();
method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method public void onCapabilitiesChanged();
method public void onNotificationDirectReplied(@NonNull String);
method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
diff --git a/api/test-current.txt b/api/test-current.txt
index 5d7144c..c3215a6 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
@@ -328,9 +329,9 @@
}
public class NotificationManager {
- method public void allowAssistantCapability(String);
- method public void disallowAssistantCapability(String);
- method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
+ method public void allowAssistantAdjustment(String);
+ method public void disallowAssistantAdjustment(String);
+ method @NonNull public java.util.List<java.lang.String> getAllowedAssistantAdjustments();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
method public android.content.ComponentName getEffectsSuppressor();
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
@@ -2488,8 +2489,8 @@
method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+ method public void onAllowedAdjustmentsChanged();
method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method public void onCapabilitiesChanged();
method public void onNotificationDirectReplied(@NonNull String);
method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 017cb6d..15d248f 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -235,6 +235,7 @@
"tests/condition/CombinationConditionTracker_test.cpp",
"tests/condition/SimpleConditionTracker_test.cpp",
"tests/condition/StateTracker_test.cpp",
+ "tests/condition/ConditionTimer_test.cpp",
"tests/metrics/OringDurationTracker_test.cpp",
"tests/metrics/MaxDurationTracker_test.cpp",
"tests/metrics/CountMetricProducer_test.cpp",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 82d177a..90ba7ce 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -176,23 +176,38 @@
FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
BinaryPushStateChanged binary_push_state_changed = 102;
DevicePolicyEvent device_policy_event = 103;
- DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
- DocsUIFileOperationCopyMoveModeReported docs_ui_file_op_copy_move_mode_reported = 105;
- DocsUIFileOperationFailureReported docs_ui_file_op_failure = 106;
- DocsUIFileOperationReported docs_ui_provider_file_op = 107;
- DocsUIInvalidScopedAccessRequestReported docs_ui_invalid_scoped_access_request = 108;
- DocsUILaunchReported docs_ui_launch_reported = 109;
- DocsUIRootVisitedReported docs_ui_root_visited = 110;
- DocsUIStartupMsReported docs_ui_startup_ms = 111;
- DocsUIUserActionReported docs_ui_user_action_reported = 112;
+ DocsUIFileOperationCanceledReported docs_ui_file_op_canceled =
+ 104 [(log_from_module) = "docsui"];
+ DocsUIFileOperationCopyMoveModeReported
+ docs_ui_file_op_copy_move_mode_reported =
+ 105 [(log_from_module) = "docsui"];
+ DocsUIFileOperationFailureReported docs_ui_file_op_failure =
+ 106 [(log_from_module) = "docsui"];
+ DocsUIFileOperationReported docs_ui_provider_file_op =
+ 107 [(log_from_module) = "docsui"];
+ DocsUIInvalidScopedAccessRequestReported
+ docs_ui_invalid_scoped_access_request =
+ 108 [(log_from_module) = "docsui"];
+ DocsUILaunchReported docs_ui_launch_reported =
+ 109 [(log_from_module) = "docsui"];
+ DocsUIRootVisitedReported docs_ui_root_visited =
+ 110 [(log_from_module) = "docsui"];
+ DocsUIStartupMsReported docs_ui_startup_ms =
+ 111 [(log_from_module) = "docsui"];
+ DocsUIUserActionReported docs_ui_user_action_reported =
+ 112 [(log_from_module) = "docsui"];
WifiEnabledStateChanged wifi_enabled_state_changed = 113;
WifiRunningStateChanged wifi_running_state_changed = 114;
AppCompacted app_compacted = 115;
NetworkDnsEventReported network_dns_event_reported = 116 [(log_from_module) = "resolv"];
- DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported = 117;
- DocsUIPickResultReported docs_ui_pick_result_reported = 118;
- DocsUISearchModeReported docs_ui_search_mode_reported = 119;
- DocsUISearchTypeReported docs_ui_search_type_reported = 120;
+ DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported =
+ 117 [(log_from_module) = "docsui"];
+ DocsUIPickResultReported docs_ui_pick_result_reported =
+ 118 [(log_from_module) = "docsui"];
+ DocsUISearchModeReported docs_ui_search_mode_reported =
+ 119 [(log_from_module) = "docsui"];
+ DocsUISearchTypeReported docs_ui_search_type_reported =
+ 120 [(log_from_module) = "docsui"];
DataStallEvent data_stall_event = 121;
RescuePartyResetReported rescue_party_reset_reported = 122;
SignedConfigReported signed_config_reported = 123;
diff --git a/cmds/statsd/src/condition/ConditionTimer.h b/cmds/statsd/src/condition/ConditionTimer.h
new file mode 100644
index 0000000..442bc11
--- /dev/null
+++ b/cmds/statsd/src/condition/ConditionTimer.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include <stdint.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * A simple stopwatch to time the duration of condition being true.
+ *
+ * The owner of the stopwatch (MetricProducer) is responsible to notify the stopwatch when condition
+ * changes (start/pause), and when to start a new bucket (a new lap basically). All timestamps
+ * should be elapsedRealTime in nano seconds.
+ *
+ * Keep the timer simple and inline everything. This class is *NOT* thread safe. Caller is
+ * responsible for thread safety.
+ */
+class ConditionTimer {
+public:
+ explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
+ if (initCondition) {
+ mLastConditionTrueTimestampNs = bucketStartNs;
+ }
+ };
+
+ // Tracks how long the condition has been stayed true in the *current* bucket.
+ // When a new bucket is created, this value will be reset to 0.
+ int64_t mTimerNs = 0;
+
+ // Last elapsed real timestamp when condition turned to true
+ // When a new bucket is created and the condition is true, then the timestamp is set
+ // to be the bucket start timestamp.
+ int64_t mLastConditionTrueTimestampNs = 0;
+
+ bool mCondition = false;
+
+ int64_t newBucketStart(int64_t nextBucketStartNs) {
+ if (mCondition) {
+ mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
+ mLastConditionTrueTimestampNs = nextBucketStartNs;
+ }
+
+ int64_t temp = mTimerNs;
+ mTimerNs = 0;
+ return temp;
+ }
+
+ void onConditionChanged(bool newCondition, int64_t timestampNs) {
+ if (newCondition == mCondition) {
+ return;
+ }
+ mCondition = newCondition;
+ if (newCondition) {
+ mLastConditionTrueTimestampNs = timestampNs;
+ } else {
+ mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
+ }
+ }
+
+ FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
+ FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_True);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 13eee5d..d6411a7 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -276,7 +276,8 @@
}
bool StatsPullerManager::PullerForMatcherExists(int tagId) const {
- return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
+ // Vendor pulled atoms might be registered after we parse the config.
+ return isVendorPulledAtom(tagId) || kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
}
void StatsPullerManager::updateAlarmLocked() {
@@ -449,9 +450,8 @@
const sp<IStatsPullerCallback>& callback) {
AutoMutex _l(mLock);
// Platform pullers cannot be changed.
- if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
- VLOG("RegisterPullerCallback: atom tag %d is less than min tag %d",
- atomTag, StatsdStats::kMaxPlatformAtomTag);
+ if (!isVendorPulledAtom(atomTag)) {
+ VLOG("RegisterPullerCallback: atom tag %d is not vendor pulled", atomTag);
return;
}
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
@@ -462,7 +462,7 @@
void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) {
AutoMutex _l(mLock);
// Platform pullers cannot be changed.
- if (atomTag < StatsdStats::kMaxPlatformAtomTag) {
+ if (!isVendorPulledAtom(atomTag)) {
return;
}
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/false);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 88ecccc..53f12ac 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -160,6 +160,12 @@
// Max platform atom tag number.
static const int32_t kMaxPlatformAtomTag = 100000;
+ // Vendor pulled atom start id.
+ static const int32_t kVendorPulledAtomStartTag = 150000;
+
+ // Max accepted atom id.
+ static const int32_t kMaxAtomTag = 200000;
+
static const int64_t kInt64Max = 0x7fffffffffffffffLL;
/**
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 18bfdfc..90a4e8b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -72,6 +72,7 @@
const int FIELD_ID_BUCKET_NUM = 4;
const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 5;
const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
+const int FIELD_ID_CONDITION_TRUE_NS = 10;
const Value ZERO_LONG((int64_t)0);
const Value ZERO_DOUBLE((int64_t)0);
@@ -107,7 +108,8 @@
mCurrentBucketIsInvalid(false),
mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
: StatsdStats::kPullMaxDelayNs),
- mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
+ mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()),
+ mConditionTimer(mCondition == ConditionState::kTrue, timeBaseNs) {
int64_t bucketSizeMills = 0;
if (metric.has_bucket()) {
bucketSizeMills = TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket());
@@ -153,6 +155,7 @@
// flushIfNeeded to adjust start and end to bucket boundaries.
// Adjust start for partial bucket
mCurrentBucketStartTimeNs = startTimeNs;
+ mConditionTimer.newBucketStart(mCurrentBucketStartTimeNs);
// Kicks off the puller immediately if condition is true and diff based.
if (mIsPulled && mCondition == ConditionState::kTrue && mUseDiff) {
pullAndMatchEventsLocked(startTimeNs, mCondition);
@@ -293,6 +296,11 @@
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
(long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
}
+ // only write the condition timer value if the metric has a condition.
+ if (mConditionTrackerIndex >= 0) {
+ protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
+ (long long)bucket.mConditionTrueNs);
+ }
for (int i = 0; i < (int)bucket.valueIndex.size(); i ++) {
int index = bucket.valueIndex[i];
const Value& value = bucket.values[i];
@@ -386,19 +394,19 @@
resetBase();
}
mCondition = newCondition;
-
} else {
VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
(long long)mCurrentBucketStartTimeNs);
StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
invalidateCurrentBucket();
- // Something weird happened. If we received another event if the future, the condition might
+ // Something weird happened. If we received another event in the future, the condition might
// be wrong.
mCondition = initialCondition(mConditionTrackerIndex);
}
// This part should alway be called.
flushIfNeededLocked(eventTimeNs);
+ mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
}
void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition) {
@@ -799,12 +807,14 @@
(int)mCurrentSlicedBucket.size());
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
-
+ // Close the current bucket.
+ int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
// The current bucket is large enough to keep.
for (const auto& slice : mCurrentSlicedBucket) {
ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
+ bucket.mConditionTrueNs = conditionTrueDuration;
// it will auto create new vector of ValuebucketInfo if the key is not found.
if (bucket.valueIndex.size() > 0) {
auto& bucketList = mPastBuckets[slice.first];
@@ -817,6 +827,8 @@
appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
initCurrentSlicedBucket(nextBucketStartTimeNs);
+ // Update the condition timer again, in case we skipped buckets.
+ mConditionTimer.newBucketStart(nextBucketStartTimeNs);
mCurrentBucketNum += numBucketsForward;
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 12cec5d..0f56337 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -19,12 +19,13 @@
#include <gtest/gtest_prod.h>
#include <utils/threads.h>
#include <list>
-#include "../anomaly/AnomalyTracker.h"
-#include "../condition/ConditionTracker.h"
-#include "../external/PullDataReceiver.h"
-#include "../external/StatsPullerManager.h"
-#include "../matchers/EventMatcherWizard.h"
-#include "../stats_log_util.h"
+#include "anomaly/AnomalyTracker.h"
+#include "condition/ConditionTimer.h"
+#include "condition/ConditionTracker.h"
+#include "external/PullDataReceiver.h"
+#include "external/StatsPullerManager.h"
+#include "matchers/EventMatcherWizard.h"
+#include "stats_log_util.h"
#include "MetricProducer.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -37,6 +38,9 @@
int64_t mBucketEndNs;
std::vector<int> valueIndex;
std::vector<Value> values;
+ // If the metric has no condition, then this field is just wasted.
+ // When we tune statsd memory usage in the future, this is a candidate to optimize.
+ int64_t mConditionTrueNs;
};
@@ -228,6 +232,8 @@
const bool mSplitBucketForAppUpgrade;
+ ConditionTimer mConditionTimer;
+
FRIEND_TEST(ValueMetricProducerTest, TestAnomalyDetection);
FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
FRIEND_TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 1dfc433..54ca757 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -129,6 +129,8 @@
optional int64 start_bucket_elapsed_millis = 5;
optional int64 end_bucket_elapsed_millis = 6;
+
+ optional int64 condition_true_nanos = 10;
}
message ValueMetricData {
diff --git a/cmds/statsd/src/stats_log_util.h b/cmds/statsd/src/stats_log_util.h
index cdef874..2a18e22 100644
--- a/cmds/statsd/src/stats_log_util.h
+++ b/cmds/statsd/src/stats_log_util.h
@@ -96,6 +96,10 @@
return atomId <= util::kMaxPushedAtomId && atomId > 1;
}
+inline bool isVendorPulledAtom(int atomId) {
+ return atomId >= StatsdStats::kVendorPulledAtomStartTag && atomId < StatsdStats::kMaxAtomTag;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/tests/condition/ConditionTimer_test.cpp b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
new file mode 100644
index 0000000..ea02cd3
--- /dev/null
+++ b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/condition/ConditionTimer.h"
+
+#include <gtest/gtest.h>
+#include <stdio.h>
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static int64_t time_base = 10;
+static int64_t ct_start_time = 200;
+
+TEST(ConditionTimerTest, TestTimer_Inital_False) {
+ ConditionTimer timer(false, time_base);
+ EXPECT_EQ(false, timer.mCondition);
+ EXPECT_EQ(0, timer.mTimerNs);
+
+ EXPECT_EQ(0, timer.newBucketStart(ct_start_time));
+ EXPECT_EQ(0, timer.mTimerNs);
+
+ timer.onConditionChanged(true, ct_start_time + 5);
+ EXPECT_EQ(ct_start_time + 5, timer.mLastConditionTrueTimestampNs);
+ EXPECT_EQ(true, timer.mCondition);
+
+ EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
+ EXPECT_EQ(ct_start_time + 100, timer.mLastConditionTrueTimestampNs);
+ EXPECT_EQ(true, timer.mCondition);
+}
+
+TEST(ConditionTimerTest, TestTimer_Inital_True) {
+ ConditionTimer timer(true, time_base);
+ EXPECT_EQ(true, timer.mCondition);
+ EXPECT_EQ(0, timer.mTimerNs);
+
+ EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
+ EXPECT_EQ(true, timer.mCondition);
+ EXPECT_EQ(0, timer.mTimerNs);
+ EXPECT_EQ(ct_start_time, timer.mLastConditionTrueTimestampNs);
+
+ timer.onConditionChanged(false, ct_start_time + 5);
+ EXPECT_EQ(5, timer.mTimerNs);
+
+ EXPECT_EQ(5, timer.newBucketStart(ct_start_time + 100));
+ EXPECT_EQ(0, timer.mTimerNs);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index afa05a9..c12a5900 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -55,8 +55,11 @@
static void assertPastBucketValuesSingleKey(
const std::unordered_map<MetricDimensionKey, std::vector<ValueBucket>>& mPastBuckets,
- const std::initializer_list<int>& expectedValuesList) {
+ const std::initializer_list<int>& expectedValuesList,
+ const std::initializer_list<int64_t>& expectedDurationNsList) {
std::vector<int> expectedValues(expectedValuesList);
+ std::vector<int64_t> expectedDurationNs(expectedDurationNsList);
+ ASSERT_EQ(expectedValues.size(), expectedDurationNs.size());
if (expectedValues.size() == 0) {
ASSERT_EQ(0, mPastBuckets.size());
return;
@@ -69,10 +72,11 @@
for (int i = 0; i < expectedValues.size(); i++) {
EXPECT_EQ(expectedValues[i], buckets[i].values[0].long_value)
<< "Values differ at index " << i;
+ EXPECT_EQ(expectedDurationNs[i], buckets[i].mConditionTrueNs)
+ << "Condition duration value differ at index " << i;
}
}
-
class ValueMetricProducerTestHelper {
public:
@@ -237,6 +241,7 @@
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -256,7 +261,9 @@
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -275,8 +282,11 @@
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[2].mConditionTrueNs);
}
TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
@@ -326,8 +336,11 @@
EXPECT_EQ(2UL, buckets.size());
// Full bucket (2 - 1)
EXPECT_EQ(1, buckets[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, buckets[0].mConditionTrueNs);
// Full bucket (5 - 3)
EXPECT_EQ(3, buckets[1].values[0].long_value);
+ // partial bucket [bucket2StartTimeNs, bucket2StartTimeNs + 2]
+ EXPECT_EQ(2, buckets[1].mConditionTrueNs);
}
/*
@@ -385,6 +398,7 @@
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -402,6 +416,7 @@
EXPECT_EQ(8, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -420,6 +435,7 @@
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
}
/*
@@ -468,6 +484,7 @@
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second.back().mConditionTrueNs);
allData.clear();
event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -485,14 +502,16 @@
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[1].mConditionTrueNs);
}
/*
* Tests pulled atoms with no conditions and take zero value after reset
*/
TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
- ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
@@ -546,6 +565,7 @@
EXPECT_EQ(26, curInterval.value.long_value);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, valueProducer->mPastBuckets.begin()->second[0].mConditionTrueNs);
}
/*
@@ -574,6 +594,15 @@
event->init();
data->push_back(event);
return true;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+ event->write(tagId);
+ event->write(180);
+ event->init();
+ data->push_back(event);
+ return true;
}));
sp<ValueMetricProducer> valueProducer =
@@ -598,7 +627,7 @@
event->init();
allData.push_back(event);
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -609,7 +638,7 @@
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10}, {bucketSizeNs - 8});
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -617,6 +646,9 @@
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(20, curInterval.value.long_value);
EXPECT_EQ(false, curInterval.hasBase);
+
+ valueProducer->onConditionChanged(true, bucket3StartTimeNs + 1);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {10, 20}, {bucketSizeNs - 8, 1});
}
TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
@@ -705,8 +737,7 @@
valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
- EXPECT_EQ(20L,
- valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20}, {150});
allData.clear();
event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -719,10 +750,12 @@
EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(20L,
valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {20, 30},
+ {150, bucketSizeNs - 150});
}
TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
- ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
metric.set_split_bucket_for_app_upgrade(false);
UidMap uidMap;
@@ -791,8 +824,10 @@
// Expect one full buckets already done and starting a partial bucket.
EXPECT_EQ(bucket2StartTimeNs-50, valueProducer->mCurrentBucketStartTimeNs);
EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
- EXPECT_EQ(bucketStartTimeNs, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
- EXPECT_EQ(20L, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+ EXPECT_EQ(bucketStartTimeNs,
+ valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20},
+ {(bucket2StartTimeNs - 100) - (bucketStartTimeNs + 1)});
EXPECT_FALSE(valueProducer->mCondition);
}
@@ -835,7 +870,7 @@
EXPECT_EQ(30, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30});
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {30}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
@@ -872,7 +907,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(20, curInterval.value.long_value);
@@ -900,7 +936,7 @@
EXPECT_EQ(50, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50});
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {50}, {20});
}
TEST(ValueMetricProducerTest, TestAnomalyDetection) {
@@ -1008,7 +1044,8 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:true sum:0 start:11
EXPECT_EQ(true, curInterval.hasBase);
@@ -1031,7 +1068,7 @@
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(23, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
// pull 3 come late.
// The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1050,7 +1087,7 @@
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(36, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs});
}
/*
@@ -1089,7 +1126,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(100, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1098,7 +1136,7 @@
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
EXPECT_EQ(false, curInterval.hasBase);
// Now the alarm is delivered.
@@ -1107,7 +1145,7 @@
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 30, 110));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1160,7 +1198,8 @@
// has one slice
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer->mCurrentSlicedBucket.begin()->second[0];
// startUpdated:false sum:0 start:100
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(100, curInterval.base.long_value);
@@ -1169,7 +1208,7 @@
// pull on bucket boundary come late, condition change happens before it
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(false, curInterval.hasBase);
@@ -1177,7 +1216,7 @@
// condition changed to true again, before the pull alarm is delivered
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(130, curInterval.base.long_value);
@@ -1194,12 +1233,13 @@
EXPECT_EQ(140, curInterval.base.long_value);
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(10, curInterval.value.long_value);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20}, {bucketSizeNs - 8});
allData.clear();
allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs, 160));
valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {20, 30},
+ {bucketSizeNs - 8, bucketSizeNs - 24});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
@@ -1230,7 +1270,8 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1242,7 +1283,7 @@
EXPECT_EQ(10, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10});
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {10}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
@@ -1273,7 +1314,8 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1335,7 +1377,9 @@
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value - 12.5) < epsilon);
+
+ EXPECT_TRUE(std::abs(valueProducer.mPastBuckets.begin()->second.back().values[0].double_value -
+ 12.5) < epsilon);
}
TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
@@ -1366,7 +1410,8 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(10, curInterval.value.long_value);
EXPECT_EQ(true, curInterval.hasValue);
@@ -1378,7 +1423,7 @@
EXPECT_EQ(25, curInterval.value.long_value);
valueProducer.flushIfNeededLocked(bucket2StartTimeNs);
- assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25});
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {25}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
@@ -1410,7 +1455,8 @@
valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
// has one slice
EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
- ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+ ValueMetricProducer::Interval curInterval =
+ valueProducer.mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasBase);
EXPECT_EQ(10, curInterval.base.long_value);
EXPECT_EQ(false, curInterval.hasValue);
@@ -1449,7 +1495,7 @@
valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
- EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer.mPastBuckets, {5}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
@@ -1546,11 +1592,13 @@
EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+ EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[0].mConditionTrueNs);
EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
+ EXPECT_EQ(bucketSizeNs, valueProducer.mPastBuckets.begin()->second[1].mConditionTrueNs);
EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
}
@@ -1625,8 +1673,10 @@
EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
auto iterator = valueProducer->mPastBuckets.begin();
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
EXPECT_EQ(8, iterator->second[0].values[0].long_value);
iterator++;
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
EXPECT_EQ(4, iterator->second[0].values[0].long_value);
}
@@ -1795,7 +1845,7 @@
EXPECT_EQ(false, interval1.hasValue);
EXPECT_EQ(8, interval1.value.long_value);
EXPECT_FALSE(interval1.seenNewData);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
auto it = valueProducer->mCurrentSlicedBucket.begin();
for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
@@ -1810,7 +1860,7 @@
EXPECT_EQ(4, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
// next pull somehow did not happen, skip to end of bucket 3
allData.clear();
@@ -1828,7 +1878,7 @@
EXPECT_EQ(5, interval2.base.long_value);
EXPECT_EQ(false, interval2.hasValue);
EXPECT_FALSE(interval2.seenNewData);
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {8}, {bucketSizeNs});
allData.clear();
event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1846,8 +1896,10 @@
ASSERT_EQ(2UL, valueProducer->mPastBuckets.size());
auto iterator = valueProducer->mPastBuckets.begin();
EXPECT_EQ(9, iterator->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
iterator++;
EXPECT_EQ(8, iterator->second[0].values[0].long_value);
+ EXPECT_EQ(bucketSizeNs, iterator->second[0].mConditionTrueNs);
}
TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
@@ -1932,6 +1984,15 @@
EXPECT_CALL(*pullerManager, Pull(tagId, _))
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
+ shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+ event->write(tagId);
+ event->write(50);
+ event->init();
+ data->push_back(event);
+ return false;
+ }))
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
event->write(tagId);
event->write(100);
@@ -1943,10 +2004,11 @@
sp<ValueMetricProducer> valueProducer =
ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kTrue;
+ // Don't directly set mCondition; the real code never does that. Go through regular code path
+ // to avoid unexpected behaviors.
+ // valueProducer->mCondition = ConditionState::kTrue;
+ valueProducer->onConditionChanged(true, bucketStartTimeNs);
- vector<shared_ptr<LogEvent>> allData;
- valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
@@ -2406,7 +2468,7 @@
EXPECT_EQ(true, valueProducer->mHasGlobalBase);
EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
- EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {1}, {bucketSizeNs - 12 + 1});
}
TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
@@ -2539,13 +2601,15 @@
// Second onConditionChanged.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 10, 5));
return true;
}))
// Third onConditionChanged.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 10, 7));
return true;
}));
@@ -2572,7 +2636,7 @@
valueProducer->onConditionChanged(false, bucket3StartTimeNs + 10);
// Bucket should have been completed.
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {bucketSizeNs - 10});
}
TEST(ValueMetricProducerTest, TestLateOnDataPulledWithoutDiff) {
@@ -2592,7 +2656,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// Bucket should have been completed.
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {30}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestLateOnDataPulledWithDiff) {
@@ -2619,7 +2683,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// Bucket should have been completed.
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {19}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestBucketBoundariesOnAppUpgrade) {
@@ -2636,7 +2700,8 @@
// notifyAppUpgrade.
.WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
data->clear();
- data->push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
+ data->push_back(
+ ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 2, 10));
return true;
}));
@@ -2646,7 +2711,7 @@
valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
// Bucket should have been completed.
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {bucketSizeNs});
}
TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
@@ -2678,6 +2743,12 @@
auto curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
EXPECT_EQ(true, curInterval.hasValue);
EXPECT_EQ(2, curInterval.value.long_value);
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket2StartTimeNs + 1, 10));
+ valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 1);
+
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {2}, {2});
}
TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
@@ -2724,7 +2795,7 @@
valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
// There was not global base available so all buckets are invalid.
- assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {});
+ assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {}, {});
}
static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
@@ -2890,6 +2961,7 @@
EXPECT_EQ(1, report.value_metrics().data_size());
EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+ EXPECT_EQ(10, report.value_metrics().data(0).bucket_info(0).condition_true_nanos());
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 54fe65d..9079ace 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -132,6 +132,7 @@
import android.widget.Toast;
import android.widget.Toolbar;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
@@ -4904,6 +4905,17 @@
mTaskDescription.setNavigationBarColor(navigationBarColor);
}
+ final int targetSdk = getApplicationInfo().targetSdkVersion;
+ final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
+ if (!targetPreQ) {
+ mTaskDescription.setEnsureStatusBarContrastWhenTransparent(a.getBoolean(
+ R.styleable.ActivityTaskDescription_ensureStatusBarContrastWhenTransparent,
+ false));
+ mTaskDescription.setEnsureNavigationBarContrastWhenTransparent(a.getBoolean(
+ R.styleable.ActivityTaskDescription_ensureNavigationBarContrastWhenTransparent,
+ true));
+ }
+
a.recycle();
setTaskDescription(mTaskDescription);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 395c867..b80f781 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -986,6 +986,8 @@
private int mColorBackground;
private int mStatusBarColor;
private int mNavigationBarColor;
+ private boolean mEnsureStatusBarContrastWhenTransparent;
+ private boolean mEnsureNavigationBarContrastWhenTransparent;
/**
* Creates the TaskDescription to the specified values.
@@ -998,7 +1000,7 @@
*/
@Deprecated
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
- this(label, icon, 0, null, colorPrimary, 0, 0, 0);
+ this(label, icon, 0, null, colorPrimary, 0, 0, 0, false, false);
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
throw new RuntimeException("A TaskDescription's primary color should be opaque");
}
@@ -1014,7 +1016,7 @@
* opaque.
*/
public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
- this(label, null, iconRes, null, colorPrimary, 0, 0, 0);
+ this(label, null, iconRes, null, colorPrimary, 0, 0, 0, false, false);
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
throw new RuntimeException("A TaskDescription's primary color should be opaque");
}
@@ -1029,7 +1031,7 @@
*/
@Deprecated
public TaskDescription(String label, Bitmap icon) {
- this(label, icon, 0, null, 0, 0, 0, 0);
+ this(label, icon, 0, null, 0, 0, 0, 0, false, false);
}
/**
@@ -1040,7 +1042,7 @@
* activity.
*/
public TaskDescription(String label, @DrawableRes int iconRes) {
- this(label, null, iconRes, null, 0, 0, 0, 0);
+ this(label, null, iconRes, null, 0, 0, 0, 0, false, false);
}
/**
@@ -1049,19 +1051,21 @@
* @param label A label and description of the current state of this activity.
*/
public TaskDescription(String label) {
- this(label, null, 0, null, 0, 0, 0, 0);
+ this(label, null, 0, null, 0, 0, 0, 0, false, false);
}
/**
* Creates an empty TaskDescription.
*/
public TaskDescription() {
- this(null, null, 0, null, 0, 0, 0, 0);
+ this(null, null, 0, null, 0, 0, 0, 0, false, false);
}
/** @hide */
public TaskDescription(String label, Bitmap bitmap, int iconRes, String iconFilename,
- int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor) {
+ int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor,
+ boolean ensureStatusBarContrastWhenTransparent,
+ boolean ensureNavigationBarContrastWhenTransparent) {
mLabel = label;
mIcon = bitmap;
mIconRes = iconRes;
@@ -1070,6 +1074,9 @@
mColorBackground = colorBackground;
mStatusBarColor = statusBarColor;
mNavigationBarColor = navigationBarColor;
+ mEnsureStatusBarContrastWhenTransparent = ensureStatusBarContrastWhenTransparent;
+ mEnsureNavigationBarContrastWhenTransparent =
+ ensureNavigationBarContrastWhenTransparent;
}
/**
@@ -1092,6 +1099,9 @@
mColorBackground = other.mColorBackground;
mStatusBarColor = other.mStatusBarColor;
mNavigationBarColor = other.mNavigationBarColor;
+ mEnsureStatusBarContrastWhenTransparent = other.mEnsureStatusBarContrastWhenTransparent;
+ mEnsureNavigationBarContrastWhenTransparent =
+ other.mEnsureNavigationBarContrastWhenTransparent;
}
/**
@@ -1114,6 +1124,9 @@
if (other.mNavigationBarColor != 0) {
mNavigationBarColor = other.mNavigationBarColor;
}
+ mEnsureStatusBarContrastWhenTransparent = other.mEnsureStatusBarContrastWhenTransparent;
+ mEnsureNavigationBarContrastWhenTransparent =
+ other.mEnsureNavigationBarContrastWhenTransparent;
}
private TaskDescription(Parcel source) {
@@ -1272,6 +1285,37 @@
return mNavigationBarColor;
}
+ /**
+ * @hide
+ */
+ public boolean getEnsureStatusBarContrastWhenTransparent() {
+ return mEnsureStatusBarContrastWhenTransparent;
+ }
+
+ /**
+ * @hide
+ */
+ public void setEnsureStatusBarContrastWhenTransparent(
+ boolean ensureStatusBarContrastWhenTransparent) {
+ mEnsureStatusBarContrastWhenTransparent = ensureStatusBarContrastWhenTransparent;
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getEnsureNavigationBarContrastWhenTransparent() {
+ return mEnsureNavigationBarContrastWhenTransparent;
+ }
+
+ /**
+ * @hide
+ */
+ public void setEnsureNavigationBarContrastWhenTransparent(
+ boolean ensureNavigationBarContrastWhenTransparent) {
+ mEnsureNavigationBarContrastWhenTransparent =
+ ensureNavigationBarContrastWhenTransparent;
+ }
+
/** @hide */
public void saveToXml(XmlSerializer out) throws IOException {
if (mLabel != null) {
@@ -1332,6 +1376,8 @@
dest.writeInt(mColorBackground);
dest.writeInt(mStatusBarColor);
dest.writeInt(mNavigationBarColor);
+ dest.writeBoolean(mEnsureStatusBarContrastWhenTransparent);
+ dest.writeBoolean(mEnsureNavigationBarContrastWhenTransparent);
if (mIconFilename == null) {
dest.writeInt(0);
} else {
@@ -1348,6 +1394,8 @@
mColorBackground = source.readInt();
mStatusBarColor = source.readInt();
mNavigationBarColor = source.readInt();
+ mEnsureStatusBarContrastWhenTransparent = source.readBoolean();
+ mEnsureNavigationBarContrastWhenTransparent = source.readBoolean();
mIconFilename = source.readInt() > 0 ? source.readString() : null;
}
@@ -1366,8 +1414,11 @@
return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
" IconRes: " + mIconRes + " IconFilename: " + mIconFilename +
" colorPrimary: " + mColorPrimary + " colorBackground: " + mColorBackground +
- " statusBarColor: " + mColorBackground +
- " navigationBarColor: " + mNavigationBarColor;
+ " statusBarColor: " + mStatusBarColor + (
+ mEnsureStatusBarContrastWhenTransparent ? " (contrast when transparent)"
+ : "") + " navigationBarColor: " + mNavigationBarColor + (
+ mEnsureNavigationBarContrastWhenTransparent
+ ? " (contrast when transparent)" : "");
}
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 7884872..b3c2429 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -70,9 +70,9 @@
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
- List<String> getAllowedAssistantCapabilities(String pkg);
- void allowAssistantCapability(String adjustmentType);
- void disallowAssistantCapability(String adjustmentType);
+ List<String> getAllowedAssistantAdjustments(String pkg);
+ void allowAssistantAdjustment(String adjustmentType);
+ void disallowAssistantAdjustment(String adjustmentType);
boolean shouldHideSilentStatusIcons(String callingPkg);
void setHideSilentStatusIcons(boolean hide);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index d54aca8..dd39376 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1206,10 +1206,10 @@
*/
@SystemApi
@TestApi
- public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() {
+ public @NonNull @Adjustment.Keys List<String> getAllowedAssistantAdjustments() {
INotificationManager service = getService();
try {
- return service.getAllowedAssistantCapabilities(mContext.getOpPackageName());
+ return service.getAllowedAssistantAdjustments(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1219,10 +1219,10 @@
* @hide
*/
@TestApi
- public void allowAssistantCapability(String capability) {
+ public void allowAssistantAdjustment(String capability) {
INotificationManager service = getService();
try {
- service.allowAssistantCapability(capability);
+ service.allowAssistantAdjustment(capability);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1232,10 +1232,10 @@
* @hide
*/
@TestApi
- public void disallowAssistantCapability(String capability) {
+ public void disallowAssistantAdjustment(String capability) {
INotificationManager service = getService();
try {
- service.disallowAssistantCapability(capability);
+ service.disallowAssistantAdjustment(capability);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index b8a741a..31bbd16 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -20,6 +20,7 @@
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -37,7 +38,6 @@
import android.content.Context;
import android.os.BatteryStats;
import android.os.Binder;
-import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
@@ -61,6 +61,7 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -650,7 +651,7 @@
private final Object mLock = new Object();
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
- private static final Map<BluetoothDevice, List<Pair<MetadataListener, Handler>>>
+ private static final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
sMetadataListeners = new HashMap<>();
/**
@@ -660,14 +661,15 @@
private static final IBluetoothMetadataListener sBluetoothMetadataListener =
new IBluetoothMetadataListener.Stub() {
@Override
- public void onMetadataChanged(BluetoothDevice device, int key, String value) {
+ public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
synchronized (sMetadataListeners) {
if (sMetadataListeners.containsKey(device)) {
- List<Pair<MetadataListener, Handler>> list = sMetadataListeners.get(device);
- for (Pair<MetadataListener, Handler> pair : list) {
- MetadataListener listener = pair.first;
- Handler handler = pair.second;
- handler.post(() -> {
+ List<Pair<OnMetadataChangedListener, Executor>> list =
+ sMetadataListeners.get(device);
+ for (Pair<OnMetadataChangedListener, Executor> pair : list) {
+ OnMetadataChangedListener listener = pair.first;
+ Executor executor = pair.second;
+ executor.execute(() -> {
listener.onMetadataChanged(device, key, value);
});
}
@@ -3153,30 +3155,30 @@
}
/**
- * Register a {@link #MetadataListener} to receive update about metadata
+ * Register a {@link #OnMetadataChangedListener} to receive update about metadata
* changes for this {@link BluetoothDevice}.
* Registration must be done when Bluetooth is ON and will last until
- * {@link #unregisterMetadataListener(BluetoothDevice)} is called, even when Bluetooth
+ * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
* restarted in the middle.
* All input parameters should not be null or {@link NullPointerException} will be triggered.
- * The same {@link BluetoothDevice} and {@link #MetadataListener} pair can only be registered
- * once, double registration would cause {@link IllegalArgumentException}.
+ * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
+ * registered once, double registration would cause {@link IllegalArgumentException}.
*
* @param device {@link BluetoothDevice} that will be registered
- * @param listener {@link #MetadataListener} that will receive asynchronous callbacks
- * @param handler the handler for listener callback
+ * @param executor the executor for listener callback
+ * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
* @return true on success, false on error
- * @throws NullPointerException If one of {@code listener}, {@code device} or {@code handler}
+ * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
* is null.
- * @throws IllegalArgumentException The same {@link #MetadataListener} and
+ * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
* {@link BluetoothDevice} are registered twice.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean registerMetadataListener(BluetoothDevice device, MetadataListener listener,
- Handler handler) {
- if (DBG) Log.d(TAG, "registerMetdataListener()");
+ public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
+ @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
+ if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
final IBluetooth service = mService;
if (service == null) {
@@ -3189,14 +3191,15 @@
if (device == null) {
throw new NullPointerException("device is null");
}
- if (handler == null) {
- throw new NullPointerException("handler is null");
+ if (executor == null) {
+ throw new NullPointerException("executor is null");
}
synchronized (sMetadataListeners) {
- List<Pair<MetadataListener, Handler>> listenerList = sMetadataListeners.get(device);
+ List<Pair<OnMetadataChangedListener, Executor>> listenerList =
+ sMetadataListeners.get(device);
if (listenerList == null) {
- // Create new listener/handler list for registeration
+ // Create new listener/executor list for registeration
listenerList = new ArrayList<>();
sMetadataListeners.put(device, listenerList);
} else {
@@ -3207,7 +3210,7 @@
}
}
- Pair<MetadataListener, Handler> listenerPair = new Pair(listener, handler);
+ Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
listenerList.add(listenerPair);
boolean ret = false;
@@ -3230,63 +3233,74 @@
}
/**
- * Unregister all {@link MetadataListener} from this {@link BluetoothDevice}.
+ * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
* Unregistration can be done when Bluetooth is either ON or OFF.
- * {@link #registerMetadataListener(MetadataListener, BluetoothDevice, Handler)} must
- * be called before unregisteration.
- * Unregistering a device that is not regestered would cause {@link IllegalArgumentException}.
+ * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
+ * must be called before unregisteration.
*
- * @param device {@link BluetoothDevice} that will be unregistered. it
+ * @param device {@link BluetoothDevice} that will be unregistered. It
+ * should not be null or {@link NullPointerException} will be triggered.
+ * @param listener {@link OnMetadataChangedListener} that will be unregistered. It
* should not be null or {@link NullPointerException} will be triggered.
* @return true on success, false on error
- * @throws NullPointerException If {@code device} is null.
+ * @throws NullPointerException If {@code listener} or {@code device} is null.
* @throws IllegalArgumentException If {@code device} has not been registered before.
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean unregisterMetadataListener(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "unregisterMetdataListener()");
+ public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
+ @NonNull OnMetadataChangedListener listener) {
+ if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
if (device == null) {
throw new NullPointerException("device is null");
}
+ if (listener == null) {
+ throw new NullPointerException("listener is null");
+ }
synchronized (sMetadataListeners) {
- if (sMetadataListeners.containsKey(device)) {
- sMetadataListeners.remove(device);
- } else {
+ if (!sMetadataListeners.containsKey(device)) {
throw new IllegalArgumentException("device was not registered");
}
+ // Remove issued listener from the registered device
+ sMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
- final IBluetooth service = mService;
- if (service == null) {
- // Bluetooth is OFF, do nothing to Bluetooth service.
- return true;
- }
- try {
- return service.unregisterMetadataListener(device);
- } catch (RemoteException e) {
- Log.e(TAG, "unregisterMetadataListener fail", e);
- return false;
+ if (sMetadataListeners.get(device).isEmpty()) {
+ // Unregister to Bluetooth service if all listeners are removed from
+ // the registered device
+ sMetadataListeners.remove(device);
+ final IBluetooth service = mService;
+ if (service == null) {
+ // Bluetooth is OFF, do nothing to Bluetooth service.
+ return true;
+ }
+ try {
+ return service.unregisterMetadataListener(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, "unregisterMetadataListener fail", e);
+ return false;
+ }
}
}
+ return true;
}
/**
- * This abstract class is used to implement {@link BluetoothAdapter} metadata listener.
+ * This interface is used to implement {@link BluetoothAdapter} metadata listener.
* @hide
*/
@SystemApi
- public abstract static class MetadataListener {
+ public interface OnMetadataChangedListener {
/**
* Callback triggered if the metadata of {@link BluetoothDevice} registered in
- * {@link #registerMetadataListener}.
+ * {@link #addOnMetadataChangedListener}.
*
* @param device changed {@link BluetoothDevice}.
* @param key changed metadata key, one of BluetoothDevice.METADATA_*.
- * @param value the new value of metadata.
+ * @param value the new value of metadata as byte array.
*/
- public void onMetadataChanged(BluetoothDevice device, int key, String value) {
- }
+ void onMetadataChanged(@NonNull BluetoothDevice device, int key,
+ @Nullable byte[] value);
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 204d7e3..74ceeb9 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -351,6 +352,7 @@
/**
* Manufacturer name of this Bluetooth device
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
@@ -358,6 +360,7 @@
/**
* Model name of this Bluetooth device
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
@@ -365,6 +368,7 @@
/**
* Software version of this Bluetooth device
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
@@ -372,6 +376,7 @@
/**
* Hardware version of this Bluetooth device
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
@@ -379,6 +384,7 @@
/**
* Package name of the companion app, if any
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
@@ -386,6 +392,7 @@
/**
* URI to the main icon shown on the settings UI
+ * Data type should be {@link Byte} array.
* @hide
*/
@SystemApi
@@ -393,80 +400,91 @@
/**
* Whether this device is an untethered headset with left, right and case
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_IS_UNTHETHERED_HEADSET = 6;
+ public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
/**
* URI to icon of the left headset
+ * Data type should be {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_LEFT_ICON = 7;
+ public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
/**
* URI to icon of the right headset
+ * Data type should be {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_RIGHT_ICON = 8;
+ public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
/**
* URI to icon of the headset charging case
+ * Data type should be {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_CASE_ICON = 9;
+ public static final int METADATA_UNTETHERED_CASE_ICON = 9;
/**
- * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
- * is invalid, of the left headset
+ * Battery level of left headset
+ * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+ * as invalid.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_LEFT_BATTERY = 10;
+ public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
/**
- * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
- * is invalid, of the right headset
+ * Battery level of rigth headset
+ * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+ * as invalid.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_RIGHT_BATTERY = 11;
+ public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
/**
- * Battery level (0-100), {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
- * is invalid, of the headset charging case
+ * Battery level of the headset charging case
+ * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
+ * as invalid.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_CASE_BATTERY = 12;
+ public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
/**
* Whether the left headset is charging
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_LEFT_CHARGING = 13;
+ public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
/**
* Whether the right headset is charging
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_RIGHT_CHARGING = 14;
+ public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
/**
* Whether the headset charging case is charging
+ * Data type should be {@String} as {@link Byte} array.
* @hide
*/
@SystemApi
- public static final int METADATA_UNTHETHERED_CASE_CHARGING = 15;
+ public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
/**
- * URI to the enhanced settings UI slice, null or empty String means
- * the UI does not exist
+ * URI to the enhanced settings UI slice
+ * Data type should be {@String} as {@link Byte} array, null means
+ * the UI does not exist.
* @hide
*/
@SystemApi
@@ -2243,21 +2261,21 @@
* {@link #BOND_NONE}.
*
* @param key must be within the list of BluetoothDevice.METADATA_*
- * @param value the string data to set for key. Must be less than
+ * @param value a byte array data to set for key. Must be less than
* {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
* @return true on success, false on error
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean setMetadata(int key, String value) {
+ public boolean setMetadata(int key, @NonNull byte[] value) {
final IBluetooth service = sService;
if (service == null) {
Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
return false;
}
- if (value.length() > METADATA_MAX_LENGTH) {
- throw new IllegalArgumentException("value length is " + value.length()
+ if (value.length > METADATA_MAX_LENGTH) {
+ throw new IllegalArgumentException("value length is " + value.length
+ ", should not over " + METADATA_MAX_LENGTH);
}
try {
@@ -2272,12 +2290,13 @@
* Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
*
* @param key must be within the list of BluetoothDevice.METADATA_*
- * @return Metadata of the key as string, null on error or not found
+ * @return Metadata of the key as byte array, null on error or not found
* @hide
*/
@SystemApi
+ @Nullable
@RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public String getMetadata(int key) {
+ public byte[] getMetadata(int key) {
final IBluetooth service = sService;
if (service == null) {
Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 7fe840c..a71f7d2 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -30,7 +30,6 @@
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager.DeleteFlags;
import android.content.pm.PackageManager.InstallReason;
@@ -504,12 +503,14 @@
*
* <p>Staged session is active iff:
* <ul>
- * <li>It is committed.
- * <li>It is not applied.
- * <li>It is not failed.
+ * <li>It is committed, i.e. {@link SessionInfo#isCommitted()} is {@code true}, and
+ * <li>it is not applied, i.e. {@link SessionInfo#isStagedSessionApplied()} is {@code
+ * false}, and
+ * <li>it is not failed, i.e. {@link SessionInfo#isStagedSessionFailed()} is {@code false}.
* </ul>
*
- * <p>In case of a multi-apk session, parent session will be returned.
+ * <p>In case of a multi-apk session, reasoning above is applied to the parent session, since
+ * that is the one that should been {@link Session#commit committed}.
*/
public @Nullable SessionInfo getActiveStagedSession() {
final List<SessionInfo> stagedSessions = getStagedSessions();
@@ -2307,7 +2308,8 @@
}
/**
- * Whenever this session was committed.
+ * Returns {@code true} if {@link Session#commit(IntentSender)}} was called for this
+ * session.
*/
public boolean isCommitted() {
return isCommitted;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b2b4e0e..bdd80e32 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -591,6 +591,8 @@
*/
public interface Callback {
boolean hasFeature(String feature);
+ String[] getOverlayPaths(String targetPackageName, String targetPath);
+ String[] getOverlayApks(String targetPackageName);
}
/**
@@ -607,6 +609,14 @@
@Override public boolean hasFeature(String feature) {
return mPm.hasSystemFeature(feature);
}
+
+ @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
+ return null;
+ }
+
+ @Override public String[] getOverlayApks(String targetPackageName) {
+ return null;
+ }
}
/**
@@ -1158,7 +1168,19 @@
}
final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
- return fromCacheEntry(bytes);
+ Package p = fromCacheEntry(bytes);
+ if (mCallback != null) {
+ String[] overlayApks = mCallback.getOverlayApks(p.packageName);
+ if (overlayApks != null && overlayApks.length > 0) {
+ for (String overlayApk : overlayApks) {
+ // If a static RRO is updated, return null.
+ if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
+ return null;
+ }
+ }
+ }
+ }
+ return p;
} catch (Throwable e) {
Slog.w(TAG, "Error reading package cache: ", e);
@@ -1332,7 +1354,7 @@
final Resources res = new Resources(assets, mMetrics, null);
final String[] outError = new String[1];
- final Package pkg = parseBaseApk(res, parser, flags, outError);
+ final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
@@ -1895,6 +1917,7 @@
* need to consider whether they should be supported by split APKs and child
* packages.
*
+ * @param apkPath The package apk file path
* @param res The resources from which to resolve values
* @param parser The manifest parser
* @param flags Flags how to parse
@@ -1904,7 +1927,8 @@
* @throws XmlPullParserException
* @throws IOException
*/
- private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
@@ -1924,6 +1948,15 @@
return null;
}
+ if (mCallback != null) {
+ String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
+ if (overlayPaths != null && overlayPaths.length > 0) {
+ for (String overlayPath : overlayPaths) {
+ res.getAssets().addOverlayPath(overlayPath);
+ }
+ }
+ }
+
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6e89797..e3b2d89 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -955,6 +955,20 @@
"android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
/**
+ * Activity Action: Open the advanced power usage details page of an associated app.
+ * <p>
+ * Input: Intent's data URI set with an application name, using the
+ * "package" schema (like "package:com.my.app")
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL =
+ "android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL";
+
+ /**
* Activity Action: Show screen for controlling background data
* restrictions for a particular application.
* <p>
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 8bb5f97..5977baf 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -53,5 +53,5 @@
void onNotificationDirectReply(String key);
void onSuggestedReplySent(String key, in CharSequence reply, int source);
void onActionClicked(String key, in Notification.Action action, int source);
- void onCapabilitiesChanged();
+ void onAllowedAdjustmentsChanged();
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index b4fd397..cafeb87 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -220,10 +220,10 @@
/**
* Implement this to know when a user has changed which features of
* their notifications the assistant can modify.
- * <p> Query {@link NotificationManager#getAllowedAssistantCapabilities()} to see what
+ * <p> Query {@link NotificationManager#getAllowedAssistantAdjustments()} to see what
* {@link Adjustment adjustments} you are currently allowed to make.</p>
*/
- public void onCapabilitiesChanged() {
+ public void onAllowedAdjustmentsChanged() {
}
/**
@@ -361,8 +361,8 @@
}
@Override
- public void onCapabilitiesChanged() {
- mHandler.obtainMessage(MyHandler.MSG_ON_CAPABILITIES_CHANGED).sendToTarget();
+ public void onAllowedAdjustmentsChanged() {
+ mHandler.obtainMessage(MyHandler.MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED).sendToTarget();
}
}
@@ -374,7 +374,7 @@
public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5;
public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6;
public static final int MSG_ON_ACTION_INVOKED = 7;
- public static final int MSG_ON_CAPABILITIES_CHANGED = 8;
+ public static final int MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED = 8;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -456,8 +456,8 @@
onActionInvoked(key, action, source);
break;
}
- case MSG_ON_CAPABILITIES_CHANGED: {
- onCapabilitiesChanged();
+ case MSG_ON_ALLOWED_ADJUSTMENTS_CHANGED: {
+ onAllowedAdjustmentsChanged();
break;
}
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 6780723..3ec21e3 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1400,7 +1400,7 @@
}
@Override
- public void onCapabilitiesChanged() {
+ public void onAllowedAdjustmentsChanged() {
// no-op in the listener
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 3544a87..a9463e9 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2329,6 +2329,70 @@
return 0;
}
+ /**
+ * Sets whether the system should ensure that the status bar has enough
+ * contrast when a fully transparent background is requested.
+ *
+ * <p>If set to this value, the system will determine whether a scrim is necessary
+ * to ensure that the status bar has enough contrast with the contents of
+ * this app, and set an appropriate effective bar background color accordingly.
+ *
+ * <p>When the status bar color has a non-zero alpha value, the value of this
+ * property has no effect.
+ *
+ * @see android.R.attr#ensureStatusBarContrastWhenTransparent
+ * @hide pending API
+ */
+ public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) {
+ }
+
+ /**
+ * Returns whether the system is ensuring that the status bar has enough contrast when a
+ * fully transparent background is requested.
+ *
+ * <p>When the status bar color has a non-zero alpha value, the value of this
+ * property has no effect.
+ *
+ * @see android.R.attr#ensureStatusBarContrastWhenTransparent
+ * @return true, if the system is ensuring contrast, false otherwise.
+ * @hide pending API
+ */
+ public boolean isEnsureStatusBarContrastWhenTransparent() {
+ return false;
+ }
+
+ /**
+ * Sets whether the system should ensure that the navigation bar has enough
+ * contrast when a fully transparent background is requested.
+ *
+ * <p>If set to this value, the system will determine whether a scrim is necessary
+ * to ensure that the navigation bar has enough contrast with the contents of
+ * this app, and set an appropriate effective bar background color accordingly.
+ *
+ * <p>When the navigation bar color has a non-zero alpha value, the value of this
+ * property has no effect.
+ *
+ * @see android.R.attr#ensureNavigationBarContrastWhenTransparent
+ * @hide pending API
+ */
+ public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) {
+ }
+
+ /**
+ * Returns whether the system is ensuring that the navigation bar has enough contrast when a
+ * fully transparent background is requested.
+ *
+ * <p>When the navigation bar color has a non-zero alpha value, the value of this
+ * property has no effect.
+ *
+ * @return true, if the system is ensuring contrast, false otherwise.
+ * @see android.R.attr#ensureNavigationBarContrastWhenTransparent
+ * @hide pending API
+ */
+ public boolean isEnsureNavigationBarContrastWhenTransparent() {
+ return false;
+ }
+
/** @hide */
public void setTheme(int resId) {
}
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
deleted file mode 100644
index bf151c3..0000000
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ /dev/null
@@ -1,228 +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
- */
-
-package com.android.internal.colorextraction.drawable;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.RadialGradient;
-import android.graphics.Rect;
-import android.graphics.Shader;
-import android.graphics.Xfermode;
-import android.graphics.drawable.Drawable;
-import android.view.animation.DecelerateInterpolator;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.graphics.ColorUtils;
-
-/**
- * Draws a gradient based on a Palette
- */
-public class GradientDrawable extends Drawable {
- private static final String TAG = "GradientDrawable";
-
- private static final float CENTRALIZED_CIRCLE_1 = -2;
- private static final int GRADIENT_RADIUS = 480; // in dp
- private static final long COLOR_ANIMATION_DURATION = 2000;
-
- private int mAlpha = 255;
-
- private float mDensity;
- private final Paint mPaint;
- private final Rect mWindowBounds;
- private final Splat mSplat;
-
- private int mMainColor;
- private int mSecondaryColor;
- private ValueAnimator mColorAnimation;
- private int mMainColorTo;
- private int mSecondaryColorTo;
-
- public GradientDrawable(@NonNull Context context) {
- mDensity = context.getResources().getDisplayMetrics().density;
- mSplat = new Splat(0.50f, 1.00f, GRADIENT_RADIUS, CENTRALIZED_CIRCLE_1);
- mWindowBounds = new Rect();
-
- mPaint = new Paint();
- mPaint.setStyle(Paint.Style.FILL);
- }
-
- public void setColors(@NonNull ColorExtractor.GradientColors colors) {
- setColors(colors.getMainColor(), colors.getSecondaryColor(), true);
- }
-
- public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
- setColors(colors.getMainColor(), colors.getSecondaryColor(), animated);
- }
-
- public void setColors(int mainColor, int secondaryColor, boolean animated) {
- if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
- return;
- }
-
- if (mColorAnimation != null && mColorAnimation.isRunning()) {
- mColorAnimation.cancel();
- }
-
- mMainColorTo = mainColor;
- mSecondaryColorTo = mainColor;
-
- if (animated) {
- final int mainFrom = mMainColor;
- final int secFrom = mSecondaryColor;
-
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- anim.setDuration(COLOR_ANIMATION_DURATION);
- anim.addUpdateListener(animation -> {
- float ratio = (float) animation.getAnimatedValue();
- mMainColor = ColorUtils.blendARGB(mainFrom, mainColor, ratio);
- mSecondaryColor = ColorUtils.blendARGB(secFrom, secondaryColor, ratio);
- buildPaints();
- invalidateSelf();
- });
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation, boolean isReverse) {
- if (mColorAnimation == animation) {
- mColorAnimation = null;
- }
- }
- });
- anim.setInterpolator(new DecelerateInterpolator());
- anim.start();
- mColorAnimation = anim;
- } else {
- mMainColor = mainColor;
- mSecondaryColor = secondaryColor;
- buildPaints();
- invalidateSelf();
- }
- }
-
- @Override
- public void setAlpha(int alpha) {
- if (alpha != mAlpha) {
- mAlpha = alpha;
- mPaint.setAlpha(mAlpha);
- invalidateSelf();
- }
- }
-
- @Override
- public int getAlpha() {
- return mAlpha;
- }
-
- @Override
- public void setXfermode(@Nullable Xfermode mode) {
- mPaint.setXfermode(mode);
- invalidateSelf();
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
- mPaint.setColorFilter(colorFilter);
- }
-
- @Override
- public ColorFilter getColorFilter() {
- return mPaint.getColorFilter();
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- public void setScreenSize(int width, int height) {
- mWindowBounds.set(0, 0, width, height);
- setBounds(0, 0, width, height);
- buildPaints();
- }
-
- private void buildPaints() {
- Rect bounds = mWindowBounds;
- if (bounds.width() == 0) {
- return;
- }
-
- float w = bounds.width();
- float h = bounds.height();
-
- float x = mSplat.x * w;
- float y = mSplat.y * h;
-
- float radius = mSplat.radius * mDensity;
-
- // When we have only a single alpha gradient, we increase quality
- // (avoiding banding) by merging the background solid color into
- // the gradient directly
- RadialGradient radialGradient = new RadialGradient(x, y, radius,
- mSecondaryColor, mMainColor, Shader.TileMode.CLAMP);
- mPaint.setShader(radialGradient);
- }
-
- @Override
- public void draw(@NonNull Canvas canvas) {
- Rect bounds = mWindowBounds;
- if (bounds.width() == 0) {
- throw new IllegalStateException("You need to call setScreenSize before drawing.");
- }
-
- // Splat each gradient
- float w = bounds.width();
- float h = bounds.height();
-
- float x = mSplat.x * w;
- float y = mSplat.y * h;
-
- float radius = Math.max(w, h);
- canvas.drawRect(x - radius, y - radius, x + radius, y + radius, mPaint);
- }
-
- @VisibleForTesting
- public int getMainColor() {
- return mMainColor;
- }
-
- @VisibleForTesting
- public int getSecondaryColor() {
- return mSecondaryColor;
- }
-
- static final class Splat {
- final float x;
- final float y;
- final float radius;
- final float colorIndex;
-
- Splat(float x, float y, float radius, float colorIndex) {
- this.x = x;
- this.y = y;
- this.radius = radius;
- this.colorIndex = colorIndex;
- }
- }
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
new file mode 100644
index 0000000..7bd7acf
--- /dev/null
+++ b/core/java/com/android/internal/colorextraction/drawable/ScrimDrawable.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.colorextraction.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Xfermode;
+import android.graphics.drawable.Drawable;
+import android.view.animation.DecelerateInterpolator;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
+
+/**
+ * Drawable used on SysUI scrims.
+ */
+public class ScrimDrawable extends Drawable {
+ private static final String TAG = "ScrimDrawable";
+ private static final long COLOR_ANIMATION_DURATION = 2000;
+
+ private final Paint mPaint;
+ private int mAlpha = 255;
+ private int mMainColor;
+ private ValueAnimator mColorAnimation;
+ private int mMainColorTo;
+
+ public ScrimDrawable() {
+ mPaint = new Paint();
+ mPaint.setStyle(Paint.Style.FILL);
+ }
+
+ /**
+ * Sets the background color.
+ * @param mainColor the color.
+ * @param animated if transition should be interpolated.
+ */
+ public void setColor(int mainColor, boolean animated) {
+ if (mainColor == mMainColorTo) {
+ return;
+ }
+
+ if (mColorAnimation != null && mColorAnimation.isRunning()) {
+ mColorAnimation.cancel();
+ }
+
+ mMainColorTo = mainColor;
+
+ if (animated) {
+ final int mainFrom = mMainColor;
+
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ anim.setDuration(COLOR_ANIMATION_DURATION);
+ anim.addUpdateListener(animation -> {
+ float ratio = (float) animation.getAnimatedValue();
+ mMainColor = ColorUtils.blendARGB(mainFrom, mainColor, ratio);
+ invalidateSelf();
+ });
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation, boolean isReverse) {
+ if (mColorAnimation == animation) {
+ mColorAnimation = null;
+ }
+ }
+ });
+ anim.setInterpolator(new DecelerateInterpolator());
+ anim.start();
+ mColorAnimation = anim;
+ } else {
+ mMainColor = mainColor;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (alpha != mAlpha) {
+ mAlpha = alpha;
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ @Override
+ public void setXfermode(@Nullable Xfermode mode) {
+ mPaint.setXfermode(mode);
+ invalidateSelf();
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public ColorFilter getColorFilter() {
+ return mPaint.getColorFilter();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ mPaint.setColor(mMainColor);
+ mPaint.setAlpha(mAlpha);
+ canvas.drawRect(getBounds(), mPaint);
+ }
+
+ @VisibleForTesting
+ public int getMainColor() {
+ return mMainColor;
+ }
+}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index b9aab21..d2e71c8 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.app.WallpaperColors;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Color;
import android.util.Log;
import android.util.MathUtils;
@@ -51,11 +52,13 @@
private static final boolean DEBUG = true;
- public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
- public static final int MAIN_COLOR_DARK = 0xff212121;
+ public static final int MAIN_COLOR_LIGHT = 0xffdadce0;
+ public static final int MAIN_COLOR_DARK = 0xff202124;
+ public static final int MAIN_COLOR_REGULAR = 0xff000000;
private final TonalPalette mGreyPalette;
private final ArrayList<TonalPalette> mTonalPalettes;
+ private final Context mContext;
// Temporary variable to avoid allocations
private float[] mTmpHSL = new float[3];
@@ -64,6 +67,7 @@
ConfigParser parser = new ConfigParser(context);
mTonalPalettes = parser.getTonalPalettes();
+ mContext = context;
mGreyPalette = mTonalPalettes.get(0);
mTonalPalettes.remove(0);
@@ -247,7 +251,20 @@
boolean light = inWallpaperColors != null
&& (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
!= 0;
- final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+ boolean dark = inWallpaperColors != null
+ && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME)
+ != 0;
+ final int color;
+ final boolean inNightMode = (mContext.getResources().getConfiguration().uiMode
+ & android.content.res.Configuration.UI_MODE_NIGHT_MASK)
+ == Configuration.UI_MODE_NIGHT_YES;
+ if (light) {
+ color = MAIN_COLOR_LIGHT;
+ } else if (dark || inNightMode) {
+ color = MAIN_COLOR_DARK;
+ } else {
+ color = MAIN_COLOR_REGULAR;
+ }
final float[] hsl = new float[3];
ColorUtils.colorToHSL(color, hsl);
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index b0855f4..1aef573 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -60,7 +60,7 @@
public static final boolean FW_SYSTEM_USER_SPLIT =
SystemProperties.getBoolean("ro.fw.system_user_split", false);
public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER =
- SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false);
+ SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", true);
// ------ ro.crypto.* -------- //
public static final CryptoProperties.state_values CRYPTO_STATE =
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1c0030d..d945e13 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -38,6 +38,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
+
import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
import android.animation.Animator;
@@ -125,6 +126,8 @@
// The height of a window which has not in DIP.
private final static int DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP = 5;
+ private static final int SCRIM_LIGHT = 0x99ffffff; // 60% white
+
public static final ColorViewAttributes STATUS_BAR_COLOR_VIEW_ATTRIBUTES =
new ColorViewAttributes(SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
Gravity.TOP, Gravity.LEFT, Gravity.RIGHT,
@@ -1237,19 +1240,31 @@
private int calculateStatusBarColor() {
return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_STATUS,
- mSemiTransparentBarColor, mWindow.mStatusBarColor);
+ mSemiTransparentBarColor, mWindow.mStatusBarColor,
+ getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ mWindow.mEnsureStatusBarContrastWhenTransparent);
}
private int calculateNavigationBarColor() {
return calculateBarColor(mWindow.getAttributes().flags, FLAG_TRANSLUCENT_NAVIGATION,
- mSemiTransparentBarColor, mWindow.mNavigationBarColor);
+ mSemiTransparentBarColor, mWindow.mNavigationBarColor,
+ getWindowSystemUiVisibility(), SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ mWindow.mEnsureNavigationBarContrastWhenTransparent
+ && getContext().getResources().getBoolean(R.bool.config_navBarNeedsScrim));
}
public static int calculateBarColor(int flags, int translucentFlag, int semiTransparentBarColor,
- int barColor) {
- return (flags & translucentFlag) != 0 ? semiTransparentBarColor
- : (flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 ? barColor
- : Color.BLACK;
+ int barColor, int sysuiVis, int lightSysuiFlag, boolean scrimTransparent) {
+ if ((flags & translucentFlag) != 0) {
+ return semiTransparentBarColor;
+ } else if ((flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+ return Color.BLACK;
+ } else if (scrimTransparent && barColor == Color.TRANSPARENT) {
+ boolean light = (sysuiVis & lightSysuiFlag) != 0;
+ return light ? SCRIM_LIGHT : semiTransparentBarColor;
+ } else {
+ return barColor;
+ }
}
private int getCurrentColor(ColorViewState state) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 04559e4..16d6c52 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -50,6 +50,7 @@
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcel;
@@ -247,6 +248,9 @@
private boolean mForcedStatusBarColor = false;
private boolean mForcedNavigationBarColor = false;
+ boolean mEnsureStatusBarContrastWhenTransparent;
+ boolean mEnsureNavigationBarContrastWhenTransparent;
+
@UnsupportedAppUsage
private CharSequence mTitle = null;
@@ -2439,6 +2443,7 @@
final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.LOLLIPOP;
+ final boolean targetPreQ = targetSdk < Build.VERSION_CODES.Q;
final boolean targetHcNeedsOptions = context.getResources().getBoolean(
R.bool.target_honeycomb_needs_options_menu);
final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
@@ -2457,6 +2462,12 @@
mNavigationBarDividerColor = a.getColor(R.styleable.Window_navigationBarDividerColor,
0x00000000);
}
+ if (!targetPreQ) {
+ mEnsureStatusBarContrastWhenTransparent = a.getBoolean(
+ R.styleable.Window_ensureStatusBarContrastWhenTransparent, false);
+ mEnsureNavigationBarContrastWhenTransparent = a.getBoolean(
+ R.styleable.Window_ensureNavigationBarContrastWhenTransparent, true);
+ }
WindowManager.LayoutParams params = getAttributes();
@@ -3845,6 +3856,32 @@
return mNavigationBarDividerColor;
}
+ @Override
+ public void setEnsureStatusBarContrastWhenTransparent(boolean ensureContrast) {
+ mEnsureStatusBarContrastWhenTransparent = ensureContrast;
+ if (mDecor != null) {
+ mDecor.updateColorViews(null, false /* animate */);
+ }
+ }
+
+ @Override
+ public boolean isEnsureStatusBarContrastWhenTransparent() {
+ return mEnsureStatusBarContrastWhenTransparent;
+ }
+
+ @Override
+ public void setEnsureNavigationBarContrastWhenTransparent(boolean ensureContrast) {
+ mEnsureNavigationBarContrastWhenTransparent = ensureContrast;
+ if (mDecor != null) {
+ mDecor.updateColorViews(null, false /* animate */);
+ }
+ }
+
+ @Override
+ public boolean isEnsureNavigationBarContrastWhenTransparent() {
+ return mEnsureNavigationBarContrastWhenTransparent;
+ }
+
public void setIsStartingWindow(boolean isStartingWindow) {
mIsStartingWindow = isStartingWindow;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b94eb16..cc3b3a4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1637,8 +1637,8 @@
android:label="@string/permlab_bluetooth"
android:protectionLevel="normal" />
- <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
- from using them until they are unsuspended.
+ <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
+ user from using them until they are unsuspended.
@hide
-->
<permission android:name="android.permission.SUSPEND_APPS"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9d48fe3..a510424 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2091,6 +2091,40 @@
Corresponds to {@link android.view.Window#setNavigationBarDividerColor(int)}. -->
<attr name="navigationBarDividerColor" format="color" />
+ <!-- Sets whether the system should ensure that the status bar has enough
+ contrast when a fully transparent background is requested.
+
+ <p>If set to this value, the system will determine whether a scrim is necessary
+ to ensure that the status bar has enough contrast with the contents of
+ this app, and set an appropriate effective bar background color accordingly.
+
+ <p>When the status bar color has a non-zero alpha value, the value of this
+ attribute has no effect.
+
+ <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q},
+ this attribute is ignored.
+
+ @see android.view.Window#setEnsureStatusBarContrastWhenTransparent
+ @hide pendingAPI -->
+ <attr name="ensureStatusBarContrastWhenTransparent" format="boolean" />
+
+ <!-- Sets whether the system should ensure that the navigation bar has enough
+ contrast when a fully transparent background is requested.
+
+ <p>If set to this value, the system will determine whether a scrim is necessary
+ to ensure that the navigation bar has enough contrast with the contents of
+ this app, and set an appropriate effective bar background color accordingly.
+
+ <p>When the navigation bar color has a non-zero alpha value, the value of this
+ attribute has no effect.
+
+ <p>If the app does not target at least {@link android.os.Build.VERSION_CODES#Q Q},
+ this attribute is ignored.
+
+ @see android.view.Window#setEnsureNavigationBarContrastWhenTransparent
+ @hide pendingApi -->
+ <attr name="ensureNavigationBarContrastWhenTransparent" format="boolean" />
+
<!-- The duration, in milliseconds, of the window background fade duration
when transitioning into or away from an Activity when called with an
Activity Transition. Corresponds to
@@ -8980,6 +9014,10 @@
<!-- @hide From Theme.navigationBarColor, used for the TaskDescription navigation bar
color. -->
<attr name="navigationBarColor"/>
+ <!-- @hide From Window.ensureStatusBarContrastWhenTransparent -->
+ <attr name="ensureStatusBarContrastWhenTransparent"/>
+ <!-- @hide From Window.ensureNavigationBarContrastWhenTransparent -->
+ <attr name="ensureNavigationBarContrastWhenTransparent"/>
</declare-styleable>
<declare-styleable name="Shortcut">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fe4fd13..58a4c18 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -313,14 +313,15 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
- <!-- The URL returned by ConnectivityManager#getCaptivePortalServerUrl. The actual returned
- value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL. This is the default value
- used if that setting is unset.
+ <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+ If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ and if that value is empty, the framework will use a hard-coded default.
This is *NOT* a URL that will always be used by the system network validation to detect
captive portals: NetworkMonitor may use different strategies and will not necessarily use
this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
instead. -->
- <string translatable="false" name="config_networkDefaultCaptivePortalServerUrl">http://connectivitycheck.gstatic.com/generate_204</string>
+ <!--suppress CheckTagEmptyBody -->
+ <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
<!-- If the hardware supports specially marking packets that caused a wakeup of the
main CPU, set this value to the mark used. -->
@@ -3254,6 +3255,10 @@
<!-- Controls the size of the back gesture inset. -->
<dimen name="config_backGestureInset">0dp</dimen>
+ <!-- Controls whether the navbar needs a scrim with
+ {@link Window#setEnsureNavigationBarContrastWhenTransparent}. -->
+ <bool name="config_navBarNeedsScrim">true</bool>
+
<!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
These values are in DPs and will be converted to pixel sizes internally. -->
<string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index dc8c62c..0304d82 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2011,7 +2011,7 @@
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
- <java-symbol type="string" name="config_networkDefaultCaptivePortalServerUrl" />
+ <java-symbol type="string" name="config_networkCaptivePortalServerUrl" />
<java-symbol type="integer" name="config_networkWakeupPacketMark" />
<java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="bool" name="config_apfDrop802_3Frames" />
@@ -2848,6 +2848,7 @@
<java-symbol type="integer" name="config_navBarInteractionMode" />
<java-symbol type="bool" name="config_navBarCanMove" />
<java-symbol type="bool" name="config_navBarTapThrough" />
+ <java-symbol type="bool" name="config_navBarNeedsScrim" />
<java-symbol type="dimen" name="config_backGestureInset" />
<java-symbol type="color" name="system_bar_background_semi_transparent" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 78a8db42..03fb1fc 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -1725,5 +1725,7 @@
</style>
<!-- @hide DeviceDefault theme for the DocumentsUI app. -->
- <style name="Theme.DeviceDefault.DocumentsUI" parent="Theme.DeviceDefault.DayNight" />
+ <style name="Theme.DeviceDefault.DocumentsUI" parent="Theme.DeviceDefault.DayNight">
+ <item name="actionModeCloseDrawable">@drawable/ic_clear_material</item>
+ </style>
</resources>
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 2ef2d04..9520db7 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -20,33 +20,33 @@
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="permissions">
<xs:complexType>
- <xs:sequence>
- <xs:element name="group" type="group" maxOccurs="unbounded"/>
- <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
- <xs:element name="assign-permission" type="assign-permission" maxOccurs="unbounded"/>
- <xs:element name="split-permission" type="split-permission" maxOccurs="unbounded"/>
- <xs:element name="library" type="library" maxOccurs="unbounded"/>
- <xs:element name="feature" type="feature" maxOccurs="unbounded"/>
- <xs:element name="unavailable-feature" type="unavailable-feature" maxOccurs="unbounded"/>
- <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle" maxOccurs="unbounded"/>
- <xs:element name="allow-in-power-save" type="allow-in-power-save" maxOccurs="unbounded"/>
- <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save" maxOccurs="unbounded"/>
- <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location" maxOccurs="unbounded"/>
- <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings" maxOccurs="unbounded"/>
- <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast" maxOccurs="unbounded"/>
- <xs:element name="app-link" type="app-link" maxOccurs="unbounded"/>
- <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app" maxOccurs="unbounded"/>
- <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app" maxOccurs="unbounded"/>
- <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app" maxOccurs="unbounded"/>
- <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service" maxOccurs="unbounded"/>
- <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app" maxOccurs="unbounded"/>
- <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app" maxOccurs="unbounded"/>
- <xs:element name="privapp-permissions" type="privapp-permissions" maxOccurs="unbounded"/>
- <xs:element name="oem-permissions" type="oem-permissions" maxOccurs="unbounded"/>
- <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app" maxOccurs="unbounded"/>
- <xs:element name="allow-association" type="allow-association" maxOccurs="unbounded"/>
- <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted" maxOccurs="unbounded"/>
- </xs:sequence>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="group" type="group"/>
+ <xs:element name="permission" type="permission"/>
+ <xs:element name="assign-permission" type="assign-permission"/>
+ <xs:element name="split-permission" type="split-permission"/>
+ <xs:element name="library" type="library"/>
+ <xs:element name="feature" type="feature"/>
+ <xs:element name="unavailable-feature" type="unavailable-feature"/>
+ <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle"/>
+ <xs:element name="allow-in-power-save" type="allow-in-power-save"/>
+ <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save"/>
+ <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location"/>
+ <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings"/>
+ <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast"/>
+ <xs:element name="app-link" type="app-link"/>
+ <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app"/>
+ <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app"/>
+ <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app"/>
+ <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service"/>
+ <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app"/>
+ <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
+ <xs:element name="privapp-permissions" type="privapp-permissions"/>
+ <xs:element name="oem-permissions" type="oem-permissions"/>
+ <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
+ <xs:element name="allow-association" type="allow-association"/>
+ <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
+ </xs:choice>
</xs:complexType>
</xs:element>
<xs:complexType name="group">
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index c25bc14..771c1df 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -153,31 +153,31 @@
public class Permissions {
ctor public Permissions();
- method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
- method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
- method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
- method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
- method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
- method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
- method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
- method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
- method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
- method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
- method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
- method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
- method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
- method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
- method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
- method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
- method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
- method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
- method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
- method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
- method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
- method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
- method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
- method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
- method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
+ method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService_optional();
+ method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Group> getGroup_optional();
+ method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary_optional();
+ method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature_optional();
}
public class PrivappPermissions {
diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp
new file mode 100644
index 0000000..9cf68c1
--- /dev/null
+++ b/core/xsd/vts/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_test {
+ name: "vts_permission_validate_test",
+ srcs: [
+ "ValidatePermission.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "libxml2",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/core/xsd/vts/Android.mk b/core/xsd/vts/Android.mk
new file mode 100644
index 0000000..a5754a4
--- /dev/null
+++ b/core/xsd/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidatePermission
+include test/vts/tools/build/Android.host_config.mk
diff --git a/core/xsd/vts/AndroidTest.xml b/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..e5cc9a0
--- /dev/null
+++ b/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsValidatePermission.">
+ <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ <option name="push" value="DATA/etc/permission.xsd->/data/local/tmp/permission.xsd"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsValidatePermission"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_permission_validate_test/vts_permission_validate_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_permission_validate_test/vts_permission_validate_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/core/xsd/vts/ValidatePermission.cpp b/core/xsd/vts/ValidatePermission.cpp
new file mode 100644
index 0000000..3499689
--- /dev/null
+++ b/core/xsd/vts/ValidatePermission.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <regex>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string>
+
+#include "android-base/logging.h"
+#include "utility/ValidateXml.h"
+
+static void get_files_in_dirs(const char* dir_path, std::vector<std::string>& files) {
+ DIR* d;
+ struct dirent* de;
+
+ d = opendir(dir_path);
+ if (d == nullptr) {
+ return;
+ }
+
+ while ((de = readdir(d))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ if (std::regex_match(de->d_name, std::regex("(.*)(.xml)"))) {
+ files.push_back(de->d_name);
+ }
+ }
+ closedir(d);
+}
+
+TEST(CheckConfig, permission) {
+ RecordProperty("description",
+ "Verify that the permission file "
+ "is valid according to the schema");
+
+ const char* location = "/vendor/etc/permissions";
+
+ std::vector<std::string> files;
+ get_files_in_dirs(location, files);
+
+ for (std::string file_name : files) {
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(file_name.c_str(), {location},
+ "/data/local/tmp/permission.xsd");
+ }
+}
diff --git a/media/OWNERS b/media/OWNERS
index 72c8952..a33a990 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,3 +1,4 @@
+andrewlewis@google.com
chz@google.com
dwkang@google.com
elaurent@google.com
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index db33e82..72c18f6 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -546,7 +546,7 @@
@Override
void process() {
if (getState() == PLAYER_STATE_PLAYING) {
- pause();
+ native_pause();
}
playNextDataSource();
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 3a33678..9d4bce7 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -893,7 +893,7 @@
* @param muted true to force muting haptic channels.
* @return the same Builder instance.
*/
- public Builder setMuteHapticChannels(boolean muted) {
+ public @NonNull Builder setHapticChannelsMuted(boolean muted) {
mMuteHapticChannels = muted;
return this;
}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
index fcbda1d..43d7d8f 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
@@ -326,6 +326,8 @@
} else if (status == STATUS_READY) {
startForeground(NOTIFICATION_ID,
buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
+ } else {
+ stopSelf();
}
}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 262e6f6..5817118 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -39,6 +39,7 @@
":services-networkstack-shared-srcs",
],
static_libs: [
+ "androidx.annotation_annotation",
"ipmemorystore-client",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml
index 52425e5..90f96e0 100644
--- a/packages/NetworkStack/res/values/config.xml
+++ b/packages/NetworkStack/res/values/config.xml
@@ -1,5 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <!-- Captive portal http url -->
- <string name="config_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
+ <!--
+ OEMs that wish to change the below settings must do so via a runtime resource overlay package
+ and *NOT* by changing this file. This file is part of the NetworkStack mainline module.
+ The overlays must apply to the config_* values, not the default_* values. The default_*
+ values are meant to be the default when no other configuration is specified.
+ -->
+
+ <!-- HTTP URL for network validation, to use for detecting captive portals. -->
+ <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
+
+ <!-- HTTPS URL for network validation, to use for confirming internet connectivity. -->
+ <string name="default_captive_portal_https_url" translatable="false">https://www.google.com/generate_204</string>
+
+ <!-- List of fallback URLs to use for detecting captive portals. -->
+ <string-array name="default_captive_portal_fallback_urls" translatable="false">
+ <item>http://www.google.com/gen_204</item>
+ <item>http://play.googleapis.com/generate_204</item>
+ </string-array>
+
+ <!-- List of fallback probe specs to use for detecting captive portals.
+ This is an alternative to fallback URLs that provides more flexibility on detection rules.
+ Empty, so unused by default. -->
+ <string-array name="default_captive_portal_fallback_probe_specs" translatable="false">
+ </string-array>
+
+ <!-- Configuration hooks for the above settings.
+ Empty by default but may be overridden by RROs. -->
+ <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+ <string name="config_captive_portal_http_url" translatable="false"></string>
+ <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+ <string name="config_captive_portal_https_url" translatable="false"></string>
+ <string-array name="config_captive_portal_fallback_urls" translatable="false">
+ </string-array>
+ <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
+ </string-array>
</resources>
\ No newline at end of file
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 7b77d66..588dcf2 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -28,6 +28,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs;
import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
@@ -52,6 +53,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
@@ -91,6 +93,9 @@
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.ArrayRes;
+import androidx.annotation.StringRes;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.RingBufferIndices;
import com.android.internal.util.State;
@@ -105,7 +110,6 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -113,6 +117,7 @@
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
/**
* {@hide}
@@ -122,15 +127,6 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
- // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate
- private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
- // Default configuration values for captive portal detection probes.
- // TODO: append a random length parameter to the default HTTPS url.
- // TODO: randomize browser version ids in the default User-Agent String.
- private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204";
- private static final String DEFAULT_FALLBACK_URL = "http://www.google.com/gen_204";
- private static final String DEFAULT_OTHER_FALLBACK_URLS =
- "http://play.googleapis.com/generate_204";
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
+ "Chrome/60.0.3112.32 Safari/537.36";
@@ -378,7 +374,7 @@
mUseHttps = getUseHttpsValidation();
mCaptivePortalUserAgent = getCaptivePortalUserAgent();
mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
- mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context));
+ mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl());
mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
mRandom = deps.getRandom();
@@ -1178,8 +1174,22 @@
}
private String getCaptivePortalServerHttpsUrl() {
- return mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+ return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
+ R.string.default_captive_portal_https_url,
+ Settings.Global.CAPTIVE_PORTAL_HTTPS_URL);
+ }
+
+ /**
+ * Get the captive portal server HTTP URL that is configured on the device.
+ *
+ * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
+ * it has its own updatable strategies to detect captive portals. The framework only advises
+ * on one URL that can be used, while NetworkMonitor may implement more complex logic.
+ */
+ public String getCaptivePortalServerHttpUrl() {
+ return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
+ R.string.default_captive_portal_http_url,
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
}
private int getConsecutiveDnsTimeoutThreshold() {
@@ -1208,24 +1218,23 @@
private URL[] makeCaptivePortalFallbackUrls() {
try {
- String separator = ",";
- String firstUrl = mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
- String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
- DEFAULT_OTHER_FALLBACK_URLS);
- List<URL> urls = new ArrayList<>();
- for (String s : joinedUrls.split(separator)) {
- URL u = makeURL(s);
- if (u == null) {
- continue;
- }
- urls.add(u);
+ final String firstUrl = mDependencies.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null);
+
+ final URL[] settingProviderUrls;
+ if (!TextUtils.isEmpty(firstUrl)) {
+ final String otherUrls = mDependencies.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+ // otherUrls may be empty, but .split() ignores trailing empty strings
+ final String separator = ",";
+ final String[] urls = (firstUrl + separator + otherUrls).split(separator);
+ settingProviderUrls = convertStrings(urls, this::makeURL, new URL[0]);
+ } else {
+ settingProviderUrls = new URL[0];
}
- if (urls.isEmpty()) {
- Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
- }
- return urls.toArray(new URL[urls.size()]);
+
+ return getArrayConfig(settingProviderUrls, R.array.config_captive_portal_fallback_urls,
+ R.array.default_captive_portal_fallback_urls, this::makeURL);
} catch (Exception e) {
// Don't let a misconfiguration bootloop the system.
Log.e(TAG, "Error parsing configured fallback URLs", e);
@@ -1237,15 +1246,14 @@
try {
final String settingsValue = mDependencies.getSetting(
mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
- // Probe specs only used if configured in settings
- if (TextUtils.isEmpty(settingsValue)) {
- return null;
- }
+ final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
+ final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
+ ? emptySpecs
+ : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs);
- final Collection<CaptivePortalProbeSpec> specs =
- CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
- final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()];
- return specs.toArray(specsArray);
+ return getArrayConfig(providerValue, R.array.config_captive_portal_fallback_probe_specs,
+ R.array.default_captive_portal_fallback_probe_specs,
+ CaptivePortalProbeSpec::parseSpecOrNull);
} catch (Exception e) {
// Don't let a misconfiguration bootloop the system.
Log.e(TAG, "Error parsing configured fallback probe specs", e);
@@ -1253,6 +1261,83 @@
}
}
+ /**
+ * Read a setting from a resource or the settings provider.
+ *
+ * <p>The configuration resource is prioritized, then the provider value, then the default
+ * resource value.
+ * @param context The context
+ * @param configResource The resource id for the configuration parameter
+ * @param defaultResource The resource id for the default value
+ * @param symbol The symbol in the settings provider
+ * @return The best available value
+ */
+ @NonNull
+ private String getSettingFromResource(@NonNull final Context context,
+ @StringRes int configResource, @StringRes int defaultResource,
+ @NonNull String symbol) {
+ final Resources res = context.getResources();
+ String setting = res.getString(configResource);
+
+ if (!TextUtils.isEmpty(setting)) return setting;
+
+ setting = mDependencies.getSetting(context, symbol, null);
+ if (!TextUtils.isEmpty(setting)) return setting;
+
+ return res.getString(defaultResource);
+ }
+
+ /**
+ * Get an array configuration from resources or the settings provider.
+ *
+ * <p>The configuration resource is prioritized, then the provider values, then the default
+ * resource values.
+ * @param providerValue Values obtained from the setting provider.
+ * @param configResId ID of the configuration resource.
+ * @param defaultResId ID of the default resource.
+ * @param resourceConverter Converter from the resource strings to stored setting class. Null
+ * return values are ignored.
+ */
+ private <T> T[] getArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
+ @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) {
+ final Resources res = mContext.getResources();
+ String[] configValue = res.getStringArray(configResId);
+
+ if (configValue.length == 0) {
+ if (providerValue.length > 0) {
+ return providerValue;
+ }
+
+ configValue = res.getStringArray(defaultResId);
+ }
+
+ return convertStrings(configValue, resourceConverter, Arrays.copyOf(providerValue, 0));
+ }
+
+ /**
+ * Convert a String array to an array of some other type using the specified converter.
+ *
+ * <p>Any null value, or value for which the converter throws a {@link RuntimeException}, will
+ * not be added to the output array, so the output array may be smaller than the input.
+ */
+ private <T> T[] convertStrings(
+ @NonNull String[] strings, Function<String, T> converter, T[] emptyArray) {
+ final ArrayList<T> convertedValues = new ArrayList<>(strings.length);
+ for (String configString : strings) {
+ T convertedValue = null;
+ try {
+ convertedValue = converter.apply(configString);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing configuration", e);
+ // Fall through
+ }
+ if (convertedValue != null) {
+ convertedValues.add(convertedValue);
+ }
+ }
+ return convertedValues.toArray(emptyArray);
+ }
+
private String getCaptivePortalUserAgent() {
return mDependencies.getSetting(mContext,
Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
@@ -1694,19 +1779,6 @@
}
/**
- * Get the captive portal server HTTP URL that is configured on the device.
- *
- * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
- * it has its own updatable strategies to detect captive portals. The framework only advises
- * on one URL that can be used, while NetworkMonitor may implement more complex logic.
- */
- public String getCaptivePortalServerHttpUrl(Context context) {
- final String defaultUrl =
- context.getResources().getString(R.string.config_captive_portal_http_url);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context, defaultUrl);
- }
-
- /**
* Get the value of a global integer setting.
* @param symbol Name of the setting
* @param defaultValue Value to return if the setting is not defined.
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 9f6c7f8..48c91bf 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -34,7 +34,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -49,6 +48,7 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.INetworkMonitorCallbacks;
import android.net.InetAddresses;
@@ -99,6 +99,7 @@
private static final String LOCATION_HEADER = "location";
private @Mock Context mContext;
+ private @Mock Resources mResources;
private @Mock IpConnectivityLog mLogger;
private @Mock SharedLog mValidationLogger;
private @Mock NetworkInfo mNetworkInfo;
@@ -153,14 +154,20 @@
.thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
anyInt())).thenReturn(1);
- when(mDependencies.getCaptivePortalServerHttpUrl(any())).thenReturn(TEST_HTTP_URL);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL),
- anyString())).thenReturn(TEST_HTTPS_URL);
+ when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
+ .thenReturn(TEST_HTTP_URL);
+ when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
+ .thenReturn(TEST_HTTPS_URL);
+
doReturn(mNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
+ when(mContext.getResources()).thenReturn(mResources);
+
+ when(mResources.getString(anyInt())).thenReturn("");
+ when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
setFallbackUrl(TEST_FALLBACK_URL);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 46e9129..0d972c5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -28,6 +28,8 @@
public static final boolean V = false; // verbose logging
public static final boolean D = true; // regular logging
+ public static final int META_INT_ERROR = -1;
+
private static ErrorListener sErrorListener;
public static int getConnectionStateSummary(int connectionState) {
@@ -133,20 +135,16 @@
final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
context, cachedDevice);
final BluetoothDevice bluetoothDevice = cachedDevice.getDevice();
- final boolean untetheredHeadset = bluetoothDevice != null
- ? Boolean.parseBoolean(bluetoothDevice.getMetadata(
- BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))
- : false;
+ final boolean untetheredHeadset = getBooleanMetaData(
+ bluetoothDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET);
final int iconSize = context.getResources().getDimensionPixelSize(
R.dimen.bt_nearby_icon_size);
final Resources resources = context.getResources();
// Deal with untethered headset
if (untetheredHeadset) {
- final String uriString = bluetoothDevice != null
- ? bluetoothDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON)
- : null;
- final Uri iconUri = uriString != null ? Uri.parse(uriString) : null;
+ final Uri iconUri = getUriMetaData(bluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_ICON);
if (iconUri != null) {
try {
context.getContentResolver().takePersistableUriPermission(iconUri,
@@ -194,4 +192,77 @@
return adaptiveIcon;
}
+
+ /**
+ * Get boolean Bluetooth metadata
+ *
+ * @param bluetoothDevice the BluetoothDevice to get metadata
+ * @param key key value within the list of BluetoothDevice.METADATA_*
+ * @return the boolean metdata
+ */
+ public static boolean getBooleanMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return false;
+ }
+ final byte[] data = bluetoothDevice.getMetadata(key);
+ if (data == null) {
+ return false;
+ }
+ return Boolean.parseBoolean(new String(data));
+ }
+
+ /**
+ * Get String Bluetooth metadata
+ *
+ * @param bluetoothDevice the BluetoothDevice to get metadata
+ * @param key key value within the list of BluetoothDevice.METADATA_*
+ * @return the String metdata
+ */
+ public static String getStringMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return null;
+ }
+ final byte[] data = bluetoothDevice.getMetadata(key);
+ if (data == null) {
+ return null;
+ }
+ return new String(data);
+ }
+
+ /**
+ * Get integer Bluetooth metadata
+ *
+ * @param bluetoothDevice the BluetoothDevice to get metadata
+ * @param key key value within the list of BluetoothDevice.METADATA_*
+ * @return the int metdata
+ */
+ public static int getIntMetaData(BluetoothDevice bluetoothDevice, int key) {
+ if (bluetoothDevice == null) {
+ return META_INT_ERROR;
+ }
+ final byte[] data = bluetoothDevice.getMetadata(key);
+ if (data == null) {
+ return META_INT_ERROR;
+ }
+ try {
+ return Integer.parseInt(new String(data));
+ } catch (NumberFormatException e) {
+ return META_INT_ERROR;
+ }
+ }
+
+ /**
+ * Get URI Bluetooth metadata
+ *
+ * @param bluetoothDevice the BluetoothDevice to get metadata
+ * @param key key value within the list of BluetoothDevice.METADATA_*
+ * @return the URI metdata
+ */
+ public static Uri getUriMetaData(BluetoothDevice bluetoothDevice, int key) {
+ String data = getStringMetaData(bluetoothDevice, key);
+ if (data == null) {
+ return null;
+ }
+ return Uri.parse(data);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 2405666..ff34578 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -881,16 +881,12 @@
//when profile is connected, information would be available
if (profileConnected) {
// Update Meta data for connected device
- if (Boolean.parseBoolean(
- mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
- try {
- leftBattery = Integer.parseInt(
- mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
- rightBattery = Integer.parseInt(mDevice.getMetadata(
- BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
- } catch (NumberFormatException e) {
- Log.d(TAG, "Parse error for unthethered battery level.");
- }
+ if (BluetoothUtils.getBooleanMetaData(
+ mDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
+ leftBattery = BluetoothUtils.getIntMetaData(mDevice,
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY);
+ rightBattery = BluetoothUtils.getIntMetaData(mDevice,
+ BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY);
}
// Set default string with battery level in device connected situation.
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index 530c73a..fb5c16b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -19,6 +19,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
@@ -33,7 +34,25 @@
public class BatterySaverUtils {
private static final String TAG = "BatterySaverUtils";
- public static final String EXTRA_CONFIRM_ONLY = "extra_confirm_only";
+ /**
+ * When set to "true" the notification will be a generic confirm message instead of asking the
+ * user if they want to turn on battery saver. If set to false the dialog will specifically
+ * talk about turning on battery saver and provide a button for taking the action.
+ */
+ public static final String EXTRA_CONFIRM_TEXT_ONLY = "extra_confirm_only";
+ /**
+ * Ignored if {@link #EXTRA_CONFIRM_TEXT_ONLY} is "false". Can be set to any of the values in
+ * {@link PowerManager.AutoPowerSaveModeTriggers}. If set the dialog will set the power
+ * save mode trigger to the specified value after the user acknowledges the trigger.
+ */
+ public static final String EXTRA_POWER_SAVE_MODE_TRIGGER = "extra_power_save_mode_trigger";
+ /**
+ * Ignored if {@link #EXTRA_CONFIRM_TEXT_ONLY} is "false". can be set to any value between
+ * 0-100 that will be used if {@link #EXTRA_POWER_SAVE_MODE_TRIGGER} is
+ * {@link PowerManager#POWER_SAVE_MODE_TRIGGER_PERCENTAGE}.
+ */
+ public static final String EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL =
+ "extra_power_save_mode_trigger_level";
private BatterySaverUtils() {
}
@@ -98,7 +117,10 @@
}
final ContentResolver cr = context.getContentResolver();
- if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context, false)) {
+ final Bundle confirmationExtras = new Bundle(1);
+ confirmationExtras.putBoolean(EXTRA_CONFIRM_TEXT_ONLY, false);
+ if (enable && needFirstTimeWarning
+ && maybeShowBatterySaverConfirmation(context, confirmationExtras)) {
return false;
}
if (enable && !needFirstTimeWarning) {
@@ -118,7 +140,7 @@
&& Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
&& Secure.getInt(cr,
Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
- showAutoBatterySaverSuggestion(context, false);
+ showAutoBatterySaverSuggestion(context, confirmationExtras);
}
}
@@ -129,34 +151,36 @@
/**
* Shows the battery saver confirmation warning if it hasn't been acknowledged by the user in
- * the past before. When confirmOnly is true, the dialog will have generic info about battery
- * saver but will only update that the user has been shown the notification and take no
- * further action. if confirmOnly is false it will show a more specific version of the dialog
- * that toggles battery saver when acknowledged
+ * the past before. Various extras can be provided that will change the behavior of this
+ * notification as well as the ui for it.
* @param context A valid context
- * @param confirmOnly Whether to show the actionless generic dialog (true) or the specific one
- * that toggles battery saver (false)
+ * @param extras Any extras to include in the intent to trigger this confirmation that will
+ * help the system disambiguate what to show/do
+ *
* @return True if it showed the notification because it has not been previously acknowledged.
+ * @see #EXTRA_CONFIRM_TEXT_ONLY
+ * @see #EXTRA_POWER_SAVE_MODE_TRIGGER
+ * @see #EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL
*/
- public static boolean maybeShowBatterySaverConfirmation(Context context, boolean confirmOnly) {
+ public static boolean maybeShowBatterySaverConfirmation(Context context, Bundle extras) {
if (Secure.getInt(context.getContentResolver(),
Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
return false; // Already shown.
}
context.sendBroadcast(
- getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, confirmOnly));
+ getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, extras));
return true;
}
- private static void showAutoBatterySaverSuggestion(Context context, boolean confirmOnly) {
- context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, confirmOnly));
+ private static void showAutoBatterySaverSuggestion(Context context, Bundle extras) {
+ context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, extras));
}
- private static Intent getSystemUiBroadcast(String action, boolean confirmOnly) {
+ private static Intent getSystemUiBroadcast(String action, Bundle extras) {
final Intent i = new Intent(action);
i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
i.setPackage(SYSUI_PACKAGE);
- i.putExtra(EXTRA_CONFIRM_ONLY, confirmOnly);
+ i.putExtras(extras);
return i;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index b228cf7..3a95852c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -25,6 +25,7 @@
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.util.Pair;
import com.android.settingslib.widget.AdaptiveIcon;
@@ -47,6 +48,9 @@
private BluetoothDevice mBluetoothDevice;
private Context mContext;
+ private static final String STRING_METADATA = "string_metadata";
+ private static final String BOOL_METADATA = "true";
+ private static final String INT_METADATA = "25";
@Before
public void setUp() {
@@ -78,7 +82,7 @@
@Test
public void getBtRainbowDrawableWithDescription_normalHeadset_returnAdaptiveIcon() {
when(mBluetoothDevice.getMetadata(
- BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn("false");
+ BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn("false".getBytes());
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn("1f:aa:bb");
@@ -86,4 +90,64 @@
RuntimeEnvironment.application,
mCachedBluetoothDevice).first).isInstanceOf(AdaptiveIcon.class);
}
-}
\ No newline at end of file
+
+ @Test
+ public void getStringMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON)).thenReturn(
+ STRING_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.getStringMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON)).isEqualTo(STRING_METADATA);
+ }
+
+ @Test
+ public void getIntMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+ INT_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.getIntMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY))
+ .isEqualTo(Integer.parseInt(INT_METADATA));
+ }
+
+ @Test
+ public void getIntMetaData_invalidMetaData_getErrorCode() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(null);
+
+ assertThat(BluetoothUtils.getIntMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_UNTETHERED_LEFT_ICON))
+ .isEqualTo(BluetoothUtils.META_INT_ERROR);
+ }
+
+ @Test
+ public void getBooleanMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+ BOOL_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.getBooleanMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).isEqualTo(true);
+ }
+
+ @Test
+ public void getUriMetaData_hasMetaData_getCorrectMetaData() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_MAIN_ICON)).thenReturn(
+ STRING_METADATA.getBytes());
+
+ assertThat(BluetoothUtils.getUriMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_ICON)).isEqualTo(Uri.parse(STRING_METADATA));
+ }
+
+ @Test
+ public void getUriMetaData_nullMetaData_getNullUri() {
+ when(mBluetoothDevice.getMetadata(
+ BluetoothDevice.METADATA_MAIN_ICON)).thenReturn(null);
+
+ assertThat(BluetoothUtils.getUriMetaData(mBluetoothDevice,
+ BluetoothDevice.METADATA_MAIN_ICON)).isNull();
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 79b84b9..c0a1f11 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -455,12 +455,12 @@
updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
- when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
- "true");
- when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
- TWS_BATTERY_LEFT);
- when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
- TWS_BATTERY_RIGHT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+ "true".getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT.getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT.getBytes());
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"Active, L: 15% battery, R: 25% battery");
@@ -472,12 +472,12 @@
updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
- when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
- "true");
- when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
- TWS_BATTERY_LEFT);
- when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
- TWS_BATTERY_RIGHT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+ "true".getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT.getBytes());
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT.getBytes());
assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
"L: 15% battery, R: 25% battery");
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
index cec97ab..79c691c 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/RecentsActivity.java
@@ -87,13 +87,13 @@
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.utilities.Utilities;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.utilities.Utilities;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.FileDescriptor;
@@ -370,8 +370,7 @@
MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
// Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
- ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
- ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true);
+ ColorExtractor.GradientColors systemColors = mColorExtractor.getNeutralColors();
// We don't want to interpolate colors because we're defining the initial state.
// Gradient should be set/ready when you open "Recents".
mRecentsView.setScrimColors(systemColors, false);
@@ -397,9 +396,7 @@
if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
// Recents doesn't care about the wallpaper being visible or not, it always
// wants to scrim with wallpaper colors
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK, true /* ignoreVis */);
+ ColorExtractor.GradientColors colors = mColorExtractor.getNeutralColors();
boolean darkText = colors.supportsDarkText();
if (darkText != mUsingDarkText) {
mUsingDarkText = darkText;
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
index 8723fb9..e60ffba 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/RecentsView.java
@@ -34,7 +34,6 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.os.IRemoteCallback;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
@@ -50,7 +49,7 @@
import android.widget.TextView;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
@@ -87,9 +86,9 @@
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -134,7 +133,7 @@
private int mDividerSize;
private float mBusynessFactor;
- private GradientDrawable mBackgroundScrim;
+ private ScrimDrawable mBackgroundScrim;
private ColorDrawable mMultiWindowBackgroundScrim;
private ValueAnimator mBackgroundScrimAnimator;
private Point mTmpDisplaySize = new Point();
@@ -172,7 +171,7 @@
mDividerSize = ssp.getDockedDividerSize(context);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
- mBackgroundScrim = new GradientDrawable(context);
+ mBackgroundScrim = new ScrimDrawable();
mMultiWindowBackgroundScrim = new ColorDrawable();
LayoutInflater inflater = LayoutInflater.from(context);
@@ -395,7 +394,7 @@
* @param animated Interpolate colors if true.
*/
public void setScrimColors(ColorExtractor.GradientColors scrimColors, boolean animated) {
- mBackgroundScrim.setColors(scrimColors, animated);
+ mBackgroundScrim.setColor(scrimColors.getMainColor(), animated);
int alpha = mMultiWindowBackgroundScrim.getAlpha();
mMultiWindowBackgroundScrim.setColor(scrimColors.getMainColor());
mMultiWindowBackgroundScrim.setAlpha(alpha);
@@ -467,7 +466,6 @@
// Needs to know the screen size since the gradient never scales up or down
// even when bounds change.
mContext.getDisplay().getRealSize(mTmpDisplaySize);
- mBackgroundScrim.setScreenSize(mTmpDisplaySize.x, mTmpDisplaySize.y);
mBackgroundScrim.setBounds(left, top, right, bottom);
mMultiWindowBackgroundScrim.setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
index fbd863d..bc6547f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -59,15 +59,17 @@
public static final int TYPE_WAKE_DISPLAY = 2;
public static final int TYPE_SWIPE = 3;
- int mType;
-
- public int getType() {
- return mType;
- }
+ private int mType;
public Sensor(int type) {
mType = type;
}
+ public int getType() {
+ return mType;
+ }
+ public String toString() {
+ return "{PluginSensor type=\"" + mType + "\"}";
+ }
}
/**
diff --git a/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml b/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml
deleted file mode 100644
index 28ff5a2..0000000
--- a/packages/SystemUI/res-keyguard/layout/type_aod_clock.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 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.
- -->
-<com.android.keyguard.clock.ClockLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <include layout="@layout/typographic_clock" />
-</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/layout/typographic_clock.xml b/packages/SystemUI/res-keyguard/layout/typographic_clock.xml
deleted file mode 100644
index 73bb4b9..0000000
--- a/packages/SystemUI/res-keyguard/layout/typographic_clock.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2019 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.
- -->
-<com.android.keyguard.clock.TypographicClock
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/type_clock"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="50dp"
- android:textAlignment="viewStart"
- style="@style/widget_big"
- android:textSize="40dp"
- />
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 2f2f84a..4738887 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -405,106 +405,6 @@
number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
</plurals>
- <!-- Time displayed on typographic clock face, which displays the time in words.
- Example:
-
- It's
- Four
- Twenty
- Nine
-
- This string requires two arguments: the first in the hours of the time and
- the second is the minutes of the time. The hours string is obtained from
- string-array type_clock_hours below and the minutes string is obtained
- from string-array type_clock_minutes below.
-
- [CHAR LIMIT=8] -->
- <plurals name="type_clock_header">
- <item quantity="one"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
- <item quantity="few"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
- <item quantity="other"><annotation name="color">It\u2019s</annotation>\n^1\n^2</item>
- </plurals>
-
- <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=12] -->
- <string-array name="type_clock_hours">
- <item>Twelve</item>
- <item>One</item>
- <item>Two</item>
- <item>Three</item>
- <item>Four</item>
- <item>Five</item>
- <item>Six</item>
- <item>Seven</item>
- <item>Eight</item>
- <item>Nine</item>
- <item>Ten</item>
- <item>Eleven</item>
- </string-array>
-
- <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=20] -->
- <string-array name="type_clock_minutes">
- <item>O\u2019Clock</item>
- <item>Oh One</item>
- <item>Oh Two</item>
- <item>Oh Three</item>
- <item>Oh Four</item>
- <item>Oh Five</item>
- <item>Oh Six</item>
- <item>Oh Seven</item>
- <item>Oh Eight</item>
- <item>Oh Nine</item>
- <item>Ten</item>
- <item>Eleven</item>
- <item>Twelve</item>
- <item>Thirteen</item>
- <item>Fourteen</item>
- <item>Fifteen</item>
- <item>Sixteen</item>
- <item>Seventeen</item>
- <item>Eighteen</item>
- <item>Nineteen</item>
- <item>Twenty</item>
- <item>Twenty\nOne</item>
- <item>Twenty\nTwo</item>
- <item>Twenty\nThree</item>
- <item>Twenty\nFour</item>
- <item>Twenty\nFive</item>
- <item>Twenty\nSix</item>
- <item>Twenty\nSeven</item>
- <item>Twenty\nEight</item>
- <item>Twenty\nNine</item>
- <item>Thirty</item>
- <item>Thirty\nOne</item>
- <item>Thirty\nTwo</item>
- <item>Thirty\nThree</item>
- <item>Thirty\nFour</item>
- <item>Thirty\nFive</item>
- <item>Thirty\nSix</item>
- <item>Thirty\nSeven</item>
- <item>Thirty\nEight</item>
- <item>Thirty\nNine</item>
- <item>Forty</item>
- <item>Forty\nOne</item>
- <item>Forty\nTwo</item>
- <item>Forty\nThree</item>
- <item>Forty\nFour</item>
- <item>Forty\nFive</item>
- <item>Forty\nSix</item>
- <item>Forty\nSeven</item>
- <item>Forty\nEight</item>
- <item>Forty\nNine</item>
- <item>Fifty</item>
- <item>Fifty\nOne</item>
- <item>Fifty\nTwo</item>
- <item>Fifty\nThree</item>
- <item>Fifty\nFour</item>
- <item>Fifty\nFive</item>
- <item>Fifty\nSix</item>
- <item>Fifty\nSeven</item>
- <item>Fifty\nEight</item>
- <item>Fifty\nNine</item>
- </string-array>
-
<!-- Title for default clock face that will appear in the picker app next to a preview image of
the clock face. [CHAR LIMIT=8] -->
<string name="clock_title_default" translatable="false">Default</string>
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
index 41e0786..ced26c9 100644
--- a/packages/SystemUI/res/values/attrs_car.xml
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -15,16 +15,23 @@
-->
<resources>
+ <attr name="icon" format="reference"/>
+ <attr name="selectedIcon" format="reference"/>
+ <attr name="intent" format="string"/>
+ <attr name="longIntent" format="string"/>
+ <attr name="selectedAlpha" format="float" />
+ <attr name="unselectedAlpha" format="float" />
+
<!-- Allow for custom attribs to be added to a facet button -->
<declare-styleable name="CarFacetButton">
<!-- icon to be rendered (drawable) -->
- <attr name="icon" format="reference"/>
+ <attr name="icon"/>
<!-- icon to be rendered when in selected state -->
- <attr name="selectedIcon" format="reference"/>
+ <attr name="selectedIcon"/>
<!-- intent to start when button is click -->
- <attr name="intent" format="string"/>
+ <attr name="intent"/>
<!-- intent to start when a long press has happened -->
- <attr name="longIntent" format="string"/>
+ <attr name="longIntent"/>
<!-- categories that will be added as extras to the fired intents -->
<attr name="categories" format="string"/>
<!-- package names that will be added as extras to the fired intents -->
@@ -32,9 +39,9 @@
<!-- componentName names that will be used for detecting selected state -->
<attr name="componentNames" format="string" />
<!-- Alpha value to used when in selected state. Defaults 1f -->
- <attr name="selectedAlpha" format="float" />
+ <attr name="selectedAlpha" />
<!-- Alpha value to used when in un-selected state. Defaults 0.7f -->
- <attr name="unselectedAlpha" format="float" />
+ <attr name="unselectedAlpha" />
<!-- Render a "more" icon. Defaults true -->
<attr name="useMoreIcon" format="boolean" />
@@ -44,17 +51,17 @@
<!-- Allow for custom attribs to be added to a nav button -->
<declare-styleable name="CarNavigationButton">
<!-- intent to start when button is click -->
- <attr name="intent" format="string"/>
+ <attr name="intent" />
<!-- intent to start when a long press has happened -->
- <attr name="longIntent" format="string"/>
+ <attr name="longIntent" />
<!-- start the intent as a broad cast instead of an activity if true-->
<attr name="broadcast" format="boolean"/>
<!-- Alpha value to used when in selected state. Defaults 1f -->
- <attr name="selectedAlpha" format="float" />
+ <attr name="selectedAlpha" />
<!-- Alpha value to used when in un-selected state. Defaults 0.7f -->
- <attr name="unselectedAlpha" format="float" />
+ <attr name="unselectedAlpha" />
<!-- icon to be rendered when in selected state -->
- <attr name="selectedIcon" format="reference"/>
+ <attr name="selectedIcon" />
</declare-styleable>
<!-- Custom attributes to configure hvac values -->
@@ -89,6 +96,6 @@
</attr>
<!-- Icon resource ids to render on UI -->
- <attr name="icon" format="reference"/>
+ <attr name="icon" />
</declare-styleable>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 59ee267..7ffee5d 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -37,7 +37,6 @@
*/
private View mDigitalClock;
private View mAnalogClock;
- private View mTypeClock;
/**
* Pixel shifting amplitidues used to prevent screen burn-in.
@@ -62,7 +61,6 @@
super.onFinishInflate();
mDigitalClock = findViewById(R.id.digital_clock);
mAnalogClock = findViewById(R.id.analog_clock);
- mTypeClock = findViewById(R.id.type_clock);
// Get pixel shifting X, Y amplitudes from resources.
Resources resources = getResources();
@@ -95,11 +93,5 @@
mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
+ offsetY);
}
-
- // Put the typographic clock part way down the screen.
- if (mTypeClock != null) {
- mTypeClock.setX(offsetX);
- mTypeClock.setY(0.2f * getHeight() + offsetY);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index bc00b5c..e373ca1 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -144,7 +144,6 @@
addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater,
colorExtractor));
- addBuiltinClock(() -> new TypeClockController(res, layoutInflater, colorExtractor));
// Store the size of the display for generation of clock preview.
DisplayMetrics dm = res.getDisplayMetrics();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
deleted file mode 100644
index 1c6b38b..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard.clock;
-
-import android.app.WallpaperManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.graphics.Paint.Style;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.internal.colorextraction.ColorExtractor;
-import com.android.keyguard.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.plugins.ClockPlugin;
-
-import java.util.TimeZone;
-
-/**
- * Plugin for a custom Typographic clock face that displays the time in words.
- */
-public class TypeClockController implements ClockPlugin {
-
- /**
- * Resources used to get title and thumbnail.
- */
- private final Resources mResources;
-
- /**
- * LayoutInflater used to inflate custom clock views.
- */
- private final LayoutInflater mLayoutInflater;
-
- /**
- * Extracts accent color from wallpaper.
- */
- private final SysuiColorExtractor mColorExtractor;
-
- /**
- * Renders preview from clock view.
- */
- private final ViewPreviewer mRenderer = new ViewPreviewer();
-
- /**
- * Custom clock shown on AOD screen and behind stack scroller on lock.
- */
- private View mView;
- private TypographicClock mTypeClock;
-
- /**
- * Small clock shown on lock screen above stack scroller.
- */
- private TypographicClock mLockClock;
-
- /**
- * Controller for transition into dark state.
- */
- private CrossFadeDarkController mDarkController;
-
- /**
- * Create a TypeClockController instance.
- *
- * @param res Resources contains title and thumbnail.
- * @param inflater Inflater used to inflate custom clock views.
- * @param colorExtractor Extracts accent color from wallpaper.
- */
- TypeClockController(Resources res, LayoutInflater inflater,
- SysuiColorExtractor colorExtractor) {
- mResources = res;
- mLayoutInflater = inflater;
- mColorExtractor = colorExtractor;
- }
-
- private void createViews() {
- mView = mLayoutInflater.inflate(R.layout.type_aod_clock, null);
- mTypeClock = mView.findViewById(R.id.type_clock);
-
- // For now, this view is used to hide the default digital clock.
- // Need better transition to lock screen.
- mLockClock = (TypographicClock) mLayoutInflater.inflate(R.layout.typographic_clock, null);
- mLockClock.setVisibility(View.GONE);
-
- mDarkController = new CrossFadeDarkController(mView, mLockClock);
- }
-
- @Override
- public void onDestroyView() {
- mView = null;
- mTypeClock = null;
- mLockClock = null;
- mDarkController = null;
- }
-
- @Override
- public String getName() {
- return "type";
- }
-
- @Override
- public String getTitle() {
- return mResources.getString(R.string.clock_title_type);
- }
-
- @Override
- public Bitmap getThumbnail() {
- return BitmapFactory.decodeResource(mResources, R.drawable.type_thumbnail);
- }
-
- @Override
- public Bitmap getPreview(int width, int height) {
-
- // Use the big clock view for the preview
- View view = getBigClockView();
-
- // Initialize state of plugin before generating preview.
- setDarkAmount(1f);
- setTextColor(Color.WHITE);
- ColorExtractor.GradientColors colors = mColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK, true);
- setColorPalette(colors.supportsDarkText(), colors.getColorPalette());
- onTimeTick();
-
- return mRenderer.createPreview(view, width, height);
- }
-
- @Override
- public View getView() {
- if (mLockClock == null) {
- createViews();
- }
- return mLockClock;
- }
-
- @Override
- public View getBigClockView() {
- if (mView == null) {
- createViews();
- }
- return mView;
- }
-
- @Override
- public void setStyle(Style style) {}
-
- @Override
- public void setTextColor(int color) {
- mTypeClock.setTextColor(color);
- mLockClock.setTextColor(color);
- }
-
- @Override
- public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
- if (colorPalette == null || colorPalette.length == 0) {
- return;
- }
- final int color = colorPalette[Math.max(0, colorPalette.length - 5)];
- mTypeClock.setClockColor(color);
- mLockClock.setClockColor(color);
- }
-
- @Override
- public void onTimeTick() {
- mTypeClock.onTimeChanged();
- mLockClock.onTimeChanged();
- }
-
- @Override
- public void setDarkAmount(float darkAmount) {
- if (mDarkController != null) {
- mDarkController.setDarkAmount(darkAmount);
- }
- }
-
- @Override
- public void onTimeZoneChanged(TimeZone timeZone) {
- mTypeClock.onTimeZoneChanged(timeZone);
- mLockClock.onTimeZoneChanged(timeZone);
- }
-
- @Override
- public boolean shouldShowStatusArea() {
- return false;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
deleted file mode 100644
index 572ab30..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.keyguard.clock;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.Annotation;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannedString;
-import android.text.TextUtils;
-import android.text.format.DateFormat;
-import android.text.style.ForegroundColorSpan;
-import android.util.AttributeSet;
-import android.widget.TextView;
-
-import com.android.keyguard.R;
-
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * Clock that presents the time in words.
- */
-public class TypographicClock extends TextView {
-
- private static final String ANNOTATION_COLOR = "color";
-
- private final Resources mResources;
- private final String[] mHours;
- private final String[] mMinutes;
- private int mAccentColor;
- private final Calendar mTime = Calendar.getInstance(TimeZone.getDefault());
- private String mDescFormat;
- private TimeZone mTimeZone;
-
- public TypographicClock(Context context) {
- this(context, null);
- }
-
- public TypographicClock(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
- mResources = context.getResources();
- mHours = mResources.getStringArray(R.array.type_clock_hours);
- mMinutes = mResources.getStringArray(R.array.type_clock_minutes);
- mAccentColor = mResources.getColor(R.color.typeClockAccentColor, null);
- }
-
- /**
- * Call when the time changes to update the text of the time.
- */
- public void onTimeChanged() {
- mTime.setTimeInMillis(System.currentTimeMillis());
- setContentDescription(DateFormat.format(mDescFormat, mTime));
- final int hour = mTime.get(Calendar.HOUR) % 12;
- final int minute = mTime.get(Calendar.MINUTE) % 60;
-
- // Get the quantity based on the hour for languages like Portuguese and Czech.
- SpannedString typeTemplate = (SpannedString) mResources.getQuantityText(
- R.plurals.type_clock_header, hour);
-
- // Find the "color" annotation and set the foreground color to the accent color.
- Annotation[] annotations = typeTemplate.getSpans(0, typeTemplate.length(),
- Annotation.class);
- SpannableString spanType = new SpannableString(typeTemplate);
- for (int i = 0; i < annotations.length; i++) {
- Annotation annotation = annotations[i];
- String key = annotation.getValue();
- if (ANNOTATION_COLOR.equals(key)) {
- spanType.setSpan(new ForegroundColorSpan(mAccentColor),
- spanType.getSpanStart(annotation), spanType.getSpanEnd(annotation),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
-
- setText(TextUtils.expandTemplate(spanType, mHours[hour], mMinutes[minute]));
- }
-
- /**
- * Call when the time zone has changed to update clock time.
- *
- * @param timeZone The updated time zone that will be used.
- */
- public void onTimeZoneChanged(TimeZone timeZone) {
- mTimeZone = timeZone;
- mTime.setTimeZone(timeZone);
- }
-
- /**
- * Sets the accent color used on the clock face.
- */
- public void setClockColor(int color) {
- mAccentColor = color;
- onTimeChanged();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mTime.setTimeZone(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
- onTimeChanged();
- }
-
- /**
- * Overriding hasOverlappingRendering as false to improve performance of crossfading.
- */
- @Override
- public boolean hasOverlappingRendering() {
- return false;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 6b21526..285d4aab 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -229,6 +229,9 @@
true /* singleTaskInstance */);
addView(mActivityView);
+ // Make sure pointer is below activity view
+ bringChildToFront(mPointerView);
+
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
// Keep track of IME displaying because we should not make any adjustments that might
// cause a config change while the IME is displayed otherwise it'll loose focus.
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index a74c328..05665b5 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -34,6 +34,7 @@
import com.android.internal.colorextraction.types.Tonal;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -46,7 +47,8 @@
* ColorExtractor aware of wallpaper visibility
*/
@Singleton
-public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
+public class SysuiColorExtractor extends ColorExtractor implements Dumpable,
+ ConfigurationController.ConfigurationListener {
private static final String TAG = "SysuiColorExtractor";
private final Tonal mTonal;
private boolean mWallpaperVisible;
@@ -55,15 +57,17 @@
private final GradientColors mWpHiddenColors;
@Inject
- public SysuiColorExtractor(Context context) {
- this(context, new Tonal(context), true);
+ public SysuiColorExtractor(Context context, ConfigurationController configurationController) {
+ this(context, new Tonal(context), configurationController, true);
}
@VisibleForTesting
- public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
+ public SysuiColorExtractor(Context context, ExtractionType type,
+ ConfigurationController configurationController, boolean registerVisibility) {
super(context, type, false /* immediately */);
mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context);
mWpHiddenColors = new GradientColors();
+ configurationController.addCallback(this);
WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
updateDefaultGradients(systemColors);
@@ -113,8 +117,21 @@
}
}
- @VisibleForTesting
- GradientColors getFallbackColors() {
+ @Override
+ public void onUiModeChanged() {
+ WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
+ updateDefaultGradients(systemColors);
+ }
+
+ /**
+ * Colors the should be using for scrims.
+ *
+ * They will be:
+ * - A light gray if the wallpaper is light
+ * - A dark gray if the wallpaper is very dark or we're in night mode.
+ * - Black otherwise
+ */
+ public GradientColors getNeutralColors() {
return mWpHiddenColors;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 77180f8..831d074 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -228,9 +228,9 @@
/** Dump current state */
public void dump(PrintWriter pw) {
for (TriggerSensor s : mSensors) {
- pw.print("Sensor: "); pw.println(s.toString());
+ pw.print(" Sensor: "); pw.println(s.toString());
}
- pw.print("ProxSensor: "); pw.println(mProxSensor.toString());
+ pw.print(" ProxSensor: "); pw.println(mProxSensor.toString());
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 7a3f3be..411536c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -35,7 +35,6 @@
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
-import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.ConnectivityManager;
@@ -73,7 +72,7 @@
import com.android.internal.R;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.telephony.TelephonyIntents;
@@ -1503,7 +1502,7 @@
private final MyAdapter mAdapter;
private MultiListLayout mGlobalActionsLayout;
private Drawable mBackgroundDrawable;
- private final ColorExtractor mColorExtractor;
+ private final SysuiColorExtractor mColorExtractor;
private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
private boolean mKeyguardShowing;
private boolean mShowing;
@@ -1582,7 +1581,7 @@
if (!shouldUsePanel()) {
if (mBackgroundDrawable == null) {
- mBackgroundDrawable = new GradientDrawable(mContext);
+ mBackgroundDrawable = new ScrimDrawable();
}
mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
} else {
@@ -1610,16 +1609,9 @@
super.onStart();
mGlobalActionsLayout.updateList();
- if (mBackgroundDrawable instanceof GradientDrawable) {
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
+ if (mBackgroundDrawable instanceof ScrimDrawable) {
mColorExtractor.addOnColorsChangedListener(this);
- ((GradientDrawable) mBackgroundDrawable)
- .setScreenSize(displaySize.x, displaySize.y);
- GradientColors colors = mColorExtractor.getColors(
- mKeyguardShowing
- ? WallpaperManager.FLAG_LOCK
- : WallpaperManager.FLAG_SYSTEM);
+ GradientColors colors = mColorExtractor.getNeutralColors();
updateColors(colors, false /* animate */);
}
}
@@ -1630,10 +1622,10 @@
* @param animate Interpolates gradient if true, just sets otherwise.
*/
private void updateColors(GradientColors colors, boolean animate) {
- if (!(mBackgroundDrawable instanceof GradientDrawable)) {
+ if (!(mBackgroundDrawable instanceof ScrimDrawable)) {
return;
}
- ((GradientDrawable) mBackgroundDrawable).setColors(colors, animate);
+ ((ScrimDrawable) mBackgroundDrawable).setColor(colors.getMainColor(), animate);
View decorView = getWindow().getDecorView();
if (colors.supportsDarkText()) {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 4cf58b7..4065d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -19,9 +19,7 @@
import android.app.Dialog;
import android.app.KeyguardManager;
-import android.app.WallpaperManager;
import android.content.Context;
-import android.graphics.Point;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -31,7 +29,7 @@
import com.android.internal.R;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.SysUiServiceProvider;
@@ -87,7 +85,7 @@
@Override
public void showShutdownUi(boolean isReboot, String reason) {
- GradientDrawable background = new GradientDrawable(mContext);
+ ScrimDrawable background = new ScrimDrawable();
background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
Dialog d = new Dialog(mContext,
@@ -129,12 +127,8 @@
message.setTextColor(color);
if (isReboot) message.setText(R.string.reboot_to_reset_message);
- Point displaySize = new Point();
- mContext.getDisplay().getRealSize(displaySize);
- GradientColors colors = Dependency.get(SysuiColorExtractor.class).getColors(
- onKeyguard ? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM);
- background.setColors(colors, false);
- background.setScreenSize(displaySize.x, displaySize.y);
+ GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
+ background.setColor(colors.getMainColor(), false);
d.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 10f727b..e92aa51 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -22,15 +22,19 @@
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioAttributes;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
+import android.provider.Settings;
+import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.text.Annotation;
import android.text.Layout;
@@ -547,9 +551,15 @@
updateNotification();
}
- private void showStartSaverConfirmation(boolean confirmOnly) {
+ private void showStartSaverConfirmation(Bundle extras) {
if (mSaverConfirmation != null) return;
final SystemUIDialog d = new SystemUIDialog(mContext);
+ final boolean confirmOnly = extras.getBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY);
+ final int batterySaverTriggerMode =
+ extras.getInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER,
+ PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
+ final int batterySaverTriggerLevel =
+ extras.getInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL, 0);
d.setMessage(getBatterySaverDescription());
// Sad hack for http://b/78261259 and http://b/78298335. Otherwise "Battery" may be split
@@ -563,14 +573,25 @@
if (confirmOnly) {
d.setTitle(R.string.battery_saver_confirmation_title_generic);
d.setPositiveButton(com.android.internal.R.string.confirm_battery_saver,
- (dialog, which) -> Secure.putInt(
- mContext.getContentResolver(),
- Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
- 1));
+ (dialog, which) -> {
+ final ContentResolver resolver = mContext.getContentResolver();
+ Secure.putInt(
+ resolver,
+ Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
+ 1);
+ Settings.Global.putInt(
+ resolver,
+ Global.AUTOMATIC_POWER_SAVE_MODE,
+ batterySaverTriggerMode);
+ Settings.Global.putInt(
+ resolver,
+ Global.LOW_POWER_MODE_TRIGGER_LEVEL,
+ batterySaverTriggerLevel);
+ });
} else {
d.setTitle(R.string.battery_saver_confirmation_title);
d.setPositiveButton(R.string.battery_saver_confirmation_ok,
- (dialog, which) -> setSaverMode(true, false));
+ (dialog, which) -> setSaverMode(true, false));
d.setNegativeButton(android.R.string.cancel, null);
}
d.setShowForAllUsers(true);
@@ -731,7 +752,7 @@
dismissLowBatteryNotification();
} else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) {
dismissLowBatteryNotification();
- showStartSaverConfirmation(intent.getBooleanExtra(EXTRA_CONFIRM_ONLY, false));
+ showStartSaverConfirmation(intent.getExtras());
} else if (action.equals(ACTION_DISMISSED_WARNING)) {
dismissLowBatteryWarning();
} else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index cf6e64c..04f1c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -16,61 +16,33 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Display;
import android.view.View;
-import android.view.WindowManager;
import androidx.core.graphics.ColorUtils;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
/**
* A view which can draw a scrim
*/
-public class ScrimView extends View implements ConfigurationController.ConfigurationListener {
- private static final String TAG = "ScrimView";
+public class ScrimView extends View {
private final ColorExtractor.GradientColors mColors;
- private int mDensity;
private float mViewAlpha = 1.0f;
- private ValueAnimator mAlphaAnimator;
private Drawable mDrawable;
private PorterDuffColorFilter mColorFilter;
private int mTintColor;
- private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener = animation -> {
- if (mDrawable == null) {
- Log.w(TAG, "Trying to animate null drawable");
- return;
- }
- mDrawable.setAlpha((int) (255 * (float) animation.getAnimatedValue()));
- };
- private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mAlphaAnimator = null;
- }
- };
private Runnable mChangeRunnable;
- private int mCornerRadius;
public ScrimView(Context context) {
this(context, null);
@@ -87,47 +59,10 @@
public ScrimView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mDrawable = new GradientDrawable(context);
+ mDrawable = new ScrimDrawable();
mDrawable.setCallback(this);
mColors = new ColorExtractor.GradientColors();
- updateScreenSize();
updateColorWithTint(false);
- initView();
- final Configuration currentConfig = mContext.getResources().getConfiguration();
- mDensity = currentConfig.densityDpi;
- }
-
- private void initView() {
- mCornerRadius = getResources().getDimensionPixelSize(
- Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- int densityDpi = newConfig.densityDpi;
- if (mDensity != densityDpi) {
- mDensity = densityDpi;
- initView();
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- // We need to know about configuration changes to update the gradient size
- // since it's independent from view bounds.
- ConfigurationController config = Dependency.get(ConfigurationController.class);
- config.addCallback(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- ConfigurationController config = Dependency.get(ConfigurationController.class);
- config.removeCallback(this);
}
@Override
@@ -142,7 +77,6 @@
mDrawable.setCallback(this);
mDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
mDrawable.setAlpha((int) (255 * mViewAlpha));
- updateScreenSize();
invalidate();
}
@@ -200,15 +134,13 @@
}
private void updateColorWithTint(boolean animated) {
- if (mDrawable instanceof GradientDrawable) {
+ if (mDrawable instanceof ScrimDrawable) {
// Optimization to blend colors and avoid a color filter
- GradientDrawable drawable = (GradientDrawable) mDrawable;
+ ScrimDrawable drawable = (ScrimDrawable) mDrawable;
float tintAmount = Color.alpha(mTintColor) / 255f;
int mainTinted = ColorUtils.blendARGB(mColors.getMainColor(), mTintColor,
tintAmount);
- int secondaryTinted = ColorUtils.blendARGB(mColors.getSecondaryColor(), mTintColor,
- tintAmount);
- drawable.setColors(mainTinted, secondaryTinted, animated);
+ drawable.setColor(mainTinted, animated);
} else {
boolean hasAlpha = Color.alpha(mTintColor) != 0;
if (hasAlpha) {
@@ -250,10 +182,6 @@
if (alpha != mViewAlpha) {
mViewAlpha = alpha;
- if (mAlphaAnimator != null) {
- mAlphaAnimator.cancel();
- }
-
mDrawable.setAlpha((int) (255 * alpha));
if (mChangeRunnable != null) {
mChangeRunnable.run();
@@ -270,27 +198,6 @@
}
@Override
- public void onConfigChanged(Configuration newConfig) {
- updateScreenSize();
- }
-
- private void updateScreenSize() {
- if (mDrawable instanceof GradientDrawable) {
- WindowManager wm = mContext.getSystemService(WindowManager.class);
- if (wm == null) {
- Log.w(TAG, "Can't resize gradient drawable to fit the screen");
- return;
- }
- Display display = wm.getDefaultDisplay();
- if (display != null) {
- Point size = new Point();
- display.getRealSize(size);
- ((GradientDrawable) mDrawable).setScreenSize(size.x, size.y);
- }
- }
- }
-
- @Override
protected boolean canReceivePointerEvents() {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 2e85fea..ce8463e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -367,16 +367,11 @@
@Override
public void onFinishedGoingToSleep(int why) {
Trace.beginSection("BiometricUnlockController#onFinishedGoingToSleep");
- if (mPendingAuthenticatedUserId != -1) {
-
+ BiometricSourceType pendingType = mPendingAuthenticatedBioSourceType;
+ int pendingUserId = mPendingAuthenticatedUserId;
+ if (pendingUserId != -1 && pendingType != null) {
// Post this to make sure it's executed after the device is fully locked.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- onBiometricAuthenticated(mPendingAuthenticatedUserId,
- mPendingAuthenticatedBioSourceType);
- }
- });
+ mHandler.post(() -> onBiometricAuthenticated(pendingUserId, pendingType));
}
mPendingAuthenticatedUserId = -1;
mPendingAuthenticatedBioSourceType = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 0d2fe13..ed79476 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -20,7 +20,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.AlarmManager;
-import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
@@ -121,8 +120,7 @@
private final Handler mHandler;
private final SysuiColorExtractor mColorExtractor;
- private GradientColors mLockColors;
- private GradientColors mSystemColors;
+ private GradientColors mColors;
private boolean mNeedsDrawableColorUpdate;
protected float mScrimBehindAlpha;
@@ -190,10 +188,7 @@
mColorExtractor = Dependency.get(SysuiColorExtractor.class);
mColorExtractor.addOnColorsChangedListener(this);
- mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
- mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
+ mColors = mColorExtractor.getNeutralColors();
mNeedsDrawableColorUpdate = true;
final ScrimState[] states = ScrimState.values();
@@ -201,7 +196,6 @@
states[i].init(mScrimInFront, mScrimBehind, mDozeParameters);
states[i].setScrimBehindAlphaKeyguard(mScrimBehindAlphaKeyguard);
}
- mState = ScrimState.UNINITIALIZED;
mScrimBehind.setDefaultFocusHighlightEnabled(false);
mScrimInFront.setDefaultFocusHighlightEnabled(false);
@@ -488,17 +482,15 @@
// Make sure we have the right gradients and their opacities will satisfy GAR.
if (mNeedsDrawableColorUpdate) {
mNeedsDrawableColorUpdate = false;
- boolean isKeyguard = mKeyguardUpdateMonitor.isKeyguardVisible() && !mKeyguardOccluded;
- GradientColors currentScrimColors = isKeyguard ? mLockColors : mSystemColors;
// Only animate scrim color if the scrim view is actually visible
boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen;
boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen;
- mScrimInFront.setColors(currentScrimColors, animateScrimInFront);
- mScrimBehind.setColors(currentScrimColors, animateScrimBehind);
+ mScrimInFront.setColors(mColors, animateScrimInFront);
+ mScrimBehind.setColors(mColors, animateScrimBehind);
// Calculate minimum scrim opacity for white or black text.
- int textColor = currentScrimColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
- int mainColor = currentScrimColors.getMainColor();
+ int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE;
+ int mainColor = mColors.getMainColor();
float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
4.5f /* minimumContrast */) / 255f;
mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
@@ -815,7 +807,7 @@
}
public int getBackgroundColor() {
- int color = mLockColors.getMainColor();
+ int color = mColors.getMainColor();
return Color.argb((int) (mScrimBehind.getViewAlpha() * Color.alpha(color)),
Color.red(color), Color.green(color), Color.blue(color));
}
@@ -830,18 +822,9 @@
@Override
public void onColorsChanged(ColorExtractor colorExtractor, int which) {
- if ((which & WallpaperManager.FLAG_LOCK) != 0) {
- mLockColors = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK,
- ColorExtractor.TYPE_DARK, true /* ignoreVisibility */);
- mNeedsDrawableColorUpdate = true;
- scheduleUpdate();
- }
- if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
- mSystemColors = mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
- ColorExtractor.TYPE_DARK, mState != ScrimState.UNLOCKED);
- mNeedsDrawableColorUpdate = true;
- scheduleUpdate();
- }
+ mColors = mColorExtractor.getNeutralColors();
+ mNeedsDrawableColorUpdate = true;
+ scheduleUpdate();
}
@VisibleForTesting
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 b34e24e..aaaf3ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1152,7 +1152,6 @@
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
}
- mStatusBarKeyguardViewManager.onDensityOrFontScaleChanged();
// TODO: Bring these out of StatusBar.
((UserInfoControllerImpl) Dependency.get(UserInfoController.class))
.onDensityOrFontScaleChanged();
@@ -3949,6 +3948,7 @@
}
private void setPulsing(boolean pulsing) {
+ mStatusBarKeyguardViewManager.setPulsing(pulsing);
mKeyguardViewMediator.setPulsing(pulsing);
mNotificationPanel.setPulsing(pulsing);
mVisualStabilityManager.setPulsing(pulsing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 92cd280..e3cc3d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -40,14 +40,18 @@
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.SystemUIFactory;
+import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
@@ -61,7 +65,7 @@
* {@link com.android.keyguard.KeyguardViewBase}.
*/
public class StatusBarKeyguardViewManager implements RemoteInputController.Callback,
- StatusBarStateController.StateListener {
+ StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = - 16 * 3;
@@ -105,6 +109,18 @@
mNotificationPanelView.updateLockIcon();
}
};
+ private final DockManager.DockEventListener mDockEventListener =
+ new DockManager.DockEventListener() {
+ @Override
+ public void onEvent(int event) {
+ boolean isDocked = mDockManager.isDocked();
+ if (isDocked == mIsDocked) {
+ return;
+ }
+ mIsDocked = isDocked;
+ updateStates();
+ }
+ };
protected LockPatternUtils mLockPatternUtils;
protected ViewMediatorCallback mViewMediatorCallback;
@@ -119,6 +135,9 @@
protected boolean mOccluded;
protected boolean mRemoteInputActive;
private boolean mDozing;
+ private boolean mPulsing;
+ private boolean mGesturalNav;
+ private boolean mIsDocked;
protected boolean mFirstUpdate = true;
protected boolean mLastShowing;
@@ -127,6 +146,9 @@
private boolean mLastBouncerDismissible;
protected boolean mLastRemoteInputActive;
private boolean mLastDozing;
+ private boolean mLastGesturalNav;
+ private boolean mLastIsDocked;
+ private boolean mLastPulsing;
private int mLastBiometricMode;
private boolean mGoingToSleepVisibleNotOccluded;
@@ -139,6 +161,7 @@
(KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
+ private final DockManager mDockManager;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -159,8 +182,15 @@
mViewMediatorCallback = callback;
mLockPatternUtils = lockPatternUtils;
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
+ mGesturalNav = QuickStepContract.isGesturalMode(context);
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitorCallback);
Dependency.get(StatusBarStateController.class).addCallback(this);
+ Dependency.get(ConfigurationController.class).addCallback(this);
+ mDockManager = SysUiServiceProvider.getComponent(context, DockManager.class);
+ if (mDockManager != null) {
+ mDockManager.addListener(mDockEventListener);
+ mIsDocked = mDockManager.isDocked();
+ }
}
public void registerStatusBar(StatusBar statusBar,
@@ -241,6 +271,9 @@
}
private void hideBouncer(boolean destroyView) {
+ if (mBouncer == null) {
+ return;
+ }
mBouncer.hide(destroyView);
cancelPendingWakeupAction();
}
@@ -354,6 +387,16 @@
}
}
+ /**
+ * If {@link StatusBar} is pulsing.
+ */
+ public void setPulsing(boolean pulsing) {
+ if (mPulsing != pulsing) {
+ mPulsing = pulsing;
+ updateStates();
+ }
+ }
+
public void setNeedsInput(boolean needsInput) {
mStatusBarWindowController.setKeyguardNeedsInput(needsInput);
}
@@ -492,10 +535,20 @@
StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
}
+ @Override
public void onDensityOrFontScaleChanged() {
hideBouncer(true /* destroyView */);
}
+ @Override
+ public void onOverlayChanged() {
+ boolean gesturalNav = QuickStepContract.isGesturalMode(mContext);
+ if (gesturalNav != mGesturalNav) {
+ mGesturalNav = gesturalNav;
+ updateStates();
+ }
+ }
+
public void onThemeChanged() {
hideBouncer(true /* destroyView */);
mBouncer.prepare();
@@ -643,7 +696,10 @@
mLastBouncerDismissible = bouncerDismissible;
mLastRemoteInputActive = remoteInputActive;
mLastDozing = mDozing;
+ mLastPulsing = mPulsing;
mLastBiometricMode = mBiometricUnlockController.getMode();
+ mLastGesturalNav = mGesturalNav;
+ mLastIsDocked = mIsDocked;
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -671,8 +727,10 @@
int biometricMode = mBiometricUnlockController.getMode();
boolean keyguardShowing = mShowing && !mOccluded;
boolean hideWhileDozing = mDozing && biometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
+ boolean keyguardWithGestureNav = (keyguardShowing && !mDozing || mPulsing && !mIsDocked)
+ && mGesturalNav;
return (!keyguardShowing && !hideWhileDozing || mBouncer.isShowing()
- || mRemoteInputActive);
+ || mRemoteInputActive || keyguardWithGestureNav);
}
/**
@@ -681,8 +739,10 @@
protected boolean getLastNavBarVisible() {
boolean keyguardShowing = mLastShowing && !mLastOccluded;
boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
+ boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
+ || mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
- || mLastRemoteInputActive);
+ || mLastRemoteInputActive || keyguardWithGestureNav);
}
public boolean shouldDismissOnMenuPressed() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
index 1649f98..67df60a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/colorextraction/SysuiColorExtractorTests.java
@@ -18,6 +18,11 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
import android.app.WallpaperColors;
import android.app.WallpaperManager;
@@ -27,7 +32,9 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.colorextraction.ColorExtractor;
+import com.android.internal.colorextraction.types.Tonal;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -57,7 +64,7 @@
simulateEvent(extractor);
extractor.setWallpaperVisible(false);
- ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
+ ColorExtractor.GradientColors fallbackColors = extractor.getNeutralColors();
for (int type : sTypes) {
assertEquals("Not using fallback!",
@@ -96,7 +103,7 @@
extractor.setWallpaperVisible(true);
extractor.setHasBackdrop(true);
- ColorExtractor.GradientColors fallbackColors = extractor.getFallbackColors();
+ ColorExtractor.GradientColors fallbackColors = extractor.getNeutralColors();
for (int type : sTypes) {
assertEquals("Not using fallback!",
@@ -106,6 +113,19 @@
}
}
+ @Test
+ public void onUiModeChanged_reloadsColors() {
+ Tonal tonal = mock(Tonal.class);
+ ConfigurationController configurationController = mock(ConfigurationController.class);
+ SysuiColorExtractor sysuiColorExtractor = new SysuiColorExtractor(getContext(),
+ tonal, configurationController, false /* registerVisibility */);
+ verify(configurationController).addCallback(eq(sysuiColorExtractor));
+
+ reset(tonal);
+ sysuiColorExtractor.onUiModeChanged();
+ verify(tonal).applyFallback(any(), any());
+ }
+
private SysuiColorExtractor getTestableExtractor(ColorExtractor.GradientColors colors) {
return new SysuiColorExtractor(getContext(),
(inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
@@ -113,7 +133,7 @@
outGradientColorsNormal.set(colors);
outGradientColorsDark.set(colors);
outGradientColorsExtraDark.set(colors);
- }, false);
+ }, mock(ConfigurationController.class), false);
}
private void simulateEvent(SysuiColorExtractor extractor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
index 2020d4b..87a7757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ScrimViewTest.java
@@ -30,7 +30,7 @@
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
+import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.utils.leaks.LeakCheckedTest;
@@ -70,12 +70,10 @@
@Test
public void testCreation_initialColor() {
- GradientDrawable drawable = (GradientDrawable) mView.getDrawable();
+ ScrimDrawable drawable = (ScrimDrawable) mView.getDrawable();
ColorExtractor.GradientColors colors = mView.getColors();
assertEquals("Main color should be set upon creation",
drawable.getMainColor(), colors.getMainColor());
- assertEquals("Secondary color should be set upon creation",
- drawable.getSecondaryColor(), colors.getSecondaryColor());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 057f752..d2d294b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
@@ -71,6 +72,8 @@
private UnlockMethodCache mUnlockMethodCache;
@Mock
private TunerService mTunerService;
+ @Mock
+ private Handler mHandler;
private BiometricUnlockController mBiometricUnlockController;
@Before
@@ -172,12 +175,24 @@
verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
}
+ @Test
+ public void onFinishedGoingToSleep_authenticatesWhenPending() {
+ when(mUpdateMonitor.isGoingToSleep()).thenReturn(true);
+ mBiometricUnlockController.onFinishedGoingToSleep(-1);
+ verify(mHandler, never()).post(any());
+
+ mBiometricUnlockController.onBiometricAuthenticated(1 /* userId */,
+ BiometricSourceType.FACE);
+ mBiometricUnlockController.onFinishedGoingToSleep(-1);
+ verify(mHandler).post(any());
+ }
+
private class TestableBiometricUnlockController extends BiometricUnlockController {
TestableBiometricUnlockController(boolean faceDismissesKeyguard) {
super(mContext, mDozeScrimController,
mKeyguardViewMediator, mScrimController, mStatusBar, mUnlockMethodCache,
- new Handler(), mUpdateMonitor, mTunerService, 0 /* wakeUpDelay */,
+ mHandler, mUpdateMonitor, mTunerService, 0 /* wakeUpDelay */,
faceDismissesKeyguard);
mFaceDismissesKeyguard = faceDismissesKeyguard;
}
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index c57d4e9..b9b3a61 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -18,6 +18,10 @@
LOCAL_MODULE := frameworks-base-overlays
LOCAL_REQUIRED_MODULES := \
AccentColorBlackOverlay \
+ AccentColorCinnamonOverlay \
+ AccentColorOceanOverlay \
+ AccentColorOrchidOverlay \
+ AccentColorSpaceOverlay \
AccentColorGreenOverlay \
AccentColorPurpleOverlay \
DisplayCutoutEmulationCornerOverlay \
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
index 704ff2e..86fd47b 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
@@ -33,4 +33,8 @@
<!-- Controls the size of the back gesture inset. -->
<dimen name="config_backGestureInset">20dp</dimen>
+ <!-- Controls whether the navbar needs a scrim with
+ {@link Window#setEnsureNavigationBarContrastWhenTransparent}. -->
+ <bool name="config_navBarNeedsScrim">false</bool>
+
</resources>
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index afb8a15..fdc01e0 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1245,18 +1245,55 @@
* when necessary.
*/
public void logContextCommitted() {
- mHandler.sendMessage(obtainMessage(
- Session::doLogContextCommitted, this));
+ mHandler.sendMessage(obtainMessage(Session::handleLogContextCommitted, this));
}
- private void doLogContextCommitted() {
+ private void handleLogContextCommitted() {
+ final FillResponse lastResponse;
synchronized (mLock) {
- logContextCommittedLocked();
+ lastResponse = getLastResponseLocked("logContextCommited()");
+ }
+
+ if (lastResponse == null) {
+ Slog.w(TAG, "handleLogContextCommitted(): last response is null");
+ return;
+ }
+
+ // Merge UserData if necessary.
+ // Fields in packageUserData will override corresponding fields in genericUserData.
+ final UserData genericUserData = mService.getUserData();
+ final UserData packageUserData = lastResponse.getUserData();
+ final FieldClassificationUserData userData;
+ if (packageUserData == null && genericUserData == null) {
+ userData = null;
+ } else if (packageUserData != null && genericUserData != null) {
+ userData = new CompositeUserData(genericUserData, packageUserData);
+ } else if (packageUserData != null) {
+ userData = packageUserData;
+ } else {
+ userData = mService.getUserData();
+ }
+
+ final FieldClassificationStrategy fcStrategy = mService.getFieldClassificationStrategy();
+
+ // Sets field classification scores
+ if (userData != null && fcStrategy != null) {
+ logFieldClassificationScore(fcStrategy, userData);
+ } else {
+ logContextCommitted(null, null);
+ }
+ }
+
+ private void logContextCommitted(@Nullable ArrayList<AutofillId> detectedFieldIds,
+ @Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
+ synchronized (mLock) {
+ logContextCommittedLocked(detectedFieldIds, detectedFieldClassifications);
}
}
@GuardedBy("mLock")
- private void logContextCommittedLocked() {
+ private void logContextCommittedLocked(@Nullable ArrayList<AutofillId> detectedFieldIds,
+ @Nullable ArrayList<FieldClassification> detectedFieldClassifications) {
final FillResponse lastResponse = getLastResponseLocked("logContextCommited()");
if (lastResponse == null) return;
@@ -1310,21 +1347,6 @@
return;
}
- // Merge UserData if necessary.
- // Fields in packageUserData will override corresponding fields in genericUserData.
- final UserData genericUserData = mService.getUserData();
- final UserData packageUserData = lastResponse.getUserData();
- final FieldClassificationUserData userData;
- if (packageUserData == null && genericUserData == null) {
- userData = null;
- } else if (packageUserData != null && genericUserData != null) {
- userData = new CompositeUserData(genericUserData, packageUserData);
- } else if (packageUserData != null) {
- userData = packageUserData;
- } else {
- userData = mService.getUserData();
- }
-
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
final int state = viewState.getState();
@@ -1449,33 +1471,18 @@
}
}
- // Sets field classification scores
- final FieldClassificationStrategy fcStrategy = mService.getFieldClassificationStrategy();
- if (userData != null && fcStrategy != null) {
- logFieldClassificationScoreLocked(fcStrategy, ignoredDatasets, changedFieldIds,
- changedDatasetIds, manuallyFilledFieldIds, manuallyFilledDatasetIds,
- userData, mViewStates.values());
- } else {
- mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
- ignoredDatasets, changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds,
- mComponentName, mCompatMode);
- }
+ mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
+ ignoredDatasets, changedFieldIds, changedDatasetIds,
+ manuallyFilledFieldIds, manuallyFilledDatasetIds, detectedFieldIds,
+ detectedFieldClassifications, mComponentName, mCompatMode);
}
/**
* Adds the matches to {@code detectedFieldsIds} and {@code detectedFieldClassifications} for
* {@code fieldId} based on its {@code currentValue} and {@code userData}.
*/
- private void logFieldClassificationScoreLocked(
- @NonNull FieldClassificationStrategy fcStrategy,
- @NonNull ArraySet<String> ignoredDatasets,
- @NonNull ArrayList<AutofillId> changedFieldIds,
- @NonNull ArrayList<String> changedDatasetIds,
- @NonNull ArrayList<AutofillId> manuallyFilledFieldIds,
- @NonNull ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
- @NonNull FieldClassificationUserData userData,
- @NonNull Collection<ViewState> viewStates) {
+ private void logFieldClassificationScore(@NonNull FieldClassificationStrategy fcStrategy,
+ @NonNull FieldClassificationUserData userData) {
final String[] userValues = userData.getValues();
final String[] categoryIds = userData.getCategoryIds();
@@ -1501,6 +1508,11 @@
final ArrayList<FieldClassification> detectedFieldClassifications = new ArrayList<>(
maxFieldsSize);
+ final Collection<ViewState> viewStates;
+ synchronized (mLock) {
+ viewStates = mViewStates.values();
+ }
+
final int viewsSize = viewStates.size();
// First, we get all scores.
@@ -1516,10 +1528,7 @@
final RemoteCallback callback = new RemoteCallback((result) -> {
if (result == null) {
if (sDebug) Slog.d(TAG, "setFieldClassificationScore(): no results");
- mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
- ignoredDatasets, changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds,
- mComponentName, mCompatMode);
+ logContextCommitted(null, null);
return;
}
final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -1546,7 +1555,7 @@
final Float currentScore = scoresByField.get(categoryId);
if (currentScore != null && currentScore > score) {
if (sVerbose) {
- Slog.v(TAG, "skipping score " + score
+ Slog.v(TAG, "skipping score " + score
+ " because it's less than " + currentScore);
}
continue;
@@ -1556,8 +1565,7 @@
+ autofillId);
}
scoresByField.put(categoryId, score);
- }
- else if (sVerbose) {
+ } else if (sVerbose) {
Slog.v(TAG, "skipping score 0 at index " + j + " and id " + autofillId);
}
}
@@ -1581,10 +1589,7 @@
return;
}
- mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
- ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
- manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
- mComponentName, mCompatMode);
+ logContextCommitted(detectedFieldIds, detectedFieldClassifications);
});
fcStrategy.calculateScores(callback, currentValues, userValues, categoryIds,
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 47c85683..1bd367c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1764,7 +1764,8 @@
+ ", callingPackage: " + callingPackage;
// STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
Slog.wtf(TAG, errorMsg);
- throw new UnsupportedOperationException(errorMsg);
+ // TODO b/129995049: Resume throwing once issue is resolved.
+ // throw new UnsupportedOperationException(errorMsg);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 57de67e..e4c39cc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -108,7 +108,6 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
-import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
@@ -238,6 +237,16 @@
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
+ /**
+ * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
+ * by OEMs for configuration purposes, as this value is overridden by
+ * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
+ * (preferably via runtime resource overlays).
+ */
+ private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
+ "http://connectivitycheck.gstatic.com/generate_204";
+
// TODO: create better separation between radio types and network types
// how long to wait before switching back to a radio's default network
@@ -6543,7 +6552,7 @@
uid, newRules, metered, mRestrictBackground);
}
if (oldBlocked == newBlocked) {
- return;
+ continue;
}
final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -6701,9 +6710,20 @@
@Override
public String getCaptivePortalServerUrl() {
enforceConnectivityInternalPermission();
- final String defaultUrl = mContext.getResources().getString(
- R.string.config_networkDefaultCaptivePortalServerUrl);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl);
+ String settingUrl = mContext.getResources().getString(
+ R.string.config_networkCaptivePortalServerUrl);
+
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ settingUrl = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
}
@Override
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 8847e32..01a3a6f 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1020,11 +1020,7 @@
if (state.state == STATE_RUNNING_UNLOCKED) {
// We'll skip all later code, so we must tell listener it's already
// unlocked.
- try {
- unlockListener.onFinished(userId, null);
- } catch (RemoteException ignore) {
- // Ignore.
- }
+ notifyFinished(userId, unlockListener);
}
return true;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d360a63..e88d62f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4589,25 +4589,42 @@
pw.decreaseIndent();
pw.decreaseIndent();
- pw.println("enable <ID>");
+ pw.println("enable [--user <USER_ID>] <ID>");
pw.increaseIndent();
pw.println("allows the given input method ID to be used.");
+ pw.increaseIndent();
+ pw.print("--user <USER_ID>: Specify which user to enable.");
+ pw.println(" Assumes the current user if not specified.");
+ pw.decreaseIndent();
pw.decreaseIndent();
- pw.println("disable <ID>");
+ pw.println("disable [--user <USER_ID>] <ID>");
pw.increaseIndent();
pw.println("disallows the given input method ID to be used.");
+ pw.increaseIndent();
+ pw.print("--user <USER_ID>: Specify which user to disable.");
+ pw.println(" Assumes the current user if not specified.");
+ pw.decreaseIndent();
pw.decreaseIndent();
- pw.println("set <ID>");
+ pw.println("set [--user <USER_ID>] <ID>");
pw.increaseIndent();
pw.println("switches to the given input method ID.");
+ pw.increaseIndent();
+ pw.print("--user <USER_ID>: Specify which user to enable.");
+ pw.println(" Assumes the current user if not specified.");
+ pw.decreaseIndent();
pw.decreaseIndent();
- pw.println("reset");
+ pw.println("reset [--user <USER_ID>]");
pw.increaseIndent();
pw.println("reset currently selected/enabled IMEs to the default ones as if "
+ "the device is initially booted with the current locale.");
+ pw.increaseIndent();
+ pw.print("--user <USER_ID>: Specify which user to reset.");
+ pw.println(" Assumes the current user if not specified.");
+ pw.decreaseIndent();
+
pw.decreaseIndent();
pw.decreaseIndent();
@@ -4693,32 +4710,108 @@
@ShellCommandResult
private int handleShellCommandEnableDisableInputMethod(
@NonNull ShellCommand shellCommand, boolean enabled) {
- final String id = shellCommand.getNextArgRequired();
- final boolean previouslyEnabled;
+ final String imeId = shellCommand.getNextArgRequired();
+ final PrintWriter out = shellCommand.getOutPrintWriter();
+ final PrintWriter error = shellCommand.getErrPrintWriter();
+ final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
synchronized (mMethodMap) {
- if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
- return ShellCommandResult.SUCCESS;
+ final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+ mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+ for (int userId : userIds) {
+ if (!userHasDebugPriv(userId, shellCommand)) {
+ continue;
+ }
+ handleShellCommandEnableDisableInputMethodInternalLocked(userId, imeId, enabled,
+ out, error);
}
- // Make sure this is a valid input method.
- if (enabled && !mMethodMap.containsKey(id)) {
- final PrintWriter error = shellCommand.getErrPrintWriter();
- error.print("Unknown input method ");
- error.print(id);
- error.println(" cannot be enabled");
- return ShellCommandResult.SUCCESS;
- }
- previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
}
- final PrintWriter pr = shellCommand.getOutPrintWriter();
- pr.print("Input method ");
- pr.print(id);
- pr.print(": ");
- pr.print((enabled == previouslyEnabled) ? "already " : "now ");
- pr.println(enabled ? "enabled" : "disabled");
return ShellCommandResult.SUCCESS;
}
/**
+ * A special helper method for commands that only have {@code -u} and {@code --user} options.
+ *
+ * <p>You cannot use this helper method if the command has other options.</p>
+ *
+ * @param shellCommand {@link ShellCommand} from which options should be obtained.
+ * @return User ID to be resolved. {@link UserHandle#CURRENT} if not specified.
+ */
+ @BinderThread
+ @UserIdInt
+ private static int handleOptionsForCommandsThatOnlyHaveUserOption(ShellCommand shellCommand) {
+ while (true) {
+ final String nextOption = shellCommand.getNextOption();
+ if (nextOption == null) {
+ break;
+ }
+ switch (nextOption) {
+ case "-u":
+ case "--user":
+ return UserHandle.parseUserArg(shellCommand.getNextArgRequired());
+ }
+ }
+ return UserHandle.USER_CURRENT;
+ }
+
+ @BinderThread
+ private void handleShellCommandEnableDisableInputMethodInternalLocked(
+ @UserIdInt int userId, String imeId, boolean enabled, PrintWriter out,
+ PrintWriter error) {
+ boolean failedToEnableUnknownIme = false;
+ boolean previouslyEnabled = false;
+ if (userId == mSettings.getCurrentUserId()) {
+ if (enabled && !mMethodMap.containsKey(imeId)) {
+ failedToEnableUnknownIme = true;
+ } else {
+ previouslyEnabled = setInputMethodEnabledLocked(imeId, enabled);
+ }
+ } else {
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
+ methodMap, methodList);
+ final InputMethodSettings settings = new InputMethodSettings(mContext.getResources(),
+ mContext.getContentResolver(), methodMap, userId, false);
+ if (enabled) {
+ if (!methodMap.containsKey(imeId)) {
+ failedToEnableUnknownIme = true;
+ } else {
+ for (InputMethodInfo imi : settings.getEnabledInputMethodListLocked()) {
+ if (TextUtils.equals(imi.getId(), imeId)) {
+ previouslyEnabled = true;
+ break;
+ }
+ }
+ if (!previouslyEnabled) {
+ settings.appendAndPutEnabledInputMethodLocked(imeId, false);
+ }
+ }
+ } else {
+ previouslyEnabled =
+ settings.buildAndPutEnabledInputMethodsStrRemovingIdLocked(
+ new StringBuilder(),
+ settings.getEnabledInputMethodsAndSubtypeListLocked(), imeId);
+ }
+ }
+ if (failedToEnableUnknownIme) {
+ error.print("Unknown input method ");
+ error.print(imeId);
+ error.println(" cannot be enabled for user #" + userId);
+ } else {
+ out.print("Input method ");
+ out.print(imeId);
+ out.print(": ");
+ out.print((enabled == previouslyEnabled) ? "already " : "now ");
+ out.print(enabled ? "enabled" : "disabled");
+ out.print(" for user #");
+ out.println(userId);
+ }
+ }
+
+ /**
* Handles {@code adb shell ime set}.
* @param shellCommand {@link ShellCommand} object that is handling this command.
* @return Exit code of the command.
@@ -4726,17 +4819,55 @@
@BinderThread
@ShellCommandResult
private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
- final String id = shellCommand.getNextArgRequired();
+ final String imeId = shellCommand.getNextArgRequired();
+ final PrintWriter out = shellCommand.getOutPrintWriter();
+ final PrintWriter error = shellCommand.getErrPrintWriter();
+ final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
synchronized (mMethodMap) {
- if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
- return ShellCommandResult.SUCCESS;
+ final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+ mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+ for (int userId : userIds) {
+ if (!userHasDebugPriv(userId, shellCommand)) {
+ continue;
+ }
+ boolean failedToSelectUnknownIme = false;
+ if (userId == mSettings.getCurrentUserId()) {
+ if (mMethodMap.containsKey(imeId)) {
+ setInputMethodLocked(imeId, NOT_A_SUBTYPE_ID);
+ } else {
+ failedToSelectUnknownIme = true;
+ }
+ } else {
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
+ methodMap, methodList);
+ final InputMethodSettings settings = new InputMethodSettings(
+ mContext.getResources(), mContext.getContentResolver(), methodMap,
+ userId, false);
+ if (methodMap.containsKey(imeId)) {
+ settings.putSelectedInputMethod(imeId);
+ settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+ } else {
+ failedToSelectUnknownIme = true;
+ }
+ }
+ if (failedToSelectUnknownIme) {
+ error.print("Unknown input method ");
+ error.print(imeId);
+ error.print(" cannot be selected for user #");
+ error.println(userId);
+ } else {
+ out.print("Input method ");
+ out.print(imeId);
+ out.print(" selected for user #");
+ error.println(userId);
+ }
}
- setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
}
- final PrintWriter pr = shellCommand.getOutPrintWriter();
- pr.print("Input method ");
- pr.print(id);
- pr.println(" selected");
return ShellCommandResult.SUCCESS;
}
@@ -4748,45 +4879,67 @@
@BinderThread
@ShellCommandResult
private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
+ final PrintWriter out = shellCommand.getOutPrintWriter();
+ final int userIdToBeResolved = handleOptionsForCommandsThatOnlyHaveUserOption(shellCommand);
synchronized (mMethodMap) {
- if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
- return ShellCommandResult.SUCCESS;
- }
- final String nextIme;
- final List<InputMethodInfo> nextEnabledImes;
- hideCurrentInputLocked(0, null);
- unbindCurrentMethodLocked();
- // Reset the current IME
- resetSelectedInputMethodAndSubtypeLocked(null);
- // Also reset the settings of the current IME
- mSettings.putSelectedInputMethod(null);
- // Disable all enabled IMEs.
- mSettings.getEnabledInputMethodListLocked().forEach(
- imi -> setInputMethodEnabledLocked(imi.getId(), false));
- // Re-enable with default enabled IMEs.
- InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
- imi -> setInputMethodEnabledLocked(imi.getId(), true));
- updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(),
- mSettings.getCurrentUserId(),
- mContext.getBasePackageName());
- nextIme = mSettings.getSelectedInputMethod();
- nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
- final PrintWriter pr = shellCommand.getOutPrintWriter();
- pr.println("Reset current and enabled IMEs");
- pr.println("Newly selected IME:");
- pr.print(" "); pr.println(nextIme);
- pr.println("Newly enabled IMEs:");
- {
- final int N = nextEnabledImes.size();
- for (int i = 0; i < N; ++i) {
- pr.print(" ");
- pr.println(nextEnabledImes.get(i).getId());
+ final int[] userIds = InputMethodUtils.resolveUserId(userIdToBeResolved,
+ mSettings.getCurrentUserId(), shellCommand.getErrPrintWriter());
+ for (int userId : userIds) {
+ if (!userHasDebugPriv(userId, shellCommand)) {
+ continue;
}
+ final String nextIme;
+ final List<InputMethodInfo> nextEnabledImes;
+ if (userId == mSettings.getCurrentUserId()) {
+ hideCurrentInputLocked(0, null);
+ unbindCurrentMethodLocked();
+ // Reset the current IME
+ resetSelectedInputMethodAndSubtypeLocked(null);
+ // Also reset the settings of the current IME
+ mSettings.putSelectedInputMethod(null);
+ // Disable all enabled IMEs.
+ mSettings.getEnabledInputMethodListLocked().forEach(
+ imi -> setInputMethodEnabledLocked(imi.getId(), false));
+ // Re-enable with default enabled IMEs.
+ InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList).forEach(
+ imi -> setInputMethodEnabledLocked(imi.getId(), true));
+ updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+ mSettings.getEnabledInputMethodListLocked(),
+ mSettings.getCurrentUserId(),
+ mContext.getBasePackageName());
+ nextIme = mSettings.getSelectedInputMethod();
+ nextEnabledImes = mSettings.getEnabledInputMethodListLocked();
+ } else {
+ final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
+ final ArrayList<InputMethodInfo> methodList = new ArrayList<>();
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ new ArrayMap<>();
+ AdditionalSubtypeUtils.load(additionalSubtypeMap, userId);
+ queryInputMethodServicesInternal(mContext, userId, additionalSubtypeMap,
+ methodMap, methodList);
+ final InputMethodSettings settings = new InputMethodSettings(
+ mContext.getResources(), mContext.getContentResolver(), methodMap,
+ userId, false);
+
+ nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
+ nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
+
+ // Reset enabled IMEs.
+ settings.putEnabledInputMethodsStr("");
+ nextEnabledImes.forEach(imi -> settings.appendAndPutEnabledInputMethodLocked(
+ imi.getId(), false));
+
+ // Reset selected IME.
+ settings.putSelectedInputMethod(nextIme);
+ settings.putSelectedSubtype(NOT_A_SUBTYPE_ID);
+ }
+ out.println("Reset current and enabled IMEs for user #" + userId);
+ out.println(" Selected: " + nextIme);
+ nextEnabledImes.forEach(ime -> out.println(" Enabled: " + ime.getId()));
}
- return ShellCommandResult.SUCCESS;
}
+ return ShellCommandResult.SUCCESS;
}
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 4349b4a..b5e19ae 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -1003,7 +1003,7 @@
return res;
}
- private void putEnabledInputMethodsStr(@Nullable String str) {
+ void putEnabledInputMethodsStr(@Nullable String str) {
if (DEBUG) {
Slog.d(TAG, "putEnabledInputMethodStr: " + str);
}
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 2948aaf..2e72fbd 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -457,15 +457,13 @@
}
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
- // The NetworkRequest.Builder class is not used to construct the network request because
- // the ConnectivityService requires the network request to be constructed in this way
- // to extend support for requestRouteToHostAddress() method for pre-gnss@2.0 devices.
- NetworkCapabilities networkCapabilities = new NetworkCapabilities();
- networkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
- networkCapabilities.addCapability(getNetworkCapability(mAGpsType));
- NetworkRequest networkRequest = new NetworkRequest(networkCapabilities,
- getLegacyDataConnectionType(agpsType), ConnectivityManager.REQUEST_ID_UNSET,
- NetworkRequest.Type.REQUEST);
+ // The transport type must be set to NetworkCapabilities.TRANSPORT_CELLULAR for the
+ // deprecated requestRouteToHostAddress() method in ConnectivityService to work for
+ // pre-gnss@2.0 devices.
+ NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType));
+ networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ NetworkRequest networkRequest = networkRequestBuilder.build();
mConnMgr.requestNetwork(
networkRequest,
mSuplConnectivityCallback,
@@ -487,19 +485,6 @@
}
}
- private int getLegacyDataConnectionType(int agpsType) {
- switch (agpsType) {
- case AGPS_TYPE_C2K:
- case AGPS_TYPE_SUPL:
- return ConnectivityManager.TYPE_MOBILE_SUPL;
- case AGPS_TYPE_EIMS:
- return ConnectivityManager.TYPE_MOBILE_EMERGENCY;
- case AGPS_TYPE_IMS:
- return ConnectivityManager.TYPE_MOBILE_IMS;
- default:
- throw new IllegalArgumentException("agpsType: " + agpsType);
- }
- }
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
if (DEBUG) {
String message = String.format(
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index dec47a1..7f1b25ca 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1516,6 +1516,11 @@
}
@VisibleForTesting
+ void setZenHelper(ZenModeHelper zenHelper) {
+ mZenModeHelper = zenHelper;
+ }
+
+ @VisibleForTesting
void setIsAutomotive(boolean isAutomotive) {
mIsAutomotive = isAutomotive;
}
@@ -2856,7 +2861,7 @@
}
@Override
- public List<String> getAllowedAssistantCapabilities(String pkg) {
+ public List<String> getAllowedAssistantAdjustments(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
if (!isCallerSystemOrPhone()
@@ -2864,11 +2869,11 @@
throw new SecurityException("Not currently an assistant");
}
- return mAssistants.getAllowedAssistantCapabilities();
+ return mAssistants.getAllowedAssistantAdjustments();
}
@Override
- public void allowAssistantCapability(String adjustmentType) {
+ public void allowAssistantAdjustment(String adjustmentType) {
checkCallerIsSystemOrSystemUiOrShell();
mAssistants.allowAdjustmentType(adjustmentType);
@@ -2876,7 +2881,7 @@
}
@Override
- public void disallowAssistantCapability(String adjustmentType) {
+ public void disallowAssistantAdjustment(String adjustmentType) {
checkCallerIsSystemOrSystemUiOrShell();
mAssistants.disallowAdjustmentType(adjustmentType);
@@ -3563,7 +3568,7 @@
return;
}
boolean accessAllowed = false;
- String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ String[] packages = mPackageManagerClient.getPackagesForUid(uid);
final int packageCount = packages.length;
for (int i = 0; i < packageCount; i++) {
if (mConditionProviders.isPackageOrComponentAllowed(
@@ -7410,7 +7415,7 @@
}
}
- protected List<String> getAllowedAssistantCapabilities() {
+ protected List<String> getAllowedAssistantAdjustments() {
synchronized (mLock) {
List<String> types = new ArrayList<>();
types.addAll(mAllowedAdjustments);
@@ -7470,7 +7475,7 @@
private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
final INotificationListener assistant = (INotificationListener) info.service;
try {
- assistant.onCapabilitiesChanged();
+ assistant.onAllowedAdjustmentsChanged();
} catch (RemoteException ex) {
Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index ea7bf2d2..7e74cc2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -389,8 +389,8 @@
if (mConfig == null) return;
newConfig = mConfig.copy();
+ setAutomaticZenRuleStateLocked(newConfig, newConfig.automaticRules.get(id), condition);
}
- setAutomaticZenRuleState(newConfig, newConfig.automaticRules.get(id), condition);
}
public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) {
@@ -398,14 +398,15 @@
synchronized (mConfig) {
if (mConfig == null) return;
newConfig = mConfig.copy();
- }
- setAutomaticZenRuleState(newConfig,
- findMatchingRule(newConfig, ruleDefinition, condition),
- condition);
+ setAutomaticZenRuleStateLocked(newConfig,
+ findMatchingRule(newConfig, ruleDefinition, condition),
+ condition);
+ }
}
- private void setAutomaticZenRuleState(ZenModeConfig config, ZenRule rule, Condition condition) {
+ private void setAutomaticZenRuleStateLocked(ZenModeConfig config, ZenRule rule,
+ Condition condition) {
if (rule == null) return;
rule.condition = condition;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6c5abe4..928b8f6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -757,9 +757,124 @@
@Override public final boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
+
+ final List<PackageParser.Package> getStaticOverlayPackages(
+ Collection<PackageParser.Package> allPackages, String targetPackageName) {
+ if ("android".equals(targetPackageName)) {
+ // Static RROs targeting to "android", ie framework-res.apk, are already applied by
+ // native AssetManager.
+ return null;
+ }
+
+ List<PackageParser.Package> overlayPackages = null;
+ for (PackageParser.Package p : allPackages) {
+ if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
+ if (overlayPackages == null) {
+ overlayPackages = new ArrayList<>();
+ }
+ overlayPackages.add(p);
+ }
+ }
+ if (overlayPackages != null) {
+ Comparator<PackageParser.Package> cmp =
+ Comparator.comparingInt(p -> p.mOverlayPriority);
+ overlayPackages.sort(cmp);
+ }
+ return overlayPackages;
+ }
+
+ final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
+ String targetPath) {
+ if (overlayPackages == null || overlayPackages.isEmpty()) {
+ return null;
+ }
+ List<String> overlayPathList = null;
+ for (PackageParser.Package overlayPackage : overlayPackages) {
+ if (targetPath == null) {
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ continue;
+ }
+
+ try {
+ // Creates idmaps for system to parse correctly the Android manifest of the
+ // target package.
+ //
+ // OverlayManagerService will update each of them with a correct gid from its
+ // target package app id.
+ mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+ UserHandle.getSharedAppGid(
+ UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
+ if (overlayPathList == null) {
+ overlayPathList = new ArrayList<>();
+ }
+ overlayPathList.add(overlayPackage.baseCodePath);
+ } catch (InstallerException e) {
+ Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
+ overlayPackage.baseCodePath);
+ }
+ }
+ return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
+ }
+
+ String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ List<PackageParser.Package> overlayPackages;
+ synchronized (mInstallLock) {
+ synchronized (mPackages) {
+ overlayPackages = getStaticOverlayPackages(
+ mPackages.values(), targetPackageName);
+ }
+ // It is safe to keep overlayPackages without holding mPackages because static overlay
+ // packages can't be uninstalled or disabled.
+ return getStaticOverlayPaths(overlayPackages, targetPath);
+ }
+ }
+
+ @Override public final String[] getOverlayApks(String targetPackageName) {
+ return getStaticOverlayPaths(targetPackageName, null);
+ }
+
+ @Override public final String[] getOverlayPaths(String targetPackageName,
+ String targetPath) {
+ return getStaticOverlayPaths(targetPackageName, targetPath);
+ }
+ }
+
+ class ParallelPackageParserCallback extends PackageParserCallback {
+ List<PackageParser.Package> mOverlayPackages = null;
+
+ void findStaticOverlayPackages() {
+ synchronized (mPackages) {
+ for (PackageParser.Package p : mPackages.values()) {
+ if (p.mOverlayIsStatic) {
+ if (mOverlayPackages == null) {
+ mOverlayPackages = new ArrayList<>();
+ }
+ mOverlayPackages.add(p);
+ }
+ }
+ }
+ }
+
+ @Override
+ synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
+ // We can trust mOverlayPackages without holding mPackages because package uninstall
+ // can't happen while running parallel parsing.
+ // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
+ // because mInstallLock is held before running parallel parsing.
+ // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
+ return mOverlayPackages == null ? null :
+ getStaticOverlayPaths(
+ getStaticOverlayPackages(mOverlayPackages, targetPackageName),
+ targetPath);
+ }
}
final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
+ final ParallelPackageParserCallback mParallelPackageParserCallback =
+ new ParallelPackageParserCallback();
// Currently known shared libraries.
final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2443,6 +2558,8 @@
| SCAN_AS_ODM,
0);
+ mParallelPackageParserCallback.findStaticOverlayPackages();
+
// Find base frameworks (resource packages without code).
scanDirTracedLI(frameworkDir,
mDefParseFlags
@@ -2850,7 +2967,7 @@
// Uncompress and install any stubbed system applications.
// This must be done last to ensure all stubs are replaced or disabled.
- decompressSystemApplications(stubSystemApps, scanFlags);
+ installSystemStubPackages(stubSystemApps, scanFlags);
final int cachedNonSystemApps = PackageParser.sCachedPackageReadCount.get()
- cachedSystemApps;
@@ -3161,49 +3278,37 @@
* <p>In order to forcefully attempt an installation of a full application, go to app
* settings and enable the application.
*/
- private void decompressSystemApplications(@NonNull List<String> stubSystemApps, int scanFlags) {
- for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
- final String pkgName = stubSystemApps.get(i);
+ private void installSystemStubPackages(@NonNull List<String> systemStubPackageNames,
+ @ScanFlags int scanFlags) {
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String packageName = systemStubPackageNames.get(i);
// skip if the system package is already disabled
- if (mSettings.isDisabledSystemPackageLPr(pkgName)) {
- stubSystemApps.remove(i);
+ if (mSettings.isDisabledSystemPackageLPr(packageName)) {
+ systemStubPackageNames.remove(i);
continue;
}
// skip if the package isn't installed (?!); this should never happen
- final PackageParser.Package pkg = mPackages.get(pkgName);
+ final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- stubSystemApps.remove(i);
+ systemStubPackageNames.remove(i);
continue;
}
// skip if the package has been disabled by the user
- final PackageSetting ps = mSettings.mPackages.get(pkgName);
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
final int enabledState = ps.getEnabled(UserHandle.USER_SYSTEM);
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) {
- stubSystemApps.remove(i);
+ systemStubPackageNames.remove(i);
continue;
}
}
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Uncompressing system stub; pkg: " + pkgName);
- }
-
- // uncompress the binary to its eventual destination on /data
- final File scanFile = decompressPackage(pkg);
- if (scanFile == null) {
- continue;
- }
-
// install the package to replace the stub on /system
try {
- mSettings.disableSystemPackageLPw(pkgName, true /*replaced*/);
- removePackageLI(pkg, true /*chatty*/);
- scanPackageTracedLI(scanFile, 0 /*reparseFlags*/, scanFlags, 0, null);
+ installStubPackageLI(pkg, 0, scanFlags);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
UserHandle.USER_SYSTEM, "android");
- stubSystemApps.remove(i);
- continue;
+ systemStubPackageNames.remove(i);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse uncompressed system package: " + e.getMessage());
}
@@ -3212,8 +3317,8 @@
}
// disable any stub still left; these failed to install the full application
- for (int i = stubSystemApps.size() - 1; i >= 0; --i) {
- final String pkgName = stubSystemApps.get(i);
+ for (int i = systemStubPackageNames.size() - 1; i >= 0; --i) {
+ final String pkgName = systemStubPackageNames.get(i);
final PackageSetting ps = mSettings.mPackages.get(pkgName);
ps.setEnabled(PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
UserHandle.USER_SYSTEM, "android");
@@ -3222,20 +3327,107 @@
}
/**
+ * Extract, install and enable a stub package.
+ * <p>If the compressed file can not be extracted / installed for any reason, the stub
+ * APK will be installed and the package will be disabled. To recover from this situation,
+ * the user will need to go into system settings and re-enable the package.
+ */
+ private boolean enableCompressedPackage(PackageParser.Package stubPkg) {
+ final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
+ | PackageParser.PARSE_ENFORCE_CODE;
+ synchronized (mInstallLock) {
+ final PackageParser.Package pkg;
+ try (PackageFreezer freezer =
+ freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ pkg = installStubPackageLI(stubPkg, parseFlags, 0 /*scanFlags*/);
+ synchronized (mPackages) {
+ prepareAppDataAfterInstallLIF(pkg);
+ try {
+ updateSharedLibrariesLocked(pkg, null, mPackages);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
+ }
+ mPermissionManager.updatePermissions(
+ pkg.packageName, pkg, true, mPackages.values(),
+ mPermissionCallback);
+ mSettings.writeLPr();
+ }
+ } catch (PackageManagerException e) {
+ // Whoops! Something went very wrong; roll back to the stub and disable the package
+ try (PackageFreezer freezer =
+ freezePackage(stubPkg.packageName, "setEnabledSetting")) {
+ synchronized (mPackages) {
+ // NOTE: Ensure the system package is enabled; even for a compressed stub.
+ // If we don't, installing the system package fails during scan
+ enableSystemPackageLPw(stubPkg);
+ }
+ installPackageFromSystemLIF(stubPkg.codePath,
+ null /*allUserHandles*/, null /*origUserHandles*/,
+ null /*origPermissionsState*/, true /*writeSettings*/);
+ } catch (PackageManagerException pme) {
+ // Serious WTF; we have to be able to install the stub
+ Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.packageName, pme);
+ } finally {
+ // Disable the package; the stub by itself is not runnable
+ synchronized (mPackages) {
+ final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED,
+ UserHandle.USER_SYSTEM, "android");
+ }
+ mSettings.writeLPr();
+ }
+ }
+ return false;
+ }
+ clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
+ | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
+ mDexManager.notifyPackageUpdated(pkg.packageName,
+ pkg.baseCodePath, pkg.splitCodePaths);
+ }
+ return true;
+ }
+
+ private PackageParser.Package installStubPackageLI(PackageParser.Package stubPkg,
+ @ParseFlags int parseFlags, @ScanFlags int scanFlags)
+ throws PackageManagerException {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Uncompressing system stub; pkg: " + stubPkg.packageName);
+ }
+ // uncompress the binary to its eventual destination on /data
+ final File scanFile = decompressPackage(stubPkg.packageName, stubPkg.codePath);
+ if (scanFile == null) {
+ throw new PackageManagerException("Unable to decompress stub at " + stubPkg.codePath);
+ }
+ synchronized (mPackages) {
+ mSettings.disableSystemPackageLPw(stubPkg.packageName, true /*replaced*/);
+ }
+ removePackageLI(stubPkg, true /*chatty*/);
+ try {
+ return scanPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.packageName, e);
+ // Remove the failed install
+ removeCodePathLI(scanFile);
+ throw e;
+ }
+ }
+
+ /**
* Decompresses the given package on the system image onto
* the /data partition.
* @return The directory the package was decompressed into. Otherwise, {@code null}.
*/
- private File decompressPackage(PackageParser.Package pkg) {
- final File[] compressedFiles = getCompressedFiles(pkg.codePath);
+ private File decompressPackage(String packageName, String codePath) {
+ final File[] compressedFiles = getCompressedFiles(codePath);
if (compressedFiles == null || compressedFiles.length == 0) {
if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "No files to decompress: " + pkg.baseCodePath);
+ Slog.i(TAG, "No files to decompress: " + codePath);
}
return null;
}
final File dstCodePath =
- getNextCodePath(Environment.getDataAppDirectory(null), pkg.packageName);
+ getNextCodePath(Environment.getDataAppDirectory(null), packageName);
int ret = PackageManager.INSTALL_SUCCEEDED;
try {
Os.mkdir(dstCodePath.getAbsolutePath(), 0755);
@@ -3248,14 +3440,14 @@
ret = decompressFile(srcFile, dstFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + pkg.packageName
+ + "; pkg: " + packageName
+ ", file: " + dstFileName);
break;
}
}
} catch (ErrnoException e) {
logCriticalInfo(Log.ERROR, "Failed to decompress"
- + "; pkg: " + pkg.packageName
+ + "; pkg: " + packageName
+ ", err: " + e.errno);
}
if (ret == PackageManager.INSTALL_SUCCEEDED) {
@@ -3267,7 +3459,7 @@
null /*abiOverride*/);
} catch (IOException e) {
logCriticalInfo(Log.ERROR, "Failed to extract native libraries"
- + "; pkg: " + pkg.packageName);
+ + "; pkg: " + packageName);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
@@ -8665,7 +8857,7 @@
}
try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
- mPackageParserCallback)) {
+ mParallelPackageParserCallback)) {
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
@@ -18099,12 +18291,15 @@
return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
}
- PackageSetting uninstalledPs;
- PackageParser.Package pkg;
+ final PackageSetting uninstalledPs;
+ final PackageSetting disabledSystemPs;
+ final PackageParser.Package pkg;
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
int[] allUsers;
+ /** enabled state of the uninstalled application */
+ final int origEnabledState;
synchronized (mPackages) {
uninstalledPs = mSettings.mPackages.get(packageName);
if (uninstalledPs == null) {
@@ -18119,6 +18314,11 @@
return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
+ disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName);
+ // Save this off before we delete the package. When deleting a stub application
+ // we always set the enabled state to 'disabled'.
+ origEnabledState = uninstalledPs == null
+ ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId);
// Static shared libs can be declared by any package, so let us not
// allow removing a package if it provides a lib others depend on.
pkg = mPackages.get(packageName);
@@ -18187,10 +18387,30 @@
Runtime.getRuntime().gc();
// Delete the resources here after sending the broadcast to let
// other processes clean up before deleting resources.
- if (info.args != null) {
- synchronized (mInstallLock) {
+ synchronized (mInstallLock) {
+ if (info.args != null) {
info.args.doPostDeleteLI(true);
}
+ final PackageParser.Package stubPkg =
+ (disabledSystemPs == null) ? null : disabledSystemPs.pkg;
+ if (stubPkg != null && stubPkg.isStub) {
+ synchronized (mPackages) {
+ // restore the enabled state of the stub; the state is overwritten when
+ // the stub is uninstalled
+ final PackageSetting stubPs = mSettings.mPackages.get(stubPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(origEnabledState, userId, "android");
+ }
+ }
+ if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT
+ || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ + stubPkg.packageName);
+ }
+ enableCompressedPackage(stubPkg);
+ }
+ }
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -18596,7 +18816,14 @@
throw new SystemDeleteException(e);
} finally {
if (disabledPs.pkg.isStub) {
- mSettings.disableSystemPackageLPw(disabledPs.name, true /*replaced*/);
+ // We've re-installed the stub; make sure it's disabled here. If package was
+ // originally enabled, we'll install the compressed version of the application
+ // and re-enable it afterward.
+ final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.packageName);
+ if (stubPs != null) {
+ stubPs.setEnabled(
+ COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
+ }
}
}
}
@@ -20681,102 +20908,9 @@
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) {
- final File codePath = decompressPackage(deletedPkg);
- if (codePath == null) {
- Slog.e(TAG, "couldn't decompress pkg: " + pkgSetting.name);
+ if (!enableCompressedPackage(deletedPkg)) {
return;
}
- // TODO remove direct parsing of the package object during internal cleanup
- // of scan package
- // We need to call parse directly here for no other reason than we need
- // the new package in order to disable the old one [we use the information
- // for some internal optimization to optionally create a new package setting
- // object on replace]. However, we can't get the package from the scan
- // because the scan modifies live structures and we need to remove the
- // old [system] package from the system before a scan can be attempted.
- // Once scan is indempotent we can remove this parse and use the package
- // object we scanned, prior to adding it to package settings.
- final PackageParser pp = new PackageParser();
- pp.setSeparateProcesses(mSeparateProcesses);
- pp.setDisplayMetrics(mMetrics);
- pp.setCallback(mPackageParserCallback);
- final PackageParser.Package tmpPkg;
- try {
- final @ParseFlags int parseFlags = mDefParseFlags
- | PackageParser.PARSE_MUST_BE_APK
- | PackageParser.PARSE_IS_SYSTEM_DIR;
- tmpPkg = pp.parsePackage(codePath, parseFlags);
- } catch (PackageParserException e) {
- Slog.w(TAG, "Failed to parse compressed system package:" + pkgSetting.name, e);
- return;
- }
- synchronized (mInstallLock) {
- // Disable the stub and remove any package entries
- removePackageLI(deletedPkg, true);
- synchronized (mPackages) {
- disableSystemPackageLPw(deletedPkg, tmpPkg);
- }
- final PackageParser.Package pkg;
- try (PackageFreezer freezer =
- freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
- final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
- | PackageParser.PARSE_ENFORCE_CODE;
- pkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/,
- 0 /*currentTime*/, null /*user*/);
- prepareAppDataAfterInstallLIF(pkg);
- synchronized (mPackages) {
- try {
- updateSharedLibrariesLocked(pkg, null, mPackages);
- } catch (PackageManagerException e) {
- Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
- }
- mPermissionManager.updatePermissions(
- pkg.packageName, pkg, true, mPackages.values(),
- mPermissionCallback);
- mSettings.writeLPr();
- }
- } catch (PackageManagerException e) {
- // Whoops! Something went wrong; try to roll back to the stub
- Slog.w(TAG, "Failed to install compressed system package:"
- + pkgSetting.name, e);
- // Remove the failed install
- removeCodePathLI(codePath);
-
- // Install the system package
- try (PackageFreezer freezer =
- freezePackage(deletedPkg.packageName, "setEnabledSetting")) {
- synchronized (mPackages) {
- // NOTE: The system package always needs to be enabled; even
- // if it's for a compressed stub. If we don't, installing the
- // system package fails during scan [scanning checks the disabled
- // packages]. We will reverse this later, after we've "installed"
- // the stub.
- // This leaves us in a fragile state; the stub should never be
- // enabled, so, cross your fingers and hope nothing goes wrong
- // until we can disable the package later.
- enableSystemPackageLPw(deletedPkg);
- }
- installPackageFromSystemLIF(deletedPkg.codePath,
- /*isPrivileged*/ null /*allUserHandles*/,
- null /*origUserHandles*/, null /*origPermissionsState*/,
- true /*writeSettings*/);
- } catch (PackageManagerException pme) {
- Slog.w(TAG, "Failed to restore system package:"
- + deletedPkg.packageName, pme);
- } finally {
- synchronized (mPackages) {
- mSettings.disableSystemPackageLPw(
- deletedPkg.packageName, true /*replaced*/);
- mSettings.writeLPr();
- }
- }
- return;
- }
- clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE
- | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
- mDexManager.notifyPackageUpdated(pkg.packageName,
- pkg.baseCodePath, pkg.splitCodePaths);
- }
}
if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index f83b3ea..96924c04 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1458,8 +1458,18 @@
private void pullNumBiometricsEnrolled(int modality, int tagId, long elapsedNanos,
long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
- FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
- FaceManager faceManager = mContext.getSystemService(FaceManager.class);
+ final PackageManager pm = mContext.getPackageManager();
+ FingerprintManager fingerprintManager = null;
+ FaceManager faceManager = null;
+
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ fingerprintManager = mContext.getSystemService(
+ FingerprintManager.class);
+ }
+ if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
+ faceManager = mContext.getSystemService(FaceManager.class);
+ }
+
if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT && fingerprintManager == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index e2253e7..6cf36d6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -88,6 +88,8 @@
import static android.os.Build.VERSION_CODES.O;
import static android.os.Process.SYSTEM_UID;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER;
import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK;
@@ -195,6 +197,7 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
+import android.view.DisplayCutout;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.RemoteAnimationDefinition;
@@ -382,6 +385,12 @@
private int[] mHorizontalSizeConfigurations;
private int[] mSmallestSizeConfigurations;
+ /**
+ * The precomputed display insets for resolving configuration. It will be non-null if
+ * {@link #shouldUseSizeCompatMode} returns {@code true}.
+ */
+ private CompatDisplayInsets mCompatDisplayInsets;
+
boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
IVoiceInteractionSession voiceSession; // Voice interaction session for this activity
@@ -2833,6 +2842,11 @@
// The smallest screen width is the short side of screen bounds. Because the bounds
// and density won't be changed, smallestScreenWidthDp is also fixed.
overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp;
+
+ final ActivityDisplay display = getDisplay();
+ if (display != null && display.mDisplayContent != null) {
+ mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent);
+ }
}
}
onRequestedOverrideConfigurationChanged(overrideConfig);
@@ -2849,7 +2863,7 @@
super.resolveOverrideConfiguration(newParentConfiguration);
if (hasOverrideBounds) {
task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(),
- newParentConfiguration, true /* insideParentBounds */);
+ newParentConfiguration);
}
}
@@ -2922,9 +2936,8 @@
resolvedBounds.right -= resolvedAppBounds.left;
}
- // In size compatibility mode, activity is allowed to have larger bounds than its parent.
task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration,
- false /* insideParentBounds */);
+ mCompatDisplayInsets);
// Use parent orientation if it cannot be decided by bounds, so the activity can fit inside
// the parent bounds appropriately.
if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) {
@@ -3450,6 +3463,7 @@
// configuration.
getRequestedOverrideConfiguration().setToDefaults();
getResolvedOverrideConfiguration().setToDefaults();
+ mCompatDisplayInsets = null;
if (visible) {
// Configuration will be ensured when becoming visible, so if it is already visible,
// then the manual update is needed.
@@ -3796,4 +3810,46 @@
writeToProto(proto);
proto.end(token);
}
+
+ /**
+ * The precomputed insets of the display in each rotation. This is used to make the size
+ * compatibility mode activity compute the configuration without relying on its current display.
+ */
+ static class CompatDisplayInsets {
+ final int mDisplayWidth;
+ final int mDisplayHeight;
+
+ /** The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. */
+ final Rect[] mNonDecorInsets = new Rect[4];
+ /**
+ * The stableInsets for each rotation. Includes the status bar inset and the
+ * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and
+ * {@link Configuration#screenHeightDp}.
+ */
+ final Rect[] mStableInsets = new Rect[4];
+
+ CompatDisplayInsets(DisplayContent display) {
+ mDisplayWidth = display.mBaseDisplayWidth;
+ mDisplayHeight = display.mBaseDisplayHeight;
+ final DisplayPolicy policy = display.getDisplayPolicy();
+ final DisplayCutout cutout = display.getDisplayInfo().displayCutout;
+ for (int rotation = 0; rotation < 4; rotation++) {
+ mNonDecorInsets[rotation] = new Rect();
+ mStableInsets[rotation] = new Rect();
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? mDisplayHeight : mDisplayWidth;
+ final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+ policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
+ mStableInsets[rotation].set(mNonDecorInsets[rotation]);
+ policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
+ }
+ }
+
+ void getDisplayBounds(Rect outBounds, int rotation) {
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated ? mDisplayHeight : mDisplayWidth;
+ final int dh = rotated ? mDisplayWidth : mDisplayHeight;
+ outBounds.set(0, 0, dw, dh);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6ae7720..1934e25 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2775,6 +2775,16 @@
}
/**
+ * Calculates the stable insets if we already have the non-decor insets.
+ *
+ * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
+ * @param rotation The current display rotation.
+ */
+ void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
+ inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
+ }
+
+ /**
* Calculates the stable insets without running a layout.
*
* @param displayRotation the current display rotation
@@ -2789,7 +2799,7 @@
// Navigation bar and status bar.
getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
- outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
+ convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 714c227..15060e1 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -22,6 +22,7 @@
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -1688,6 +1689,8 @@
int colorBackground = 0;
int statusBarColor = 0;
int navigationBarColor = 0;
+ boolean statusBarContrastWhenTransparent = false;
+ boolean navigationBarContrastWhenTransparent = false;
boolean topActivity = true;
for (--activityNdx; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
@@ -1711,12 +1714,17 @@
colorBackground = r.taskDescription.getBackgroundColor();
statusBarColor = r.taskDescription.getStatusBarColor();
navigationBarColor = r.taskDescription.getNavigationBarColor();
+ statusBarContrastWhenTransparent =
+ r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
+ navigationBarContrastWhenTransparent =
+ r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
}
}
topActivity = false;
}
lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
- colorPrimary, colorBackground, statusBarColor, navigationBarColor);
+ colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+ statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent);
if (mTask != null) {
mTask.setTaskDescription(lastTaskDescription);
}
@@ -2041,15 +2049,12 @@
}
mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
- policy.getStableInsetsLw(displayInfo.rotation,
- displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
- mTmpInsets);
- intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
-
- policy.getNonDecorInsetsLw(displayInfo.rotation,
- displayInfo.logicalWidth, displayInfo.logicalHeight, displayInfo.displayCutout,
- mTmpInsets);
+ policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
+ displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
+
+ policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
+ intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
}
/**
@@ -2066,7 +2071,7 @@
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
@NonNull Configuration parentConfig) {
- computeConfigResourceOverrides(inOutConfig, parentConfig, true /* insideParentBounds */);
+ computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
}
/**
@@ -2078,7 +2083,8 @@
* just be inherited from the parent configuration.
**/
void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
- @NonNull Configuration parentConfig, boolean insideParentBounds) {
+ @NonNull Configuration parentConfig,
+ @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
if (windowingMode == WINDOWING_MODE_UNDEFINED) {
windowingMode = parentConfig.windowConfiguration.getWindowingMode();
@@ -2096,6 +2102,9 @@
inOutConfig.windowConfiguration.setAppBounds(bounds);
outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
}
+ // Non-null compatibility insets means the activity prefers to keep its original size, so
+ // the out bounds doesn't need to be restricted by the parent.
+ final boolean insideParentBounds = compatInsets == null;
if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
@@ -2118,6 +2127,17 @@
// Set to app bounds because it excludes decor insets.
mTmpNonDecorBounds.set(outAppBounds);
mTmpStableBounds.set(outAppBounds);
+
+ // Apply the given non-decor and stable insets to calculate the corresponding bounds
+ // for screen size of configuration.
+ final int rotation = parentConfig.windowConfiguration.getRotation();
+ if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
+ compatInsets.getDisplayBounds(mTmpBounds, rotation);
+ intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
+ compatInsets.mNonDecorInsets[rotation]);
+ intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
+ compatInsets.mStableInsets[rotation]);
+ }
}
if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 6fe8b43..f31416c 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -362,11 +362,9 @@
}
final int color = ColorUtils.setAlphaComponent(
task.getTaskDescription().getBackgroundColor(), 255);
- final int statusBarColor = task.getTaskDescription().getStatusBarColor();
- final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
final LayoutParams attrs = mainWindow.getAttrs();
final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
- attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
+ attrs.privateFlags, attrs.systemUiVisibility, task.getTaskDescription());
final int width = mainWindow.getFrameLw().width();
final int height = mainWindow.getFrameLw().height();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 39b5662..5d99db5 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -18,6 +18,8 @@
import static android.graphics.Color.WHITE;
import static android.graphics.Color.alpha;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
@@ -148,9 +150,8 @@
final Rect tmpStableInsets = new Rect();
final InsetsState mTmpInsetsState = new InsetsState();
final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
- int backgroundColor = WHITE;
- int statusBarColor = 0;
- int navigationBarColor = 0;
+ final TaskDescription taskDescription = new TaskDescription();
+ taskDescription.setBackgroundColor(WHITE);
final int sysUiVis;
final int windowFlags;
final int windowPrivateFlags;
@@ -194,11 +195,9 @@
layoutParams.systemUiVisibility = sysUiVis;
layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
- final TaskDescription taskDescription = task.getTaskDescription();
- if (taskDescription != null) {
- backgroundColor = taskDescription.getBackgroundColor();
- statusBarColor = taskDescription.getStatusBarColor();
- navigationBarColor = taskDescription.getNavigationBarColor();
+ final TaskDescription td = task.getTaskDescription();
+ if (td != null) {
+ taskDescription.copyFrom(td);
}
taskBounds = new Rect();
task.getBounds(taskBounds);
@@ -216,8 +215,8 @@
// Local call.
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
- surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
- navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
+ surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
+ windowFlags, windowPrivateFlags, taskBounds,
currentOrientation);
window.setOuter(snapshotSurface);
try {
@@ -234,9 +233,9 @@
@VisibleForTesting
TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
- TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
- int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
- Rect taskBounds, int currentOrientation) {
+ TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
+ int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
+ int currentOrientation) {
mService = service;
mSurface = new Surface();
mHandler = new Handler(mService.mH.getLooper());
@@ -245,11 +244,12 @@
mSurfaceControl = surfaceControl;
mSnapshot = snapshot;
mTitle = title;
+ int backgroundColor = taskDescription.getBackgroundColor();
mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
mTaskBounds = taskBounds;
mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
- windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
- mStatusBarColor = statusBarColor;
+ windowPrivateFlags, sysUiVis, taskDescription);
+ mStatusBarColor = taskDescription.getStatusBarColor();
mOrientationOnCreation = currentOrientation;
}
@@ -490,7 +490,7 @@
private final int mSysUiVis;
SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
- int statusBarColor, int navigationBarColor) {
+ TaskDescription taskDescription) {
mWindowFlags = windowFlags;
mWindowPrivateFlags = windowPrivateFlags;
mSysUiVis = sysUiVis;
@@ -498,11 +498,17 @@
final int semiTransparent = context.getColor(
R.color.system_bar_background_semi_transparent);
mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
- semiTransparent, statusBarColor);
+ semiTransparent, taskDescription.getStatusBarColor(), sysUiVis,
+ SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ taskDescription.getEnsureStatusBarContrastWhenTransparent());
mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
- FLAG_TRANSLUCENT_NAVIGATION, semiTransparent, navigationBarColor);
+ FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+ taskDescription.getNavigationBarColor(), sysUiVis,
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+ && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
mStatusBarPaint.setColor(mStatusBarColor);
- mNavigationBarPaint.setColor(navigationBarColor);
+ mNavigationBarPaint.setColor(mNavigationBarColor);
}
void setInsets(Rect contentInsets, Rect stableInsets) {
diff --git a/services/core/xsd/vts/Android.bp b/services/core/xsd/vts/Android.bp
new file mode 100644
index 0000000..967750d
--- /dev/null
+++ b/services/core/xsd/vts/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_test {
+ name: "vts_defaultPermissions_validate_test",
+ srcs: [
+ "ValidateDefaultPermissions.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "libxml2",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/services/core/xsd/vts/Android.mk b/services/core/xsd/vts/Android.mk
new file mode 100644
index 0000000..6dc2c43
--- /dev/null
+++ b/services/core/xsd/vts/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidateDefaultPermissions
+include test/vts/tools/build/Android.host_config.mk
diff --git a/services/core/xsd/vts/AndroidTest.xml b/services/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..4f3b2ef
--- /dev/null
+++ b/services/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsValidateDefaultPermissions.">
+ <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ <option name="push" value="DATA/etc/default-permissions.xsd->/data/local/tmp/default-permissions.xsd"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsValidateDefaultPermissions"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/services/core/xsd/vts/ValidateDefaultPermissions.cpp b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
new file mode 100644
index 0000000..54c115b
--- /dev/null
+++ b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, mediaDefaultPermissions) {
+ RecordProperty("description",
+ "Verify that the default-permissions file "
+ "is valid according to the schema");
+
+ const char* location = "/vendor/etc/default-permissions";
+
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("default-permissions.xml", {location},
+ "/data/local/tmp/default-permissions.xsd");
+}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 7befd087..6b5842f 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -32,6 +32,7 @@
import android.net.ip.IIpClientCallbacks;
import android.net.util.SharedLog;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -148,14 +149,18 @@
private class NetworkStackConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- log("Network stack service connected");
+ logi("Network stack service connected");
registerNetworkStackService(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
- // TODO: crash/reboot the system ?
- logWtf("Lost network stack connector", null);
+ // The system has lost its network stack (probably due to a crash in the
+ // network stack process): better crash rather than stay in a bad state where all
+ // networking is broken.
+ // onServiceDisconnected is not being called on device shutdown, so this method being
+ // called always indicates a bad state for the system server.
+ maybeCrashWithTerribleFailure("Lost network stack");
}
};
@@ -211,8 +216,7 @@
}
if (intent == null) {
- logWtf("Could not resolve the network stack", null);
- // TODO: crash/reboot system server ?
+ maybeCrashWithTerribleFailure("Could not resolve the network stack");
return;
}
@@ -220,9 +224,9 @@
// NetworkStackConnection.onServiceConnected().
if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
- logWtf("Could not bind to network stack with " + intent, null);
+ maybeCrashWithTerribleFailure(
+ "Could not bind to network stack in-process, or in app with " + intent);
return;
- // TODO: crash/reboot system server if no network stack after a timeout ?
}
log("Network stack service start requested");
@@ -270,6 +274,16 @@
}
}
+ private void maybeCrashWithTerribleFailure(@NonNull String message) {
+ logWtf(message, null);
+ if (Build.IS_DEBUGGABLE) {
+ throw new IllegalStateException(message);
+ }
+ }
+
+ /**
+ * Log a message in the local log.
+ */
private void log(@NonNull String message) {
synchronized (mLog) {
mLog.log(message);
@@ -290,6 +304,15 @@
}
/**
+ * Log a message in the local and system logs.
+ */
+ private void logi(@NonNull String message) {
+ synchronized (mLog) {
+ mLog.i(message);
+ }
+ }
+
+ /**
* For non-system server clients, get the connector registered by the system server.
*/
private INetworkStackConnector getRemoteConnector() {
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
index a17cb464..bb4a603 100644
--- a/services/net/java/android/net/shared/NetworkMonitorUtils.java
+++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java
@@ -21,9 +21,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import android.content.Context;
import android.net.NetworkCapabilities;
-import android.provider.Settings;
/** @hide */
public class NetworkMonitorUtils {
@@ -45,16 +43,6 @@
"android.permission.ACCESS_NETWORK_CONDITIONS";
/**
- * Get the captive portal server HTTP URL that is configured on the device.
- */
- public static String getCaptivePortalServerHttpUrl(Context context, String defaultUrl) {
- final String settingUrl = Settings.Global.getString(
- context.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
- return settingUrl != null ? settingUrl : defaultUrl;
- }
-
- /**
* Return whether validation is required for a network.
* @param dfltNetCap Default requested network capabilities.
* @param nc Network capabilities of the network to test.
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index bafcd5f..355ff63 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -348,6 +348,7 @@
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
+ when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
// write to a test file; the system file isn't readable from tests
mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -4948,22 +4949,26 @@
assertEquals(1, mService.getNotificationRecordCount());
}
- public void testGetAllowedAssistantCapabilities() throws Exception {
- List<String> capabilities = mBinderService.getAllowedAssistantCapabilities(null);
+ @Test
+ public void testGetAllowedAssistantAdjustments() throws Exception {
+ List<String> capabilities = mBinderService.getAllowedAssistantAdjustments(null);
assertNotNull(capabilities);
for (int i = capabilities.size() - 1; i >= 0; i--) {
String capability = capabilities.get(i);
- mBinderService.disallowAssistantCapability(capability);
- assertEquals(i + 1, mBinderService.getAllowedAssistantCapabilities(null).size());
- List<String> currentCapabilities = mBinderService.getAllowedAssistantCapabilities(null);
+ mBinderService.disallowAssistantAdjustment(capability);
+ assertEquals(i + 1, mBinderService.getAllowedAssistantAdjustments(null).size());
+ List<String> currentCapabilities = mBinderService.getAllowedAssistantAdjustments(null);
assertNotNull(currentCapabilities);
assertFalse(currentCapabilities.contains(capability));
}
}
+ @Test
public void testAdjustRestrictedKey() throws Exception {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(r);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true);
when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false);
@@ -4981,8 +4986,12 @@
assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
}
+ @Test
public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
- ComponentName owner = mock(ComponentName.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mock(ZenModeHelper.class));
+ ComponentName owner = new ComponentName(mContext, this.getClass());
ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
boolean isEnabled = true;
AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
@@ -4990,7 +4999,7 @@
try {
mBinderService.addAutomaticZenRule(rule);
- fail("Zen policy only aplies to priority only mode");
+ fail("Zen policy only applies to priority only mode");
} catch (IllegalArgumentException e) {
// yay
}
@@ -5004,6 +5013,7 @@
mBinderService.addAutomaticZenRule(rule);
}
+ @Test
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
try {
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
@@ -5020,6 +5030,7 @@
mUid + UserHandle.PER_USER_RANGE);
}
+ @Test
public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
try {
mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 32e96a5..44390b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -57,6 +57,7 @@
import android.platform.test.annotations.Presubmit;
import android.util.MergedConfiguration;
import android.util.MutableBoolean;
+import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
@@ -87,6 +88,10 @@
doReturn(false).when(mService).isBooting();
doReturn(true).when(mService).isBooted();
+
+ final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
+ doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
+ doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index dc307b5..d87eed2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -25,7 +25,10 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Surface.ROTATION_0;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.hamcrest.Matchers.not;
@@ -35,6 +38,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import android.app.ActivityManager;
@@ -357,6 +362,7 @@
parentConfig.densityDpi = 400;
parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
+ parentConfig.windowConfiguration.setRotation(ROTATION_0);
// Portrait bounds.
inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
@@ -370,12 +376,27 @@
inOutConfig.setToDefaults();
// Landscape bounds.
inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
+
+ // Setup the display with a top stable inset. The later assertion will ensure the inset is
+ // excluded from screenHeightDp.
+ final int statusBarHeight = 100;
+ final DisplayContent displayContent = mock(DisplayContent.class);
+ final DisplayPolicy policy = mock(DisplayPolicy.class);
+ doAnswer(invocationOnMock -> {
+ final Rect insets = invocationOnMock.<Rect>getArgument(0);
+ insets.top = statusBarHeight;
+ return null;
+ }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
+ doReturn(policy).when(displayContent).getDisplayPolicy();
+ doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
+
// Without limiting to be inside the parent bounds, the out screen size should keep relative
// to the input bounds.
- task.computeConfigResourceOverrides(inOutConfig, parentConfig,
- false /* insideParentBounds */);
+ final ActivityRecord.CompatDisplayInsets compatIntsets =
+ new ActivityRecord.CompatDisplayInsets(displayContent);
+ task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
- assertEquals(shortSide * DENSITY_DEFAULT / parentConfig.densityDpi,
+ assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
inOutConfig.screenHeightDp);
assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
inOutConfig.screenWidthDp);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index ca815ec..cb6dc6d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
import android.content.ComponentName;
import android.graphics.Canvas;
@@ -38,7 +39,6 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.view.Surface;
import android.view.SurfaceControl;
import androidx.test.filters.SmallTest;
@@ -67,8 +67,17 @@
ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */,
WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
- Color.WHITE, Color.RED, Color.BLUE, sysuiVis, windowFlags, 0, taskBounds,
- ORIENTATION_PORTRAIT);
+ createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
+ taskBounds, ORIENTATION_PORTRAIT);
+ }
+
+ private static TaskDescription createTaskDescription(int background, int statusBar,
+ int navigationBar) {
+ final TaskDescription td = new TaskDescription();
+ td.setBackgroundColor(background);
+ td.setStatusBarColor(statusBar);
+ td.setNavigationBarColor(navigationBar);
+ return td;
}
private void setupSurface(int width, int height) {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ee28ca2..cf15b92 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -87,8 +87,8 @@
private int mCarrierId;
/**
- * The source of the name, NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
- * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
+ * The source of the name, NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
+ * NAME_SOURCE_USER_INPUT.
*/
private int mNameSource;
@@ -103,7 +103,7 @@
private String mNumber;
/**
- * Data roaming state, DATA_RAOMING_ENABLE, DATA_RAOMING_DISABLE
+ * Data roaming state, DATA_ROAMING_ENABLE, DATA_ROAMING_DISABLE
*/
private int mDataRoaming;
@@ -306,8 +306,8 @@
}
/**
- * @return the source of the name, eg NAME_SOURCE_UNDEFINED, NAME_SOURCE_DEFAULT_SOURCE,
- * NAME_SOURCE_SIM_SOURCE or NAME_SOURCE_USER_INPUT.
+ * @return the source of the name, eg NAME_SOURCE_DEFAULT_SOURCE, NAME_SOURCE_SIM_SOURCE or
+ * NAME_SOURCE_USER_INPUT.
* @hide
*/
@UnsupportedAppUsage
@@ -316,8 +316,8 @@
}
/**
- * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a user
- * interface.
+ * Creates and returns an icon {@code Bitmap} to represent this {@code SubscriptionInfo} in a
+ * user interface.
*
* @param context A {@code Context} to get the {@code DisplayMetrics}s from.
*
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 57c84a6..0c63411 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -364,12 +364,6 @@
public static final String NAME_SOURCE = "name_source";
/**
- * The name_source is undefined
- * @hide
- */
- public static final int NAME_SOURCE_UNDEFINDED = -1;
-
- /**
* The name_source is the default
* @hide
*/
@@ -1598,27 +1592,16 @@
}
/**
- * Set display name by simInfo index
- * @param displayName the display name of SIM card
- * @param subId the unique SubscriptionInfo index in database
- * @return the number of records updated
- * @hide
- */
- public int setDisplayName(String displayName, int subId) {
- return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED);
- }
-
- /**
* Set display name by simInfo index with name source
* @param displayName the display name of SIM card
* @param subId the unique SubscriptionInfo index in database
* @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE,
- * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED
+ * 2: NAME_SOURCE_USER_INPUT
* @return the number of records updated or < 0 if invalid subId
* @hide
*/
@UnsupportedAppUsage
- public int setDisplayName(String displayName, int subId, long nameSource) {
+ public int setDisplayName(String displayName, int subId, int nameSource) {
if (VDBG) {
logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId
+ " nameSource:" + nameSource);
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 01fdae8..cfba052 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -145,21 +145,13 @@
int setIconTint(int tint, int subId);
/**
- * Set display name by simInfo index
- * @param displayName the display name of SIM card
- * @param subId the unique SubscriptionInfo index in database
- * @return the number of records updated
- */
- int setDisplayName(String displayName, int subId);
-
- /**
* Set display name by simInfo index with name source
* @param displayName the display name of SIM card
* @param subId the unique SubscriptionInfo index in database
* @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT
* @return the number of records updated
*/
- int setDisplayNameUsingSrc(String displayName, int subId, long nameSource);
+ int setDisplayNameUsingSrc(String displayName, int subId, int nameSource);
/**
* Set phone number by subId