summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--api/test-current.txt5
-rw-r--r--cmds/incidentd/tests/EncodedBuffer_test.cpp80
-rw-r--r--cmds/statsd/Android.mk4
-rw-r--r--cmds/statsd/src/AnomalyMonitor.cpp108
-rw-r--r--cmds/statsd/src/AnomalyMonitor.h138
-rw-r--r--cmds/statsd/src/DropboxReader.cpp9
-rw-r--r--cmds/statsd/src/DropboxReader.h9
-rw-r--r--cmds/statsd/src/DropboxWriter.cpp10
-rw-r--r--cmds/statsd/src/DropboxWriter.h9
-rw-r--r--cmds/statsd/src/LogEntryPrinter.cpp8
-rw-r--r--cmds/statsd/src/LogEntryPrinter.h8
-rw-r--r--cmds/statsd/src/LogReader.cpp7
-rw-r--r--cmds/statsd/src/LogReader.h9
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp10
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h9
-rw-r--r--cmds/statsd/src/StatsService.cpp103
-rw-r--r--cmds/statsd/src/StatsService.h44
-rw-r--r--cmds/statsd/src/indexed_priority_queue.h199
-rw-r--r--cmds/statsd/src/main.cpp5
-rw-r--r--cmds/statsd/src/parse_util.cpp8
-rw-r--r--cmds/statsd/src/stats_constants.proto3
-rw-r--r--cmds/statsd/tests/indexed_priority_queue_test.cpp188
-rw-r--r--config/compiled-classes-phone2
-rw-r--r--config/preloaded-classes2
-rw-r--r--core/java/android/app/ActivityManager.java39
-rw-r--r--core/java/android/app/ActivityOptions.java51
-rw-r--r--core/java/android/app/IActivityManager.aidl5
-rw-r--r--core/java/android/app/ITaskStackListener.aidl2
-rw-r--r--core/java/android/app/Notification.java25
-rw-r--r--core/java/android/app/TaskStackListener.java3
-rw-r--r--core/java/android/app/WindowConfiguration.java14
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java131
-rw-r--r--core/java/android/content/Context.java7
-rw-r--r--core/java/android/content/pm/ActivityInfo.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteConnection.java26
-rw-r--r--core/java/android/database/sqlite/SQLiteConnectionPool.java8
-rw-r--r--core/java/android/hardware/Camera.java66
-rw-r--r--core/java/android/os/IStatsCompanionService.aidl51
-rw-r--r--core/java/android/os/IStatsManager.aidl28
-rw-r--r--core/java/android/os/ParcelableException.java6
-rwxr-xr-xcore/java/android/provider/Settings.java7
-rw-r--r--core/java/android/service/carrier/CarrierService.java26
-rw-r--r--core/java/android/service/carrier/ICarrierService.aidl3
-rw-r--r--core/java/android/text/DynamicLayout.java2
-rw-r--r--core/java/android/view/SurfaceControl.java10
-rw-r--r--core/java/android/view/SurfaceView.java3
-rw-r--r--core/java/android/view/autofill/AutofillManager.java114
-rw-r--r--core/java/android/view/autofill/IAutoFillManagerClient.aidl11
-rw-r--r--core/java/android/webkit/WebViewFactory.java4
-rw-r--r--core/java/android/webkit/WebViewZygote.java19
-rw-r--r--core/java/android/widget/RemoteViews.java75
-rw-r--r--core/java/android/widget/Switch.java5
-rw-r--r--core/java/android/widget/TabWidget.java32
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/java/com/android/internal/app/NightDisplayController.java150
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp4
-rw-r--r--core/jni/android/graphics/Movie.cpp3
-rw-r--r--core/jni/android/graphics/Utils.cpp2
-rw-r--r--core/jni/android/graphics/Utils.h4
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp6
-rw-r--r--core/jni/android_util_Binder.cpp140
-rw-r--r--core/jni/android_view_SurfaceControl.cpp12
-rw-r--r--core/proto/android/server/activitymanagerservice.proto84
-rw-r--r--core/res/AndroidManifest.xml16
-rw-r--r--core/res/res/values/dimens.xml5
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/coretests/src/android/text/DynamicLayoutTest.java17
-rw-r--r--core/tests/coretests/src/android/widget/RemoteViewsTest.java17
-rw-r--r--data/etc/platform.xml3
-rw-r--r--media/java/android/media/MediaRouter.java6
-rw-r--r--packages/SettingsLib/res/layout/preference_two_target.xml1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java70
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java98
-rw-r--r--packages/SystemUI/OWNERS8
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java107
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java93
-rw-r--r--proto/src/metrics_constants.proto5
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java16
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java60
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java18
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java9
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java46
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java4
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java161
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java47
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java28
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java422
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java140
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java22
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java10
-rw-r--r--services/core/java/com/android/server/am/LockTaskController.java5
-rw-r--r--services/core/java/com/android/server/am/TaskChangeNotificationController.java6
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java3
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java73
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java20
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/OffloadController.java53
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java45
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java6
-rw-r--r--services/core/java/com/android/server/display/NightDisplayService.java101
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java7
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java27
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java4
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java5
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java35
-rw-r--r--services/core/java/com/android/server/notification/ScheduleCalendar.java3
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java47
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java14
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java2
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java259
-rw-r--r--services/core/java/com/android/server/twilight/TwilightState.java23
-rw-r--r--services/core/java/com/android/server/utils/PriorityDump.java14
-rw-r--r--services/core/java/com/android/server/webkit/SystemImpl.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java18
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java18
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java5
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java2
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java26
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java42
159 files changed, 3704 insertions, 1400 deletions
diff --git a/Android.mk b/Android.mk
index 7bb64482df73..aa7caa547e43 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,6 +270,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IRecoverySystemProgressListener.aidl \
core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/ISchedulingPolicyService.aidl \
+ core/java/android/os/IStatsCompanionService.aidl \
core/java/android/os/IStatsManager.aidl \
core/java/android/os/IThermalEventListener.aidl \
core/java/android/os/IThermalService.aidl \
diff --git a/api/test-current.txt b/api/test-current.txt
index a54a79a689b8..a62bffca7f64 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4052,10 +4052,11 @@ package android.app {
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public void requestUsageTimeReport(android.app.PendingIntent);
method public android.app.ActivityOptions setAppVerificationBundle(android.os.Bundle);
+ method public void setLaunchActivityType(int);
method public android.app.ActivityOptions setLaunchBounds(android.graphics.Rect);
method public android.app.ActivityOptions setLaunchDisplayId(int);
- method public void setLaunchStackId(int);
method public void setLaunchTaskId(int);
+ method public void setLaunchWindowingMode(int);
method public void setTaskOverlay(boolean, boolean);
method public android.os.Bundle toBundle();
method public void update(android.app.ActivityOptions);
@@ -6244,6 +6245,7 @@ package android.app {
field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
+ field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4
field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
@@ -10197,6 +10199,7 @@ package android.content.pm {
field public static final int PERSIST_ACROSS_REBOOTS = 2; // 0x2
field public static final int PERSIST_NEVER = 1; // 0x1
field public static final int PERSIST_ROOT_ONLY = 0; // 0x0
+ field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
field public static final int SCREEN_ORIENTATION_BEHIND = 3; // 0x3
field public static final int SCREEN_ORIENTATION_FULL_SENSOR = 10; // 0xa
field public static final int SCREEN_ORIENTATION_FULL_USER = 13; // 0xd
diff --git a/cmds/incidentd/tests/EncodedBuffer_test.cpp b/cmds/incidentd/tests/EncodedBuffer_test.cpp
index 98c39bded512..37a938a6de07 100644
--- a/cmds/incidentd/tests/EncodedBuffer_test.cpp
+++ b/cmds/incidentd/tests/EncodedBuffer_test.cpp
@@ -42,40 +42,17 @@ const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
-static Privacy* create_privacy(uint32_t field_id, uint8_t type, uint8_t dest) {
- struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
- p->field_id = field_id;
- p->type = type;
- p->children = NULL;
- p->dest = dest;
- p->patterns = NULL;
- return p;
-}
-
-static Privacy* create_message_privacy(uint32_t field_id, Privacy** children)
-{
- struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
- p->field_id = field_id;
- p->type = MESSAGE_TYPE;
- p->children = children;
- p->dest = EXPLICIT;
- p->patterns = NULL;
- return p;
-}
-
-static Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns)
-{
- struct Privacy* p = (struct Privacy*)malloc(sizeof(struct Privacy));
- p->field_id = field_id;
- p->type = STRING_TYPE;
- p->children = NULL;
- p->dest = dest;
- p->patterns = patterns;
- return p;
-}
-
class EncodedBufferTest : public Test {
public:
+ virtual ~EncodedBufferTest() {
+ // Delete in reverse order of construction, to be consistent with
+ // regular allocation/deallocation.
+ while (!privacies.empty()) {
+ delete privacies.back();
+ privacies.pop_back();
+ }
+ }
+
virtual void SetUp() override {
ASSERT_NE(tf.fd, -1);
}
@@ -113,9 +90,48 @@ public:
assertStrip(dest, expected, create_message_privacy(300, list));
}
+ Privacy* create_privacy(uint32_t field_id, uint8_t type, uint8_t dest) {
+ Privacy* p = new_uninit_privacy();
+ p->field_id = field_id;
+ p->type = type;
+ p->children = NULL;
+ p->dest = dest;
+ p->patterns = NULL;
+ return p;
+ }
+
+ Privacy* create_message_privacy(uint32_t field_id, Privacy** children) {
+ Privacy* p = new_uninit_privacy();
+ p->field_id = field_id;
+ p->type = MESSAGE_TYPE;
+ p->children = children;
+ p->dest = EXPLICIT;
+ p->patterns = NULL;
+ return p;
+ }
+
+ Privacy* create_string_privacy(uint32_t field_id, uint8_t dest, const char** patterns) {
+ Privacy* p = new_uninit_privacy();
+ p->field_id = field_id;
+ p->type = STRING_TYPE;
+ p->children = NULL;
+ p->dest = dest;
+ p->patterns = patterns;
+ return p;
+ }
+
FdBuffer buffer;
private:
TemporaryFile tf;
+ // Littering this code with unique_ptr (or similar) is ugly, so we just
+ // mass-free everything after the test completes.
+ std::vector<Privacy *> privacies;
+
+ Privacy *new_uninit_privacy() {
+ Privacy* p = new Privacy;
+ privacies.push_back(p);
+ return p;
+ }
};
TEST_F(EncodedBufferTest, NullFieldPolicy) {
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 9c2e63e42933..b9ee7ff201d5 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -40,8 +40,10 @@ include $(CLEAR_VARS)
LOCAL_MODULE := statsd
LOCAL_SRC_FILES := \
+ ../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
+ src/AnomalyMonitor.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
src/main.cpp \
@@ -117,8 +119,10 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
STATSD_PROTO_INCLUDES
LOCAL_SRC_FILES := \
+ ../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
src/StatsService.cpp \
+ tests/indexed_priority_queue_test.cpp \
src/LogEntryPrinter.cpp \
src/LogReader.cpp \
tests/LogReader_test.cpp \
diff --git a/cmds/statsd/src/AnomalyMonitor.cpp b/cmds/statsd/src/AnomalyMonitor.cpp
new file mode 100644
index 000000000000..2d3454a831f9
--- /dev/null
+++ b/cmds/statsd/src/AnomalyMonitor.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AnomalyMonitor"
+#define DEBUG true
+
+#include "AnomalyMonitor.h"
+
+#include <cutils/log.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
+ : mRegisteredAlarmTimeSec(0),
+ mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) {
+}
+
+AnomalyMonitor::~AnomalyMonitor() {
+}
+
+void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
+ std::lock_guard<std::mutex> lock(mLock);
+ sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
+ mStatsCompanionService = statsCompanionService;
+ if (statsCompanionService == nullptr) {
+ if (DEBUG) ALOGD("Erasing link to statsCompanionService");
+ return;
+ }
+ if (DEBUG) ALOGD("Creating link to statsCompanionService");
+ const sp<const AnomalyAlarm> top = mPq.top();
+ if (top != nullptr) {
+ updateRegisteredAlarmTime_l(top->timestampSec);
+ }
+}
+
+void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (alarm == nullptr) {
+ ALOGW("Asked to add a null alarm.");
+ return;
+ }
+ if (alarm->timestampSec < 1) {
+ // forbidden since a timestamp 0 is used to indicate no alarm registered
+ ALOGW("Asked to add a 0-time alarm.");
+ return;
+ }
+ // TODO: Ensure that refractory period is respected.
+ if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
+ mPq.push(alarm);
+ if (mRegisteredAlarmTimeSec < 1 ||
+ alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
+ updateRegisteredAlarmTime_l(alarm->timestampSec);
+ }
+}
+
+void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (alarm == nullptr) {
+ ALOGW("Asked to remove a null alarm.");
+ return;
+ }
+ if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
+ mPq.remove(alarm);
+ if (mPq.empty()) {
+ if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+ mRegisteredAlarmTimeSec = 0;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->cancelAnomalyAlarm();
+ }
+ return;
+ }
+ uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
+ if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
+ if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
+ updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
+ }
+}
+
+void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
+ if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
+ mRegisteredAlarmTimeSec = timestampSec;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
+ }
+}
+
+int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
+ return ((int64_t) timeSec) * 1000;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/AnomalyMonitor.h
new file mode 100644
index 000000000000..e89afa8a6497
--- /dev/null
+++ b/cmds/statsd/src/AnomalyMonitor.h
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#ifndef ANOMALY_MONITOR_H
+#define ANOMALY_MONITOR_H
+
+#include <indexed_priority_queue.h>
+#include <android/os/IStatsCompanionService.h>
+#include <utils/RefBase.h>
+
+#include <queue>
+#include <vector>
+
+using namespace android;
+
+using android::os::IStatsCompanionService;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Represents an alarm, associated with some aggregate metric, holding a
+ * projected time at which the metric is expected to exceed its anomaly
+ * threshold.
+ * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106.
+ */
+struct AnomalyAlarm : public RefBase {
+ AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) {
+ }
+
+ const uint32_t timestampSec;
+
+ /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */
+ struct SmallerTimestamp {
+ bool operator()(sp<const AnomalyAlarm> a, sp<const AnomalyAlarm> b) const {
+ return (a->timestampSec < b->timestampSec);
+ }
+ };
+};
+
+/**
+ * Manages alarms for Anomaly Detection.
+ */
+class AnomalyMonitor : public RefBase {
+ public:
+ /**
+ * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
+ * from the registered alarm by more than this amount, update the registered
+ * alarm.
+ */
+ AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
+ ~AnomalyMonitor();
+
+ /**
+ * Tells AnomalyMonitor what IStatsCompanionService to use and, if
+ * applicable, immediately registers an existing alarm with it.
+ * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
+ * update IStatsCompanionService (until such time as it is set non-null).
+ */
+ void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
+
+ /**
+ * Adds the given alarm (reference) to the queue.
+ */
+ void add(sp<const AnomalyAlarm> alarm);
+
+ /**
+ * Removes the given alarm (reference) from the queue.
+ * Note that alarm comparison is reference-based; if another alarm exists
+ * with the same timestampSec, that alarm will still remain in the queue.
+ */
+ void remove(sp<const AnomalyAlarm> alarm);
+
+ /**
+ * Returns the projected alarm timestamp that is registered with
+ * StatsCompanionService. This may not be equal to the soonest alarm,
+ * but should be within minDiffToUpdateRegisteredAlarmTimeSec of it.
+ */
+ uint32_t getRegisteredAlarmTimeSec() const {
+ return mRegisteredAlarmTimeSec;
+ }
+
+ private:
+ std::mutex mLock;
+
+ /**
+ * Timestamp (seconds since epoch) of the alarm registered with
+ * StatsCompanionService. This, in general, may not be equal to the soonest
+ * alarm stored in mPq, but should be within minUpdateTimeSec of it.
+ * A value of 0 indicates that no alarm is currently registered.
+ */
+ uint32_t mRegisteredAlarmTimeSec;
+
+ /**
+ * Priority queue of alarms, prioritized by soonest alarm.timestampSec.
+ */
+ indexed_priority_queue<AnomalyAlarm, AnomalyAlarm::SmallerTimestamp> mPq;
+
+ /**
+ * Binder interface for communicating with StatsCompanionService.
+ */
+ sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+
+ /**
+ * Amount by which the soonest projected alarm must differ from
+ * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called.
+ */
+ uint32_t mMinUpdateTimeSec;
+
+ /**
+ * Updates the alarm registered with StatsCompanionService to the given time.
+ * Also correspondingly updates mRegisteredAlarmTimeSec.
+ */
+ void updateRegisteredAlarmTime_l(uint32_t timestampSec);
+
+ /** Converts uint32 timestamp in seconds to a Java long in msec. */
+ int64_t secToMs(uint32_t timeSec);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // ANOMALY_MONITOR_H \ No newline at end of file
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/DropboxReader.cpp
index cda2f431e435..307e7712e5aa 100644
--- a/cmds/statsd/src/DropboxReader.cpp
+++ b/cmds/statsd/src/DropboxReader.cpp
@@ -23,11 +23,14 @@ using android::sp;
using android::String16;
using android::binder::Status;
using android::base::unique_fd;
-using android::os::statsd::EventMetricData;
using android::os::DropBoxManager;
using android::ZipUtils;
using std::vector;
+namespace android {
+namespace os {
+namespace statsd {
+
status_t DropboxReader::readStatsLogs(FILE* out, const string& tag, long msec) {
sp<DropBoxManager> dropbox = new DropBoxManager();
StatsLogReport logReport;
@@ -117,3 +120,7 @@ void DropboxReader::printLog(FILE* out, const StatsLogReport& logReport) {
}
fprintf(out, "\n");
}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/DropboxReader.h
index f7d5a8205f57..b7f8739c9ad6 100644
--- a/cmds/statsd/src/DropboxReader.h
+++ b/cmds/statsd/src/DropboxReader.h
@@ -23,10 +23,13 @@
#include <stdio.h>
using android::base::unique_fd;
-using android::os::statsd::StatsLogReport;
using android::status_t;
using std::string;
+namespace android {
+namespace os {
+namespace statsd {
+
class DropboxReader {
public:
// msec is the start timestamp.
@@ -42,4 +45,8 @@ private:
};
};
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif //DROPBOX_READER_H
diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/DropboxWriter.cpp
index 01a9eac317d8..b9d48fa362d5 100644
--- a/cmds/statsd/src/DropboxWriter.cpp
+++ b/cmds/statsd/src/DropboxWriter.cpp
@@ -18,12 +18,16 @@
#include "DropboxWriter.h"
-using android::os::DropBoxManager;
using android::binder::Status;
+using android::os::DropBoxManager;
using android::sp;
using android::String16;
using std::vector;
+namespace android {
+namespace os {
+namespace statsd {
+
DropboxWriter::DropboxWriter(const string& tag)
: mTag(tag), mLogReport(), mBufferSize(0) {
}
@@ -57,3 +61,7 @@ void DropboxWriter::flush() {
mLogReport.Clear();
mBufferSize = 0;
}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/DropboxWriter.h
index 31b3f2764bb9..59629fb65b22 100644
--- a/cmds/statsd/src/DropboxWriter.h
+++ b/cmds/statsd/src/DropboxWriter.h
@@ -20,7 +20,10 @@
#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
using std::string;
-using android::os::statsd::StatsLogReport;
+
+namespace android {
+namespace os {
+namespace statsd {
class DropboxWriter {
public:
@@ -62,4 +65,8 @@ private:
};
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif //DROPBOX_WRITER_H
diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp
index ba07308086ca..c877b0545795 100644
--- a/cmds/statsd/src/LogEntryPrinter.cpp
+++ b/cmds/statsd/src/LogEntryPrinter.cpp
@@ -22,6 +22,10 @@
using namespace android;
+namespace android {
+namespace os {
+namespace statsd {
+
LogEntryPrinter::LogEntryPrinter(int out)
:m_out(out)
{
@@ -59,3 +63,7 @@ LogEntryPrinter::OnLogEvent(const log_msg& msg)
}
}
+} // namespace statsd
+} // namespace os
+} // namespace android
+
diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/LogEntryPrinter.h
index 61ffddca0916..ed720dcd17ac 100644
--- a/cmds/statsd/src/LogEntryPrinter.h
+++ b/cmds/statsd/src/LogEntryPrinter.h
@@ -23,6 +23,10 @@
#include <stdio.h>
+namespace android {
+namespace os {
+namespace statsd {
+
/**
* Decodes the log entry and prints it to the supplied file descriptor.
*/
@@ -51,4 +55,8 @@ private:
AndroidLogFormat* m_format;
};
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif // LOG_ENTRY_PRINTER_H
diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/LogReader.cpp
index 2a9e5005499c..c9164f914cd2 100644
--- a/cmds/statsd/src/LogReader.cpp
+++ b/cmds/statsd/src/LogReader.cpp
@@ -26,6 +26,10 @@
using namespace android;
using namespace std;
+namespace android {
+namespace os {
+namespace statsd {
+
#define SNOOZE_INITIAL_MS 100
#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes
@@ -141,3 +145,6 @@ LogReader::connect_and_read()
return lineCount;
}
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/LogReader.h
index 08a17a31aa18..4c2afe8ba43f 100644
--- a/cmds/statsd/src/LogReader.h
+++ b/cmds/statsd/src/LogReader.h
@@ -18,11 +18,14 @@
#define LOGREADER_H
#include <log/log_read.h>
-
#include <utils/RefBase.h>
#include <vector>
+namespace android {
+namespace os {
+namespace statsd {
+
/**
* Callback for LogReader
*/
@@ -78,4 +81,8 @@ private:
int connect_and_read();
};
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif // LOGREADER_H
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index c2fffd8a2d84..1ae23ef8af13 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -21,8 +21,10 @@
#include <parse_util.h>
using namespace android;
-using android::os::statsd::EventMetricData;
-using android::os::statsd::StatsLogReport;
+
+namespace android {
+namespace os {
+namespace statsd {
StatsLogProcessor::StatsLogProcessor() : m_dropbox_writer("all-logs")
{
@@ -71,3 +73,7 @@ StatsLogProcessor::UpdateConfig(const int config_source, StatsdConfig config)
m_configs[config_source] = config;
ALOGD("Updated configuration for source %i", config_source);
}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 5df84245a406..a6d182cac47a 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -20,7 +20,9 @@
#include <unordered_map>
-using android::os::statsd::StatsdConfig;
+namespace android {
+namespace os {
+namespace statsd {
class StatsLogProcessor : public LogListener
{
@@ -51,4 +53,9 @@ private:
*/
std::unordered_map<int, StatsdConfig> m_configs;
};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif //STATS_LOG_PROCESSOR_H
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 24413f65fb9f..965c9b7192de 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "statsd"
+#define DEBUG true
#include "StatsService.h"
#include "DropboxReader.h"
@@ -33,10 +34,13 @@
#include <stdlib.h>
using namespace android;
-using android::os::statsd::StatsdConfig;
-// ================================================================================
+namespace android {
+namespace os {
+namespace statsd {
+
StatsService::StatsService(const sp<Looper>& handlerLooper)
+ : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Change this based on the config
{
ALOGD("stats service constructed");
}
@@ -162,6 +166,38 @@ StatsService::doLoadConfig(FILE* in)
}
Status
+StatsService::informAnomalyAlarmFired()
+{
+ if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call informAnomalyAlarmFired");
+ }
+
+ if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired succeeded");
+ // TODO: check through all counters/timers and see if an anomaly has indeed occurred.
+
+ return Status::ok();
+}
+
+Status
+StatsService::informPollAlarmFired()
+{
+ if (DEBUG) ALOGD("StatsService::informPollAlarmFired was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call informPollAlarmFired");
+ }
+
+ if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
+ // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
+
+ return Status::ok();
+}
+
+Status
StatsService::systemRunning()
{
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
@@ -172,9 +208,68 @@ StatsService::systemRunning()
// When system_server is up and running, schedule the dropbox task to run.
ALOGD("StatsService::systemRunning");
+ sayHiToStatsCompanion();
+
+ return Status::ok();
+}
+
+void
+StatsService::sayHiToStatsCompanion()
+{
+ // TODO: This method needs to be private. It is temporarily public and unsecured for testing purposes.
+ sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
+ if (statsCompanion != nullptr) {
+ if (DEBUG) ALOGD("Telling statsCompanion that statsd is ready");
+ statsCompanion->statsdReady();
+ } else {
+ if (DEBUG) ALOGD("Could not access statsCompanion");
+ }
+}
+
+sp<IStatsCompanionService>
+StatsService::getStatsCompanionService() {
+ sp<IStatsCompanionService> statsCompanion = nullptr;
+ // Get statscompanion service from service manager
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ const String16 name("statscompanion");
+ statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
+ if (statsCompanion == nullptr) {
+ ALOGW("statscompanion service unavailable!");
+ return nullptr;
+ }
+ }
+ return statsCompanion;
+}
+
+Status
+StatsService::statsCompanionReady()
+{
+ if (DEBUG) ALOGD("StatsService::statsCompanionReady was called");
+
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call statsCompanionReady");
+ }
+
+ sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
+ if (statsCompanion == nullptr) {
+ return Status::fromExceptionCode(Status::EX_NULL_POINTER,
+ "statscompanion unavailable despite it contacting statsd!");
+ }
+ if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
+ IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor));
+ mAnomalyMonitor->setStatsCompanionService(statsCompanion);
+
return Status::ok();
}
+void
+StatsdDeathRecipient::binderDied(const wp<IBinder>& who) {
+ ALOGW("statscompanion service died");
+ mAnmlyMntr->setStatsCompanionService(nullptr);
+}
+
status_t
StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) {
long msec = 0;
@@ -191,3 +286,7 @@ StatsService::printCmdHelp(FILE* out) {
fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
fprintf(out, "\t config\t Loads a new config from command-line (must be proto in wire-encoded format).\n");
}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index ef52b5628c29..57276d2425e9 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -17,9 +17,11 @@
#ifndef STATS_SERVICE_H
#define STATS_SERVICE_H
+#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"
#include <android/os/BnStatsManager.h>
+#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
@@ -33,9 +35,11 @@ using namespace android::base;
using namespace android::binder;
using namespace android::os;
using namespace std;
-using android::os::statsd::StatsdConfig;
-// ================================================================================
+namespace android {
+namespace os {
+namespace statsd {
+
class StatsService : public BnStatsManager {
public:
StatsService(const sp<Looper>& handlerLooper);
@@ -49,13 +53,49 @@ public:
virtual Status systemRunning();
+ // Inform statsd that statsCompanion is ready.
+ virtual Status statsCompanionReady();
+
+ virtual Status informAnomalyAlarmFired();
+
+ virtual Status informPollAlarmFired();
+
virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
+ // TODO: public for testing since statsd doesn't run when system starts. Change to private later.
+ /** Inform statsCompanion that statsd is ready. */
+ virtual void sayHiToStatsCompanion();
+
private:
sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
+
+ const sp<AnomalyMonitor> mAnomalyMonitor; // TODO: Move this to a more logical file/class
+
status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
+
void printCmdHelp(FILE* out);
+
status_t doLoadConfig(FILE* in);
+
+ /** Fetches the StatsCompanionService. */
+ sp<IStatsCompanionService> getStatsCompanionService();
+};
+
+// --- StatsdDeathRecipient ---
+class StatsdDeathRecipient : public IBinder::DeathRecipient {
+public:
+ StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor)
+ : mAnmlyMntr(anomalyMonitor) {
+ }
+
+ virtual void binderDied(const wp<IBinder>& who);
+
+private:
+ const sp<AnomalyMonitor> mAnmlyMntr;
};
+} // namespace statsd
+} // namespace os
+} // namespace android
+
#endif // STATS_SERVICE_H
diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/indexed_priority_queue.h
new file mode 100644
index 000000000000..76409c07523a
--- /dev/null
+++ b/cmds/statsd/src/indexed_priority_queue.h
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+#ifndef STATSD_INDEXED_PRIORITY_QUEUE_H
+#define STATSD_INDEXED_PRIORITY_QUEUE_H
+
+// ALOGE can be called from this file. If header loaded by another class, use their LOG_TAG instead.
+#ifndef LOG_TAG
+#define LOG_TAG "statsd(indexed_priority_queue)"
+#endif //LOG_TAG
+
+#include <cutils/log.h>
+#include <unordered_map>
+#include <utils/RefBase.h>
+#include <vector>
+
+using namespace android;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/** Defines a hash function for sp<AA>, returning the hash of the underlying pointer. */
+template <class AA>
+struct SpHash {
+ size_t operator()(const sp<const AA>& k) const {
+ return std::hash<const AA*>()(k.get());
+ }
+};
+
+/**
+ * Min priority queue for generic type AA.
+ * Unlike a regular priority queue, this class is also capable of removing interior elements.
+ * @tparam Comparator must implement [bool operator()(sp<const AA> a, sp<const AA> b)], returning
+ * whether a should be closer to the top of the queue than b.
+ */
+template <class AA, class Comparator>
+class indexed_priority_queue {
+ public:
+ indexed_priority_queue();
+ /** Adds a into the priority queue. If already present or a==nullptr, does nothing. */
+ void push(sp<const AA> a);
+ /** Removes a from the priority queue. If not present or a==nullptr, does nothing. */
+ void remove(sp<const AA> a);
+ /** Removes all elements. */
+ void clear();
+ /** Returns whether priority queue contains a (not just a copy of a, but a itself). */
+ bool contains(sp<const AA> a) const;
+ /** Returns min element. Returns nullptr iff empty(). */
+ sp<const AA> top() const;
+ /** Returns number of elements in priority queue. */
+ size_t size() const { return pq.size() - 1; } // pq is 1-indexed
+ /** Returns true iff priority queue is empty. */
+ bool empty() const { return size() < 1; }
+
+ private:
+ /** Vector representing a min-heap (1-indexed, with nullptr at 0). */
+ std::vector<sp<const AA>> pq;
+ /** Mapping of each element in pq to its index in pq (i.e. the inverse of a=pq[i]). */
+ std::unordered_map<sp<const AA>, size_t, SpHash<AA>> indices;
+
+ void init();
+ void sift_up(size_t idx);
+ void sift_down(size_t idx);
+ /** Returns whether pq[idx1] is considered higher than pq[idx2], according to Comparator. */
+ bool higher(size_t idx1, size_t idx2) const;
+ void swap_indices(size_t i, size_t j);
+};
+
+// Implementation must be done in this file due to use of template.
+
+template <class AA, class Comparator>
+indexed_priority_queue<AA,Comparator>::indexed_priority_queue() {
+ init();
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::push(sp<const AA> a) {
+ if (a == nullptr) return;
+ if (contains(a)) return;
+ pq.push_back(a);
+ size_t idx = size(); // index of last element since 1-indexed
+ indices.insert({a, idx});
+ sift_up(idx); // get the pq back in order
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::remove(sp<const AA> a) {
+ if (a == nullptr) return;
+ if (!contains(a)) return;
+ size_t idx = indices[a];
+ if (idx >= pq.size()) {
+ ALOGE("indexed_priority_queue: Invalid index in map of indices.");
+ return;
+ }
+ if (idx == size()) { // if a is the last element, i.e. at index idx == size() == (pq.size()-1)
+ pq.pop_back();
+ indices.erase(a);
+ return;
+ }
+ // move last element (guaranteed not to be at idx) to idx, then delete a
+ sp<const AA> last_a = pq.back();
+ pq[idx] = last_a;
+ pq.pop_back();
+ indices[last_a] = idx;
+ indices.erase(a);
+
+ // get the heap back in order (since the element at idx is not in order)
+ sift_up(idx);
+ sift_down(idx);
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::clear() {
+ pq.clear();
+ indices.clear();
+ init();
+}
+
+template <class AA, class Comparator>
+sp<const AA> indexed_priority_queue<AA,Comparator>::top() const {
+ if (empty()) return nullptr;
+ return pq[1];
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::init() {
+ pq.push_back(nullptr); // so that pq is 1-indexed.
+ indices.insert({nullptr, 0}); // just to be consistent with pq.
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::sift_up(size_t idx) {
+ while (idx > 1) {
+ size_t parent = idx/2;
+ if (higher(idx, parent)) swap_indices(idx, parent);
+ else break;
+ idx = parent;
+ }
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::sift_down(size_t idx) {
+ while (2*idx <= size()) {
+ size_t child = 2 * idx;
+ if (child < size() && higher(child+1, child)) child++;
+ if (higher(child, idx)) swap_indices(child, idx);
+ else break;
+ idx = child;
+ }
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA,Comparator>::higher(size_t idx1, size_t idx2) const {
+ if (!(0u < idx1 && idx1 < pq.size() && 0u < idx2 && idx2 < pq.size())) {
+ ALOGE("indexed_priority_queue: Attempting to access invalid index");
+ return false; // got to do something.
+ }
+ return Comparator()(pq[idx1], pq[idx2]);
+}
+
+template <class AA, class Comparator>
+bool indexed_priority_queue<AA,Comparator>::contains(sp<const AA> a) const {
+ if (a == nullptr) return false; // publicly, we pretend that nullptr is not actually in pq.
+ return indices.count(a) > 0;
+}
+
+template <class AA, class Comparator>
+void indexed_priority_queue<AA,Comparator>::swap_indices(size_t i, size_t j) {
+ if (!(0u < i && i < pq.size() && 0u < j && j < pq.size())) {
+ ALOGE("indexed_priority_queue: Attempting to swap invalid index");
+ return;
+ }
+ sp<const AA> val_i = pq[i];
+ sp<const AA> val_j = pq[j];
+ pq[i] = val_j;
+ pq[j] = val_i;
+ indices[val_i] = j;
+ indices[val_j] = i;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif //STATSD_INDEXED_PRIORITY_QUEUE_H
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index f9265c642dfb..c1dad4f1ed3f 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -36,6 +36,7 @@
#include <unistd.h>
using namespace android;
+using namespace android::os::statsd;
// ================================================================================
/**
@@ -129,6 +130,10 @@ main(int /*argc*/, char** /*argv*/)
return -1;
}
+ // TODO: This line is temporary, since statsd doesn't start up automatically (and therefore
+ // the call in StatsService::SystemRunning() won't ever be called right now).
+ service->sayHiToStatsCompanion();
+
// Start the log reader thread
err = start_log_reader_thread(service);
if (err != NO_ERROR) {
diff --git a/cmds/statsd/src/parse_util.cpp b/cmds/statsd/src/parse_util.cpp
index 9caeacf3b538..ffce88424d93 100644
--- a/cmds/statsd/src/parse_util.cpp
+++ b/cmds/statsd/src/parse_util.cpp
@@ -17,6 +17,7 @@
#include <parse_util.h>
#include <log/log_event_list.h>
+using android::os::statsd::EVENT_TIMESTAMP;
using android::os::statsd::EventMetricData;
using android::os::statsd::KeyId;
using android::os::statsd::KeyId_IsValid;
@@ -29,6 +30,13 @@ EventMetricData parse(log_msg msg)
// dump all statsd logs to dropbox for now.
// TODO: Add filtering, aggregation, etc.
EventMetricData eventMetricData;
+
+ // set timestamp of the event.
+ KeyValuePair *keyValuePair = eventMetricData.add_key_value_pair();
+ keyValuePair->set_key(EVENT_TIMESTAMP);
+ keyValuePair->set_value_int(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec);
+
+ // start iterating k,v pairs.
android_log_context context = create_android_log_parser(const_cast<log_msg*>(&msg)->msg()
+ sizeof(uint32_t),
const_cast<log_msg*>(&msg)->len()
diff --git a/cmds/statsd/src/stats_constants.proto b/cmds/statsd/src/stats_constants.proto
index 3f8bd1c5a9fc..9758a2e0cb89 100644
--- a/cmds/statsd/src/stats_constants.proto
+++ b/cmds/statsd/src/stats_constants.proto
@@ -24,7 +24,8 @@ option java_outer_classname = "StatsConstantsProto";
enum TagId {
WAKELOCK = 1;
- SCREEN = 1003;
+ SCREEN = 2;
+ PROCESS = 1112; // TODO: Temporary usage only for testing.
}
enum KeyId {
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
new file mode 100644
index 000000000000..1aad08918ad9
--- /dev/null
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../src/indexed_priority_queue.h"
+
+#include <gtest/gtest.h>
+
+using namespace android::os::statsd;
+
+/** struct for template in indexed_priority_queue */
+struct AATest : public RefBase {
+ AATest(uint32_t val) : val(val) {
+ }
+
+ const int val;
+
+ struct Smaller {
+ bool operator()(const sp<const AATest> a, const sp<const AATest> b) const {
+ return (a->val < b->val);
+ }
+ };
+};
+
+#ifdef __ANDROID__
+TEST(indexed_priority_queue, empty_and_size) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+ sp<const AATest> aa4 = new AATest{4};
+ sp<const AATest> aa8 = new AATest{8};
+
+ EXPECT_EQ(0u, ipq.size());
+ EXPECT_TRUE(ipq.empty());
+
+ ipq.push(aa4);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_FALSE(ipq.empty());
+
+ ipq.push(aa8);
+ EXPECT_EQ(2u, ipq.size());
+ EXPECT_FALSE(ipq.empty());
+
+ ipq.remove(aa4);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_FALSE(ipq.empty());
+
+ ipq.remove(aa8);
+ EXPECT_EQ(0u, ipq.size());
+ EXPECT_TRUE(ipq.empty());
+}
+
+TEST(indexed_priority_queue, top) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+ sp<const AATest> aa2 = new AATest{2};
+ sp<const AATest> aa4 = new AATest{4};
+ sp<const AATest> aa8 = new AATest{8};
+ sp<const AATest> aa12 = new AATest{12};
+ sp<const AATest> aa16 = new AATest{16};
+ sp<const AATest> aa20 = new AATest{20};
+
+ EXPECT_EQ(ipq.top(), nullptr);
+
+ // add 8, 4, 12
+ ipq.push(aa8);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.push(aa12);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.push(aa4);
+ EXPECT_EQ(ipq.top(), aa4);
+
+ // remove 12, 4
+ ipq.remove(aa12);
+ EXPECT_EQ(ipq.top(), aa4);
+
+ ipq.remove(aa4);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ // add 16, 2, 20
+ ipq.push(aa16);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.push(aa2);
+ EXPECT_EQ(ipq.top(), aa2);
+
+ ipq.push(aa20);
+ EXPECT_EQ(ipq.top(), aa2);
+
+ // remove 2, 20, 16, 8
+ ipq.remove(aa2);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.remove(aa20);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.remove(aa16);
+ EXPECT_EQ(ipq.top(), aa8);
+
+ ipq.remove(aa8);
+ EXPECT_EQ(ipq.top(), nullptr);
+}
+
+TEST(indexed_priority_queue, push_same_aa) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+ sp<const AATest> aa4_a = new AATest{4};
+ sp<const AATest> aa4_b = new AATest{4};
+
+ ipq.push(aa4_a);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4_a));
+ EXPECT_FALSE(ipq.contains(aa4_b));
+
+ ipq.push(aa4_a);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4_a));
+ EXPECT_FALSE(ipq.contains(aa4_b));
+
+ ipq.push(aa4_b);
+ EXPECT_EQ(2u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4_a));
+ EXPECT_TRUE(ipq.contains(aa4_b));
+}
+
+
+TEST(indexed_priority_queue, remove_nonexistant) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+ sp<const AATest> aa4 = new AATest{4};
+ sp<const AATest> aa5 = new AATest{5};
+
+ ipq.push(aa4);
+ ipq.remove(aa5);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4));
+ EXPECT_FALSE(ipq.contains(aa5));
+}
+
+TEST(indexed_priority_queue, remove_same_aa) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+ sp<const AATest> aa4_a = new AATest{4};
+ sp<const AATest> aa4_b = new AATest{4};
+
+ ipq.push(aa4_a);
+ ipq.push(aa4_b);
+ EXPECT_EQ(2u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4_a));
+ EXPECT_TRUE(ipq.contains(aa4_b));
+
+ ipq.remove(aa4_b);
+ EXPECT_EQ(1u, ipq.size());
+ EXPECT_TRUE(ipq.contains(aa4_a));
+ EXPECT_FALSE(ipq.contains(aa4_b));
+
+ ipq.remove(aa4_a);
+ EXPECT_EQ(0u, ipq.size());
+ EXPECT_FALSE(ipq.contains(aa4_a));
+ EXPECT_FALSE(ipq.contains(aa4_b));
+}
+
+TEST(indexed_priority_queue, nulls) {
+ indexed_priority_queue<AATest, AATest::Smaller> ipq;
+
+ EXPECT_TRUE(ipq.empty());
+ EXPECT_FALSE(ipq.contains(nullptr));
+
+ ipq.push(nullptr);
+ EXPECT_TRUE(ipq.empty());
+ EXPECT_FALSE(ipq.contains(nullptr));
+
+ ipq.remove(nullptr);
+ EXPECT_TRUE(ipq.empty());
+ EXPECT_FALSE(ipq.contains(nullptr));
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index c8297286b784..df68f14efec9 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3824,7 +3824,6 @@ android.system.PacketSocketAddress
android.system.StructAddrinfo
android.system.StructFlock
android.system.StructGroupReq
-android.system.StructGroupSourceReq
android.system.StructIcmpHdr
android.system.StructIfaddrs
android.system.StructLinger
@@ -5243,7 +5242,6 @@ com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
com.android.internal.app.NightDisplayController$Callback
-com.android.internal.app.NightDisplayController$LocalTime
com.android.internal.app.ProcessMap
com.android.internal.app.ResolverActivity
com.android.internal.app.ToolbarActionBar
diff --git a/config/preloaded-classes b/config/preloaded-classes
index cb3cbe196230..337d7a0ad8bb 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2006,7 +2006,6 @@ android.system.PacketSocketAddress
android.system.StructAddrinfo
android.system.StructFlock
android.system.StructGroupReq
-android.system.StructGroupSourceReq
android.system.StructIfaddrs
android.system.StructLinger
android.system.StructPasswd
@@ -2786,7 +2785,6 @@ com.android.internal.app.IVoiceInteractionManagerService$Stub
com.android.internal.app.IVoiceInteractor
com.android.internal.app.IVoiceInteractor$Stub
com.android.internal.app.NightDisplayController
-com.android.internal.app.NightDisplayController$1
com.android.internal.appwidget.IAppWidgetService
com.android.internal.appwidget.IAppWidgetService$Stub
com.android.internal.appwidget.IAppWidgetService$Stub$Proxy
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a8665037f8d3..78d05f5123c8 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -770,21 +770,6 @@ public class ActivityManager {
}
/**
- * Returns true if animation specs should be constructed for app transition that moves
- * the task to the specified stack.
- * @hide
- */
- public static boolean useAnimationSpecForAppTransition(int stackId) {
- // TODO: INVALID_STACK_ID is also animated because we don't persist stack id's across
- // reboots.
- return stackId == FREEFORM_WORKSPACE_STACK_ID
- || stackId == FULLSCREEN_WORKSPACE_STACK_ID
- || stackId == ASSISTANT_STACK_ID
- || stackId == DOCKED_STACK_ID
- || stackId == INVALID_STACK_ID;
- }
-
- /**
* Returns true if activities from stasks in the given {@param stackId} are allowed to
* enter picture-in-picture.
* @hide
@@ -885,6 +870,18 @@ public class ActivityManager {
return windowingMode;
}
+ /** Returns the stack id for the input windowing mode.
+ * @hide */
+ // TODO: To be removed once we are not using stack id for stuff...
+ public static int getStackIdForWindowingMode(int windowingMode) {
+ switch (windowingMode) {
+ case WINDOWING_MODE_PINNED: return PINNED_STACK_ID;
+ case WINDOWING_MODE_FREEFORM: return FREEFORM_WORKSPACE_STACK_ID;
+ case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return DOCKED_STACK_ID;
+ default: return INVALID_STACK_ID;
+ }
+ }
+
/** Returns the activity type that should be used for this input stack id.
* @hide */
// TODO: To be removed once we are not using stack id for stuff...
@@ -905,6 +902,18 @@ public class ActivityManager {
}
return activityType;
}
+
+ /** Returns the stack id for the input activity type.
+ * @hide */
+ // TODO: To be removed once we are not using stack id for stuff...
+ public static int getStackIdForActivityType(int activityType) {
+ switch (activityType) {
+ case ACTIVITY_TYPE_HOME: return HOME_STACK_ID;
+ case ACTIVITY_TYPE_RECENTS: return RECENTS_STACK_ID;
+ case ACTIVITY_TYPE_ASSISTANT: return ASSISTANT_STACK_ID;
+ default: return INVALID_STACK_ID;
+ }
+ }
}
/**
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 0bffc9e6cee5..a68c3a5c29a6 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -18,6 +18,8 @@ package android.app;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
import android.annotation.Nullable;
@@ -164,10 +166,16 @@ public class ActivityOptions {
private static final String KEY_LAUNCH_DISPLAY_ID = "android.activity.launchDisplayId";
/**
- * The stack id the activity should be launched into.
+ * The windowing mode the activity should be launched into.
* @hide
*/
- private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+ private static final String KEY_LAUNCH_WINDOWING_MODE = "android.activity.windowingMode";
+
+ /**
+ * The activity type the activity should be launched as.
+ * @hide
+ */
+ private static final String KEY_LAUNCH_ACTIVITY_TYPE = "android.activity.activityType";
/**
* The task id the activity should be launched into.
@@ -272,7 +280,10 @@ public class ActivityOptions {
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
private int mLaunchDisplayId = INVALID_DISPLAY;
- private int mLaunchStackId = INVALID_STACK_ID;
+ @WindowConfiguration.WindowingMode
+ private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED;
+ @WindowConfiguration.ActivityType
+ private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED;
private int mLaunchTaskId = -1;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
@@ -860,7 +871,8 @@ public class ActivityOptions {
break;
}
mLaunchDisplayId = opts.getInt(KEY_LAUNCH_DISPLAY_ID, INVALID_DISPLAY);
- mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
+ mLaunchWindowingMode = opts.getInt(KEY_LAUNCH_WINDOWING_MODE, WINDOWING_MODE_UNDEFINED);
+ mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
@@ -1070,14 +1082,34 @@ public class ActivityOptions {
}
/** @hide */
- public int getLaunchStackId() {
- return mLaunchStackId;
+ public int getLaunchWindowingMode() {
+ return mLaunchWindowingMode;
+ }
+
+ /**
+ * Sets the windowing mode the activity should launch into. If the input windowing mode is
+ * {@link android.app.WindowConfiguration#WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} and the device
+ * isn't currently in split-screen windowing mode, then the activity will be launched in
+ * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN} windowing mode. For clarity
+ * on this you can use
+ * {@link android.app.WindowConfiguration#WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY}
+ *
+ * @hide
+ */
+ @TestApi
+ public void setLaunchWindowingMode(int windowingMode) {
+ mLaunchWindowingMode = windowingMode;
+ }
+
+ /** @hide */
+ public int getLaunchActivityType() {
+ return mLaunchActivityType;
}
/** @hide */
@TestApi
- public void setLaunchStackId(int launchStackId) {
- mLaunchStackId = launchStackId;
+ public void setLaunchActivityType(int activityType) {
+ mLaunchActivityType = activityType;
}
/**
@@ -1291,7 +1323,8 @@ public class ActivityOptions {
break;
}
b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId);
- b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
+ b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode);
+ b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType);
b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index c567946a830d..eccb264796f8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -553,11 +553,6 @@ interface IActivityManager {
*/
void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds);
boolean isVrModePackageEnabled(in ComponentName packageName);
- /**
- * Moves all tasks from the docked stack in the fullscreen stack and puts the top task of the
- * fullscreen stack into the docked stack.
- */
- void swapDockedAndFullscreenStack();
void notifyLockedProfile(int userId);
void startConfirmDeviceCredentialIntent(in Intent intent, in Bundle options);
void sendIdleJobTrigger();
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index b5b101773f15..a56965bdbd4d 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -30,7 +30,7 @@ oneway interface ITaskStackListener {
void onTaskStackChanged();
/** Called whenever an Activity is moved to the pinned stack from another stack. */
- void onActivityPinned(String packageName, int taskId);
+ void onActivityPinned(String packageName, int userId, int taskId);
/** Called whenever an Activity is moved from the pinned stack to another stack. */
void onActivityUnpinned();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ee6c1cbaecfe..60f4ed01805c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -67,7 +67,6 @@ import android.text.style.TextAppearanceSpan;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TypedValue;
import android.view.Gravity;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -3906,7 +3905,6 @@ public class Notification implements Parcelable
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title, processTextSpans(p.title));
- updateTextSizePrimary(contentView, R.id.title);
if (!p.ambient) {
setTextViewColorPrimary(contentView, R.id.title);
}
@@ -3918,7 +3916,6 @@ public class Notification implements Parcelable
int textId = showProgress ? com.android.internal.R.id.text_line_1
: com.android.internal.R.id.text;
contentView.setTextViewText(textId, processTextSpans(p.text));
- updateTextSizeSecondary(contentView, textId);
if (!p.ambient) {
setTextViewColorSecondary(contentView, textId);
}
@@ -3930,25 +3927,6 @@ public class Notification implements Parcelable
return contentView;
}
- private void updateTextSizeSecondary(RemoteViews contentView, int textId) {
- updateTextSizeColorized(contentView, textId,
- com.android.internal.R.dimen.notification_text_size_colorized,
- com.android.internal.R.dimen.notification_text_size);
- }
-
- private void updateTextSizePrimary(RemoteViews contentView, int textId) {
- updateTextSizeColorized(contentView, textId,
- com.android.internal.R.dimen.notification_title_text_size_colorized,
- com.android.internal.R.dimen.notification_title_text_size);
- }
-
- private void updateTextSizeColorized(RemoteViews contentView, int textId,
- int colorizedDimen, int normalDimen) {
- int size = mContext.getResources().getDimensionPixelSize(isColorized()
- ? colorizedDimen : normalDimen);
- contentView.setTextViewTextSize(textId, TypedValue.COMPLEX_UNIT_PX, size);
- }
-
private CharSequence processTextSpans(CharSequence text) {
if (hasForegroundColor()) {
return NotificationColorUtil.clearColorSpans(text);
@@ -5874,7 +5852,6 @@ public class Notification implements Parcelable
builder.setTextViewColorSecondary(contentView, R.id.big_text);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
- builder.updateTextSizeSecondary(contentView, R.id.big_text);
contentView.setBoolean(R.id.big_text, "setHasImage", builder.mN.hasLargeIcon());
}
}
@@ -6208,7 +6185,6 @@ public class Notification implements Parcelable
contentView.setViewVisibility(rowId, View.VISIBLE);
contentView.setTextViewText(rowId, mBuilder.processTextSpans(
makeMessageLine(m, mBuilder)));
- mBuilder.updateTextSizeSecondary(contentView, rowId);
mBuilder.setTextViewColorSecondary(contentView, rowId);
if (contractedMessage == m) {
@@ -6576,7 +6552,6 @@ public class Notification implements Parcelable
contentView.setViewVisibility(rowIds[i], View.VISIBLE);
contentView.setTextViewText(rowIds[i],
mBuilder.processTextSpans(mBuilder.processLegacyText(str)));
- mBuilder.updateTextSizeSecondary(contentView, rowIds[i]);
mBuilder.setTextViewColorSecondary(contentView, rowIds[i]);
contentView.setViewPadding(rowIds[i], 0, topPadding, 0, 0);
handleInboxImageMargin(contentView, rowIds[i], first);
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index a52ca0a64cd2..4674c9cd2389 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -31,7 +31,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
}
@Override
- public void onActivityPinned(String packageName, int taskId) throws RemoteException {
+ public void onActivityPinned(String packageName, int userId, int taskId)
+ throws RemoteException {
}
@Override
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 07eb5de15d9f..0cb38046826f 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -63,8 +63,21 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/**
* The containers adjacent to the {@link #WINDOWING_MODE_SPLIT_SCREEN_PRIMARY} container in
* split-screen mode.
+ * NOTE: Containers launched with the windowing mode with APIs like
+ * {@link ActivityOptions#setLaunchWindowingMode(int)} will be launched in
+ * {@link #WINDOWING_MODE_FULLSCREEN} if the display isn't currently in split-screen windowing
+ * mode
+ * @see #WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
*/
public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4;
+ /**
+ * Alias for {@link #WINDOWING_MODE_SPLIT_SCREEN_SECONDARY} that makes it clear that the usage
+ * points for APIs like {@link ActivityOptions#setLaunchWindowingMode(int)} that the container
+ * will launch into fullscreen or split-screen secondary depending on if the device is currently
+ * in fullscreen mode or split-screen mode.
+ */
+ public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY =
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
/** Can be freely resized within its parent container. */
public static final int WINDOWING_MODE_FREEFORM = 5;
@@ -75,6 +88,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
WINDOWING_MODE_PINNED,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY,
WINDOWING_MODE_FREEFORM,
})
public @interface WindowingMode {}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 8a1eae2da976..dc9970a7ca42 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -23,17 +23,12 @@ import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
-import android.os.Parcel;
import android.os.Parcelable;
-import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
@@ -58,17 +53,17 @@ import java.util.concurrent.Executor;
* {@link RemoteViews}.
*/
public class AppWidgetHostView extends FrameLayout {
+
static final String TAG = "AppWidgetHostView";
+ private static final String KEY_JAILED_ARRAY = "jail";
+
static final boolean LOGD = false;
- static final boolean CROSSFADE = false;
static final int VIEW_MODE_NOINIT = 0;
static final int VIEW_MODE_CONTENT = 1;
static final int VIEW_MODE_ERROR = 2;
static final int VIEW_MODE_DEFAULT = 3;
- static final int FADE_DURATION = 1000;
-
// When we're inflating the initialLayout for a AppWidget, we only allow
// views that are allowed in RemoteViews.
static final LayoutInflater.Filter sInflaterFilter = new LayoutInflater.Filter() {
@@ -85,9 +80,6 @@ public class AppWidgetHostView extends FrameLayout {
View mView;
int mViewMode = VIEW_MODE_NOINIT;
int mLayoutId = -1;
- long mFadeStartTime = -1;
- Bitmap mOld;
- Paint mOldPaint = new Paint();
private OnClickHandler mOnClickHandler;
private Executor mAsyncExecutor;
@@ -212,9 +204,12 @@ public class AppWidgetHostView extends FrameLayout {
@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
- final ParcelableSparseArray jail = new ParcelableSparseArray();
+ final SparseArray<Parcelable> jail = new SparseArray<>();
super.dispatchSaveInstanceState(jail);
- container.put(generateId(), jail);
+
+ Bundle bundle = new Bundle();
+ bundle.putSparseParcelableArray(KEY_JAILED_ARRAY, jail);
+ container.put(generateId(), bundle);
}
private int generateId() {
@@ -226,12 +221,12 @@ public class AppWidgetHostView extends FrameLayout {
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
final Parcelable parcelable = container.get(generateId());
- ParcelableSparseArray jail = null;
- if (parcelable != null && parcelable instanceof ParcelableSparseArray) {
- jail = (ParcelableSparseArray) parcelable;
+ SparseArray<Parcelable> jail = null;
+ if (parcelable instanceof Bundle) {
+ jail = ((Bundle) parcelable).getSparseParcelableArray(KEY_JAILED_ARRAY);
}
- if (jail == null) jail = new ParcelableSparseArray();
+ if (jail == null) jail = new SparseArray<>();
try {
super.dispatchRestoreInstanceState(jail);
@@ -383,31 +378,10 @@ public class AppWidgetHostView extends FrameLayout {
* @hide
*/
protected void applyRemoteViews(RemoteViews remoteViews, boolean useAsyncIfPossible) {
- if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
-
boolean recycled = false;
View content = null;
Exception exception = null;
- // Capture the old view into a bitmap so we can do the crossfade.
- if (CROSSFADE) {
- if (mFadeStartTime < 0) {
- if (mView != null) {
- final int width = mView.getWidth();
- final int height = mView.getHeight();
- try {
- mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- } catch (OutOfMemoryError e) {
- // we just won't do the fade
- mOld = null;
- }
- if (mOld != null) {
- //mView.drawIntoBitmap(mOld);
- }
- }
- }
- }
-
if (mLastExecutionSignal != null) {
mLastExecutionSignal.cancel();
mLastExecutionSignal = null;
@@ -484,16 +458,6 @@ public class AppWidgetHostView extends FrameLayout {
removeView(mView);
mView = content;
}
-
- if (CROSSFADE) {
- if (mFadeStartTime < 0) {
- // if there is already an animation in progress, don't do anything --
- // the new view will pop in on top of the old one during the cross fade,
- // and that looks okay.
- mFadeStartTime = SystemClock.uptimeMillis();
- invalidate();
- }
- }
}
private void updateContentDescription(AppWidgetProviderInfo info) {
@@ -617,45 +581,6 @@ public class AppWidgetHostView extends FrameLayout {
}
}
- @Override
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- if (CROSSFADE) {
- int alpha;
- int l = child.getLeft();
- int t = child.getTop();
- if (mFadeStartTime > 0) {
- alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION);
- if (alpha > 255) {
- alpha = 255;
- }
- Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t
- + " w=" + child.getWidth());
- if (alpha != 255 && mOld != null) {
- mOldPaint.setAlpha(255-alpha);
- //canvas.drawBitmap(mOld, l, t, mOldPaint);
- }
- } else {
- alpha = 255;
- }
- int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- boolean rv = super.drawChild(canvas, child, drawingTime);
- canvas.restoreToCount(restoreTo);
- if (alpha < 255) {
- invalidate();
- } else {
- mFadeStartTime = -1;
- if (mOld != null) {
- mOld.recycle();
- mOld = null;
- }
- }
- return rv;
- } else {
- return super.drawChild(canvas, child, drawingTime);
- }
- }
-
/**
* Prepare the given view to be shown. This might include adjusting
* {@link FrameLayout.LayoutParams} before inserting.
@@ -740,36 +665,4 @@ public class AppWidgetHostView extends FrameLayout {
super.onInitializeAccessibilityNodeInfoInternal(info);
info.setClassName(AppWidgetHostView.class.getName());
}
-
- private static class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- final int count = size();
- dest.writeInt(count);
- for (int i = 0; i < count; i++) {
- dest.writeInt(keyAt(i));
- dest.writeParcelable(valueAt(i), 0);
- }
- }
-
- public static final Parcelable.Creator<ParcelableSparseArray> CREATOR =
- new Parcelable.Creator<ParcelableSparseArray>() {
- public ParcelableSparseArray createFromParcel(Parcel source) {
- final ParcelableSparseArray array = new ParcelableSparseArray();
- final ClassLoader loader = array.getClass().getClassLoader();
- final int count = source.readInt();
- for (int i = 0; i < count; i++) {
- array.put(source.readInt(), source.readParcelable(loader));
- }
- return array;
- }
-
- public ParcelableSparseArray[] newArray(int size) {
- return new ParcelableSparseArray[size];
- }
- };
- }
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2d8249acb5bf..03e4dfe829de 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2991,6 +2991,7 @@ public abstract class Context {
//@hide: CONTEXTHUB_SERVICE,
SYSTEM_HEALTH_SERVICE,
//@hide: INCIDENT_SERVICE,
+ //@hide: STATS_COMPANION_SERVICE,
COMPANION_DEVICE_SERVICE
})
@Retention(RetentionPolicy.SOURCE)
@@ -4020,6 +4021,12 @@ public abstract class Context {
public static final String INCIDENT_SERVICE = "incident";
/**
+ * Service to assist statsd in obtaining general stats.
+ * @hide
+ */
+ public static final String STATS_COMPANION_SERVICE = "statscompanion";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.content.om.OverlayManager} for managing overlay packages.
*
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 486ff43a6467..cd8201f8fb89 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -17,6 +17,7 @@
package android.content.pm;
import android.annotation.IntDef;
+import android.annotation.TestApi;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Configuration.NativeConfig;
@@ -180,6 +181,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* Activity explicitly requested to be resizeable.
* @hide
*/
+ @TestApi
public static final int RESIZE_MODE_RESIZEABLE = 2;
/**
* Activity is resizeable and supported picture-in-picture mode. This flag is now deprecated
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index f894f0536b52..c28583ea867a 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -104,7 +104,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private PreparedStatement mPreparedStatementPool;
// The recent operations log.
- private final OperationLog mRecentOperations = new OperationLog();
+ private final OperationLog mRecentOperations;
// The native SQLiteConnection pointer. (FOR INTERNAL USE ONLY)
private long mConnectionPtr;
@@ -162,6 +162,7 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
SQLiteDatabaseConfiguration configuration,
int connectionId, boolean primaryConnection) {
mPool = pool;
+ mRecentOperations = new OperationLog(mPool);
mConfiguration = new SQLiteDatabaseConfiguration(configuration);
mConnectionId = connectionId;
mIsPrimaryConnection = primaryConnection;
@@ -1298,6 +1299,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
private final Operation[] mOperations = new Operation[MAX_RECENT_OPERATIONS];
private int mIndex;
private int mGeneration;
+ private final SQLiteConnectionPool mPool;
+
+ OperationLog(SQLiteConnectionPool pool) {
+ mPool = pool;
+ }
public int beginOperation(String kind, String sql, Object[] bindArgs) {
synchronized (mOperations) {
@@ -1381,8 +1387,10 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
}
operation.mEndTime = SystemClock.uptimeMillis();
operation.mFinished = true;
+ final long execTime = operation.mEndTime - operation.mStartTime;
+ mPool.onStatementExecuted(execTime);
return SQLiteDebug.DEBUG_LOG_SLOW_QUERIES && SQLiteDebug.shouldLogSlowQuery(
- operation.mEndTime - operation.mStartTime);
+ execTime);
}
return false;
}
@@ -1426,11 +1434,16 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
int index = mIndex;
Operation operation = mOperations[index];
if (operation != null) {
+ // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created,
+ // and is relatively expensive to create during preloading. This method is only
+ // used when dumping a connection, which is a rare (mainly error) case.
+ SimpleDateFormat opDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
int n = 0;
do {
StringBuilder msg = new StringBuilder();
msg.append(" ").append(n).append(": [");
- msg.append(operation.getFormattedStartTime());
+ String formattedStartTime = opDF.format(new Date(operation.mStartWallTime));
+ msg.append(formattedStartTime);
msg.append("] ");
operation.describe(msg, verbose);
printer.println(msg.toString());
@@ -1518,12 +1531,5 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen
return methodName;
}
- private String getFormattedStartTime() {
- // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is
- // relatively expensive to create during preloading. This method is only used
- // when dumping a connection, which is a rare (mainly error) case. So:
- // DO NOT CACHE.
- return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(mStartWallTime));
- }
}
}
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index b66bf18fca1d..8b0fef4fe2bc 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.LockSupport;
/**
@@ -102,6 +103,8 @@ public final class SQLiteConnectionPool implements Closeable {
@GuardedBy("mLock")
private IdleConnectionHandler mIdleConnectionHandler;
+ private final AtomicLong mTotalExecutionTimeCounter = new AtomicLong(0);
+
// Describes what should happen to an acquired connection when it is returned to the pool.
enum AcquiredConnectionStatus {
// The connection should be returned to the pool as usual.
@@ -523,6 +526,10 @@ public final class SQLiteConnectionPool implements Closeable {
mConnectionLeaked.set(true);
}
+ void onStatementExecuted(long executionTimeMs) {
+ mTotalExecutionTimeCounter.addAndGet(executionTimeMs);
+ }
+
// Can't throw.
private void closeAvailableConnectionsAndLogExceptionsLocked() {
closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
@@ -1076,6 +1083,7 @@ public final class SQLiteConnectionPool implements Closeable {
printer.println("Connection pool for " + mConfiguration.path + ":");
printer.println(" Open: " + mIsOpen);
printer.println(" Max connections: " + mMaxConnectionPoolSize);
+ printer.println(" Total execution time: " + mTotalExecutionTimeCounter);
if (mConfiguration.isLookasideConfigSet()) {
printer.println(" Lookaside config: sz=" + mConfiguration.lookasideSlotSize
+ " cnt=" + mConfiguration.lookasideSlotCount);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index aa35a6610db7..931b5c913851 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -16,10 +16,11 @@
package android.hardware;
-import android.app.ActivityThread;
+import static android.system.OsConstants.*;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.app.job.JobInfo;
+import android.app.ActivityThread;
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Point;
@@ -34,11 +35,11 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.renderscript.Allocation;
import android.renderscript.Element;
-import android.renderscript.RenderScript;
import android.renderscript.RSIllegalArgumentException;
+import android.renderscript.RenderScript;
import android.renderscript.Type;
-import android.util.Log;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -48,8 +49,6 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
-import static android.system.OsConstants.*;
-
/**
* The Camera class is used to set image capture settings, start/stop preview,
* snap pictures, and retrieve frames for encoding for video. This class is a
@@ -243,12 +242,19 @@ public class Camera {
/**
* Returns the number of physical cameras available on this device.
+ *
+ * @return total number of accessible camera devices, or 0 if there are no
+ * cameras or an error was encountered enumerating them.
*/
public native static int getNumberOfCameras();
/**
* Returns the information about a particular camera.
* If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
+ *
+ * @throws RuntimeException if an invalid ID is provided, or if there is an
+ * error retrieving the information (generally due to a hardware or other
+ * low-level failure).
*/
public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
_getCameraInfo(cameraId, cameraInfo);
@@ -362,7 +368,10 @@ public class Camera {
/**
* Creates a new Camera object to access the first back-facing camera on the
* device. If the device does not have a back-facing camera, this returns
- * null.
+ * null. Otherwise acts like the {@link #open(int)} call.
+ *
+ * @return a new Camera object for the first back-facing camera, or null if there is no
+ * backfacing camera
* @see #open(int)
*/
public static Camera open() {
@@ -609,6 +618,8 @@ public class Camera {
*
* @throws IOException if a connection cannot be re-established (for
* example, if the camera is still in use by another process).
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
*/
public native final void reconnect() throws IOException;
@@ -637,6 +648,8 @@ public class Camera {
* or null to remove the preview surface
* @throws IOException if the method fails (for example, if the surface
* is unavailable or unsuitable).
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
*/
public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
if (holder != null) {
@@ -684,6 +697,8 @@ public class Camera {
* texture
* @throws IOException if the method fails (for example, if the surface
* texture is unavailable or unsuitable).
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
*/
public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException;
@@ -733,12 +748,20 @@ public class Camera {
* {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were
* called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)}
* will be called when preview data becomes available.
+ *
+ * @throws RuntimeException if starting preview fails; usually this would be
+ * because of a hardware or other low-level error, or because release()
+ * has been called on this Camera instance.
*/
public native final void startPreview();
/**
* Stops capturing and drawing preview frames to the surface, and
* resets the camera for a future call to {@link #startPreview()}.
+ *
+ * @throws RuntimeException if stopping preview fails; usually this would be
+ * because of a hardware or other low-level error, or because release()
+ * has been called on this Camera instance.
*/
public final void stopPreview() {
_stopPreview();
@@ -777,6 +800,8 @@ public class Camera {
*
* @param cb a callback object that receives a copy of each preview frame,
* or null to stop receiving callbacks.
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
* @see android.media.MediaActionSound
*/
public final void setPreviewCallback(PreviewCallback cb) {
@@ -803,6 +828,8 @@ public class Camera {
*
* @param cb a callback object that receives a copy of the next preview frame,
* or null to stop receiving callbacks.
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
* @see android.media.MediaActionSound
*/
public final void setOneShotPreviewCallback(PreviewCallback cb) {
@@ -840,6 +867,8 @@ public class Camera {
*
* @param cb a callback object that receives a copy of the preview frame,
* or null to stop receiving callbacks and clear the buffer queue.
+ * @throws RuntimeException if release() has been called on this Camera
+ * instance.
* @see #addCallbackBuffer(byte[])
* @see android.media.MediaActionSound
*/
@@ -1259,6 +1288,9 @@ public class Camera {
* success sound to the user.</p>
*
* @param cb the callback to run
+ * @throws RuntimeException if starting autofocus fails; usually this would
+ * be because of a hardware or other low-level error, or because
+ * release() has been called on this Camera instance.
* @see #cancelAutoFocus()
* @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
* @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
@@ -1279,6 +1311,9 @@ public class Camera {
* this function will return the focus position to the default.
* If the camera does not support auto-focus, this is a no-op.
*
+ * @throws RuntimeException if canceling autofocus fails; usually this would
+ * be because of a hardware or other low-level error, or because
+ * release() has been called on this Camera instance.
* @see #autoFocus(Camera.AutoFocusCallback)
*/
public final void cancelAutoFocus()
@@ -1333,6 +1368,9 @@ public class Camera {
* Sets camera auto-focus move callback.
*
* @param cb the callback to run
+ * @throws RuntimeException if enabling the focus move callback fails;
+ * usually this would be because of a hardware or other low-level error,
+ * or because release() has been called on this Camera instance.
*/
public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
mAutoFocusMoveCallback = cb;
@@ -1384,7 +1422,7 @@ public class Camera {
};
/**
- * Equivalent to takePicture(shutter, raw, null, jpeg).
+ * Equivalent to <pre>takePicture(Shutter, raw, null, jpeg)</pre>.
*
* @see #takePicture(ShutterCallback, PictureCallback, PictureCallback, PictureCallback)
*/
@@ -1422,6 +1460,9 @@ public class Camera {
* @param raw the callback for raw (uncompressed) image data, or null
* @param postview callback with postview image data, may be null
* @param jpeg the callback for JPEG image data, or null
+ * @throws RuntimeException if starting picture capture fails; usually this
+ * would be because of a hardware or other low-level error, or because
+ * release() has been called on this Camera instance.
*/
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
PictureCallback postview, PictureCallback jpeg) {
@@ -1534,6 +1575,9 @@ public class Camera {
*
* @param degrees the angle that the picture will be rotated clockwise.
* Valid values are 0, 90, 180, and 270.
+ * @throws RuntimeException if setting orientation fails; usually this would
+ * be because of a hardware or other low-level error, or because
+ * release() has been called on this Camera instance.
* @see #setPreviewDisplay(SurfaceHolder)
*/
public native final void setDisplayOrientation(int degrees);
@@ -1559,6 +1603,9 @@ public class Camera {
* changed. {@code false} if the shutter sound state could not be
* changed. {@code true} is also returned if shutter sound playback
* is already set to the requested state.
+ * @throws RuntimeException if the call fails; usually this would be because
+ * of a hardware or other low-level error, or because release() has been
+ * called on this Camera instance.
* @see #takePicture
* @see CameraInfo#canDisableShutterSound
* @see ShutterCallback
@@ -1903,6 +1950,9 @@ public class Camera {
* If modifications are made to the returned Parameters, they must be passed
* to {@link #setParameters(Camera.Parameters)} to take effect.
*
+ * @throws RuntimeException if reading parameters fails; usually this would
+ * be because of a hardware or other low-level error, or because
+ * release() has been called on this Camera instance.
* @see #setParameters(Camera.Parameters)
*/
public Parameters getParameters() {
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
new file mode 100644
index 000000000000..a83d31390775
--- /dev/null
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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 android.os;
+
+/**
+ * Binder interface to communicate with the Java-based statistics service helper.
+ * {@hide}
+ */
+oneway interface IStatsCompanionService {
+ /**
+ * Tell statscompanion that stastd is up and running.
+ */
+ void statsdReady();
+
+ /**
+ * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
+ * If anomaly alarm had already been registered, it will be replaced with the new timestamp.
+ * Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and
+ * alarm is inexact.
+ */
+ void setAnomalyAlarm(long timestampMs);
+
+ /** Cancel any anomaly detection alarm. */
+ void cancelAnomalyAlarm();
+
+ /**
+ * Register a repeating alarm for polling to fire at the given timestamp and every
+ * intervalMs thereafter (in ms since epoch).
+ * If polling alarm had already been registered, it will be replaced by new one.
+ * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
+ * and alarm is inexact.
+ */
+ void setPollingAlarms(long timestampMs, long intervalMs);
+
+ /** Cancel any repeating polling alarm. */
+ void cancelPollingAlarms();
+}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 9b5139dc5092..f8f28134063d 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -17,12 +17,32 @@
package android.os;
/**
- * Binder interface to communicate with the statistics collection service.
+ * Binder interface to communicate with the statistics management service.
* {@hide}
*/
-oneway interface IStatsManager {
+interface IStatsManager {
/**
- * Tell the incident daemon that the android system server is up and running.
+ * Tell the stats daemon that the android system server is up and running.
*/
- void systemRunning();
+ oneway void systemRunning();
+
+ /**
+ * Tell the stats daemon that the StatsCompanionService is up and running.
+ * Two-way binder call so that caller knows message received.
+ */
+ void statsCompanionReady();
+
+ /**
+ * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
+ * act accordingly.
+ * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+ */
+ void informAnomalyAlarmFired();
+
+ /**
+ * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
+ * what stats to poll and initiating the polling.
+ * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
+ */
+ void informPollAlarmFired();
}
diff --git a/core/java/android/os/ParcelableException.java b/core/java/android/os/ParcelableException.java
index d84d62997d93..7f71905d7f28 100644
--- a/core/java/android/os/ParcelableException.java
+++ b/core/java/android/os/ParcelableException.java
@@ -52,10 +52,12 @@ public final class ParcelableException extends RuntimeException implements Parce
final String msg = in.readString();
try {
final Class<?> clazz = Class.forName(name, true, Parcelable.class.getClassLoader());
- return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
+ if (Throwable.class.isAssignableFrom(clazz)) {
+ return (Throwable) clazz.getConstructor(String.class).newInstance(msg);
+ }
} catch (ReflectiveOperationException e) {
- throw new RuntimeException(name + ": " + msg);
}
+ return new RuntimeException(name + ": " + msg);
}
/** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 40ced6ce4815..3c3e466bebb6 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6966,8 +6966,9 @@ public final class Settings {
public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time";
/**
- * Time in milliseconds (since epoch) when Night display was last activated. Use to decide
- * whether to apply the current activated state after a reboot or user change.
+ * A String representing the LocalDateTime when Night display was last activated. Use to
+ * decide whether to apply the current activated state after a reboot or user change. In
+ * legacy cases, this is represented by the time in milliseconds (since epoch).
* @hide
*/
public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME =
@@ -10199,7 +10200,7 @@ public final class Settings {
"allow_user_switching_when_system_user_locked";
/**
- * Boot count since the device starts running APK level 24.
+ * Boot count since the device starts running API level 24.
* <p>
* Type: int
*/
diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java
index 813acc232289..2707f1467bcf 100644
--- a/core/java/android/service/carrier/CarrierService.java
+++ b/core/java/android/service/carrier/CarrierService.java
@@ -17,10 +17,13 @@ package android.service.carrier;
import android.annotation.CallSuper;
import android.app.Service;
import android.content.Intent;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.util.Log;
import com.android.internal.telephony.ITelephonyRegistry;
@@ -48,6 +51,8 @@ import com.android.internal.telephony.ITelephonyRegistry;
*/
public abstract class CarrierService extends Service {
+ private static final String LOG_TAG = "CarrierService";
+
public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
private static ITelephonyRegistry sRegistry;
@@ -133,11 +138,26 @@ public abstract class CarrierService extends Service {
/**
* A wrapper around ICarrierService that forwards calls to implementations of
* {@link CarrierService}.
+ * @hide
*/
- private class ICarrierServiceWrapper extends ICarrierService.Stub {
+ public class ICarrierServiceWrapper extends ICarrierService.Stub {
+ /** @hide */
+ public static final int RESULT_OK = 0;
+ /** @hide */
+ public static final int RESULT_ERROR = 1;
+ /** @hide */
+ public static final String KEY_CONFIG_BUNDLE = "config_bundle";
+
@Override
- public PersistableBundle getCarrierConfig(CarrierIdentifier id) {
- return CarrierService.this.onLoadConfig(id);
+ public void getCarrierConfig(CarrierIdentifier id, ResultReceiver result) {
+ try {
+ Bundle data = new Bundle();
+ data.putParcelable(KEY_CONFIG_BUNDLE, CarrierService.this.onLoadConfig(id));
+ result.send(RESULT_OK, data);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Error in onLoadConfig: " + e.getMessage(), e);
+ result.send(RESULT_ERROR, null);
+ }
}
}
}
diff --git a/core/java/android/service/carrier/ICarrierService.aidl b/core/java/android/service/carrier/ICarrierService.aidl
index 4c875851cfc8..ac6f9614d8f5 100644
--- a/core/java/android/service/carrier/ICarrierService.aidl
+++ b/core/java/android/service/carrier/ICarrierService.aidl
@@ -17,6 +17,7 @@
package android.service.carrier;
import android.os.PersistableBundle;
+import android.os.ResultReceiver;
import android.service.carrier.CarrierIdentifier;
/**
@@ -28,5 +29,5 @@ import android.service.carrier.CarrierIdentifier;
interface ICarrierService {
/** @see android.service.carrier.CarrierService#onLoadConfig */
- PersistableBundle getCarrierConfig(in CarrierIdentifier id);
+ oneway void getCarrierConfig(in CarrierIdentifier id, in ResultReceiver result);
}
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 5e40935cf6d2..24260c4f32c3 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -384,7 +384,7 @@ public class DynamicLayout extends Layout
private DynamicLayout(@NonNull Builder b) {
super(createEllipsizer(b.mEllipsize, b.mDisplay),
- b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
+ b.mPaint, b.mWidth, b.mAlignment, b.mTextDir, b.mSpacingMult, b.mSpacingAdd);
mDisplay = b.mDisplay;
mIncludePad = b.mIncludePad;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 91932dd40dd8..7198f371bf5e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -105,8 +105,8 @@ public class SurfaceControl {
long surfaceObject, long frame);
private static native void nativeReparentChildren(long nativeObject,
IBinder handle);
- private static native void nativeReparentChild(long nativeObject,
- IBinder parentHandle, IBinder childHandle);
+ private static native void nativeReparent(long nativeObject,
+ IBinder parentHandle);
private static native void nativeSeverChildren(long nativeObject);
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
@@ -455,9 +455,9 @@ public class SurfaceControl {
nativeReparentChildren(mNativeObject, newParentHandle);
}
- /** Re-parents a specific child layer to a new parent */
- public void reparentChild(IBinder newParentHandle, IBinder childHandle) {
- nativeReparentChild(mNativeObject, newParentHandle, childHandle);
+ /** Re-parents this layer to a new parent. */
+ public void reparent(IBinder newParentHandle) {
+ nativeReparent(mNativeObject, newParentHandle);
}
public void detachChildren() {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index cac27afa72cb..462dad3fad7a 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -231,6 +231,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
updateRequestedVisibility();
mAttachedToWindow = true;
+ mParent.requestTransparentRegion(SurfaceView.this);
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnScrollChangedListener(mScrollChangedListener);
@@ -269,8 +270,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (mPendingReportDraws > 0) {
mDrawFinished = true;
if (mAttachedToWindow) {
- mParent.requestTransparentRegion(SurfaceView.this);
-
notifyDrawFinished();
invalidate();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 27eeb2e67fb7..e906a1fa7807 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -37,7 +37,6 @@ import android.service.autofill.AutofillService;
import android.service.autofill.FillEventHistory;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.DebugUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
@@ -202,9 +201,12 @@ public final class AutofillManager {
* Initial state of the autofill context, set when there is no session (i.e., when
* {@link #mSessionId} is {@link #NO_SESSION}).
*
+ * <p>In this state, app callbacks (such as {@link #notifyViewEntered(View)}) are notified to
+ * the server.
+ *
* @hide
*/
- public static final int STATE_UNKNOWN = 1;
+ public static final int STATE_UNKNOWN = 0;
/**
* State where the autofill context hasn't been {@link #commit() finished} nor
@@ -212,7 +214,18 @@ public final class AutofillManager {
*
* @hide
*/
- public static final int STATE_ACTIVE = 2;
+ public static final int STATE_ACTIVE = 1;
+
+ /**
+ * State where the autofill context was finished by the server because the autofill
+ * service could not autofill the page.
+ *
+ * <p>In this state, most apps callback (such as {@link #notifyViewEntered(View)}) are ignored,
+ * exception {@link #requestAutofill(View)} (and {@link #requestAutofill(View, int, Rect)}).
+ *
+ * @hide
+ */
+ public static final int STATE_FINISHED = 2;
/**
* State where the autofill context has been {@link #commit() finished} but the server still has
@@ -220,7 +233,7 @@ public final class AutofillManager {
*
* @hide
*/
- public static final int STATE_SHOWING_SAVE_UI = 4;
+ public static final int STATE_SHOWING_SAVE_UI = 3;
/**
* Makes an authentication id from a request id and a dataset id.
@@ -559,6 +572,14 @@ public final class AutofillManager {
}
AutofillCallback callback = null;
synchronized (mLock) {
+ if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+ + "): ignored on state " + getStateAsStringLocked());
+ }
+ return;
+ }
+
ensureServiceClientAddedIfNeededLocked();
if (!mEnabled) {
@@ -682,6 +703,14 @@ public final class AutofillManager {
}
AutofillCallback callback = null;
synchronized (mLock) {
+ if (isFinishedLocked() && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyViewEntered(flags=" + flags + ", view=" + view
+ + ", virtualId=" + virtualId
+ + "): ignored on state " + getStateAsStringLocked());
+ }
+ return;
+ }
ensureServiceClientAddedIfNeededLocked();
if (!mEnabled) {
@@ -765,6 +794,10 @@ public final class AutofillManager {
}
if (!mEnabled || !isActiveLocked()) {
+ if (sVerbose && mEnabled) {
+ Log.v(TAG, "notifyValueChanged(" + view + "): ignoring on state "
+ + getStateAsStringLocked());
+ }
return;
}
@@ -950,10 +983,13 @@ public final class AutofillManager {
@NonNull AutofillValue value, int flags) {
if (sVerbose) {
Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
- + ", flags=" + flags + ", state=" + mState);
+ + ", flags=" + flags + ", state=" + getStateAsStringLocked());
}
- if (mState != STATE_UNKNOWN) {
- if (sDebug) Log.d(TAG, "not starting session for " + id + " on state " + mState);
+ if (mState != STATE_UNKNOWN && (flags & FLAG_MANUAL_REQUEST) == 0) {
+ if (sVerbose) {
+ Log.v(TAG, "not automatically starting session for " + id
+ + " on state " + getStateAsStringLocked());
+ }
return;
}
try {
@@ -973,7 +1009,7 @@ public final class AutofillManager {
}
private void finishSessionLocked() {
- if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + mState);
+ if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
if (!isActiveLocked()) return;
@@ -987,7 +1023,7 @@ public final class AutofillManager {
}
private void cancelSessionLocked() {
- if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + mState);
+ if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
if (!isActiveLocked()) return;
@@ -1306,6 +1342,20 @@ public final class AutofillManager {
}
}
+ /**
+ * Marks the state of the session as finished.
+ *
+ * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
+ * FillResponse) or {@link #STATE_UNKNOWN} (because the session was removed).
+ */
+ private void setSessionFinished(int newState) {
+ synchronized (mLock) {
+ if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
+ resetSessionLocked();
+ mState = newState;
+ }
+ }
+
private void requestHideFillUi(AutofillId id) {
final View anchor = findView(id);
if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
@@ -1341,7 +1391,11 @@ public final class AutofillManager {
}
}
- private void notifyNoFillUi(int sessionId, AutofillId id) {
+ private void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
+ + ", finished=" + sessionFinished);
+ }
final View anchor = findView(id);
if (anchor == null) {
return;
@@ -1361,7 +1415,11 @@ public final class AutofillManager {
} else {
callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
}
+ }
+ if (sessionFinished) {
+ // Callback call was "hijacked" to also update the session state.
+ setSessionFinished(STATE_FINISHED);
}
}
@@ -1434,8 +1492,7 @@ public final class AutofillManager {
pw.print(outerPrefix); pw.println("AutofillManager:");
final String pfx = outerPrefix + " ";
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
- pw.print(pfx); pw.print("state: "); pw.println(
- DebugUtils.flagsToString(AutofillManager.class, "STATE_", mState));
+ pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -1452,10 +1509,29 @@ public final class AutofillManager {
pw.print(pfx); pw.print("fillable ids: "); pw.println(mFillableIds);
}
+ private String getStateAsStringLocked() {
+ switch (mState) {
+ case STATE_UNKNOWN:
+ return "STATE_UNKNOWN";
+ case STATE_ACTIVE:
+ return "STATE_ACTIVE";
+ case STATE_FINISHED:
+ return "STATE_FINISHED";
+ case STATE_SHOWING_SAVE_UI:
+ return "STATE_SHOWING_SAVE_UI";
+ default:
+ return "INVALID:" + mState;
+ }
+ }
+
private boolean isActiveLocked() {
return mState == STATE_ACTIVE;
}
+ private boolean isFinishedLocked() {
+ return mState == STATE_FINISHED;
+ }
+
private void post(Runnable runnable) {
final AutofillClient client = getClientLocked();
if (client == null) {
@@ -1787,10 +1863,10 @@ public final class AutofillManager {
}
@Override
- public void notifyNoFillUi(int sessionId, AutofillId id) {
+ public void notifyNoFillUi(int sessionId, AutofillId id, boolean sessionFinished) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.notifyNoFillUi(sessionId, id));
+ afm.post(() -> afm.notifyNoFillUi(sessionId, id, sessionFinished));
}
}
@@ -1823,7 +1899,15 @@ public final class AutofillManager {
public void setSaveUiState(int sessionId, boolean shown) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() ->afm.setSaveUiState(sessionId, shown));
+ afm.post(() -> afm.setSaveUiState(sessionId, shown));
+ }
+ }
+
+ @Override
+ public void setSessionFinished(int newState) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.setSessionFinished(newState));
}
}
}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 0eae85860383..3dabcec8636a 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -67,9 +67,9 @@ oneway interface IAutoFillManagerClient {
void requestHideFillUi(int sessionId, in AutofillId id);
/**
- * Notifies no fill UI will be shown.
+ * Notifies no fill UI will be shown, and also mark the state as finished if necessary.
*/
- void notifyNoFillUi(int sessionId, in AutofillId id);
+ void notifyNoFillUi(int sessionId, in AutofillId id, boolean sessionFinished);
/**
* Starts the provided intent sender.
@@ -80,4 +80,11 @@ oneway interface IAutoFillManagerClient {
* Sets the state of the Autofill Save UI for a given session.
*/
void setSaveUiState(int sessionId, boolean shown);
+
+ /**
+ * Marks the state of the session as finished.
+ * @param newState STATE_FINISHED (because the autofill service returned a null
+ * FillResponse) or STATE_UNKNOWN (because the session was removed).
+ */
+ void setSessionFinished(int newState);
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 7c4154f5c648..994512f7c897 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -463,7 +463,7 @@ public final class WebViewFactory {
*/
public static int onWebViewProviderChanged(PackageInfo packageInfo) {
String[] nativeLibs = null;
- String originalSourceDir = packageInfo.applicationInfo.sourceDir;
+ ApplicationInfo originalAppInfo = new ApplicationInfo(packageInfo.applicationInfo);
try {
fixupStubApplicationInfo(packageInfo.applicationInfo,
AppGlobals.getInitialApplication().getPackageManager());
@@ -474,7 +474,7 @@ public final class WebViewFactory {
Log.e(LOGTAG, "error preparing webview native library", t);
}
- WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir);
+ WebViewZygote.onWebViewProviderChanged(packageInfo, originalAppInfo);
return prepareWebViewInSystemServer(nativeLibs);
}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 6e65c7a11d2f..db60ad8d1c05 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.SystemService;
@@ -67,11 +68,11 @@ public class WebViewZygote {
private static PackageInfo sPackage;
/**
- * Cache key for the selected WebView package's classloader. This is set from
+ * Original ApplicationInfo for the selected WebView package before stub fixup. This is set from
* #onWebViewProviderChanged().
*/
@GuardedBy("sLock")
- private static String sPackageCacheKey;
+ private static ApplicationInfo sPackageOriginalAppInfo;
/**
* Flag for whether multi-process WebView is enabled. If this is {@code false}, the zygote
@@ -125,10 +126,11 @@ public class WebViewZygote {
}
}
- public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) {
+ public static void onWebViewProviderChanged(PackageInfo packageInfo,
+ ApplicationInfo originalAppInfo) {
synchronized (sLock) {
sPackage = packageInfo;
- sPackageCacheKey = cacheKey;
+ sPackageOriginalAppInfo = originalAppInfo;
// If multi-process is not enabled, then do not start the zygote service.
if (!sMultiprocessEnabled) {
@@ -217,10 +219,17 @@ public class WebViewZygote {
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
+ // In the case where the ApplicationInfo has been modified by the stub WebView,
+ // we need to use the original ApplicationInfo to determine what the original classpath
+ // would have been to use as a cache key.
+ LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
+ final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
+ TextUtils.join(File.pathSeparator, zipPaths);
+
ZygoteProcess.waitForConnectionToZygote(WEBVIEW_ZYGOTE_SOCKET);
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
- sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey,
+ sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey,
Build.SUPPORTED_ABIS[0]);
} catch (Exception e) {
Log.e(LOGTAG, "Error connecting to " + serviceName, e);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index bc85fadb5ad9..1653afd1ac0f 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -16,9 +16,10 @@
package android.widget;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import android.annotation.ColorInt;
import android.annotation.DimenRes;
-import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.app.Application;
@@ -324,11 +325,11 @@ public class RemoteViews implements Parcelable, Filter {
public boolean onClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
- return onClickHandler(view, pendingIntent, fillInIntent, StackId.INVALID_STACK_ID);
+ return onClickHandler(view, pendingIntent, fillInIntent, WINDOWING_MODE_UNDEFINED);
}
public boolean onClickHandler(View view, PendingIntent pendingIntent,
- Intent fillInIntent, int launchStackId) {
+ Intent fillInIntent, int windowingMode) {
try {
// TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
Context context = view.getContext();
@@ -339,8 +340,8 @@ public class RemoteViews implements Parcelable, Filter {
opts = ActivityOptions.makeBasic();
}
- if (launchStackId != StackId.INVALID_STACK_ID) {
- opts.setLaunchStackId(launchStackId);
+ if (windowingMode != WINDOWING_MODE_UNDEFINED) {
+ opts.setLaunchWindowingMode(windowingMode);
}
context.startIntentSender(
pendingIntent.getIntentSender(), fillInIntent,
@@ -2338,20 +2339,12 @@ public class RemoteViews implements Parcelable, Filter {
}
if (src.mActions != null) {
- mActions = new ArrayList<>();
-
Parcel p = Parcel.obtain();
- int count = src.mActions.size();
- for (int i = 0; i < count; i++) {
- p.setDataPosition(0);
- Action a = src.mActions.get(i);
- a.writeToParcel(
- p, a.hasSameAppInfo(mApplication) ? PARCELABLE_ELIDE_DUPLICATES : 0);
- p.setDataPosition(0);
- // Since src is already in memory, we do not care about stack overflow as it has
- // already been read once.
- mActions.add(getActionFromParcel(p, 0));
- }
+ writeActionsToParcel(p);
+ p.setDataPosition(0);
+ // Since src is already in memory, we do not care about stack overflow as it has
+ // already been read once.
+ readActionsFromParcel(p, 0);
p.recycle();
}
@@ -2392,13 +2385,7 @@ public class RemoteViews implements Parcelable, Filter {
mLayoutId = parcel.readInt();
mIsWidgetCollectionChild = parcel.readInt() == 1;
- int count = parcel.readInt();
- if (count > 0) {
- mActions = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- mActions.add(getActionFromParcel(parcel, depth));
- }
- }
+ readActionsFromParcel(parcel, depth);
} else {
// MODE_HAS_LANDSCAPE_AND_PORTRAIT
mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth);
@@ -2409,6 +2396,16 @@ public class RemoteViews implements Parcelable, Filter {
mReapplyDisallowed = parcel.readInt() == 0;
}
+ private void readActionsFromParcel(Parcel parcel, int depth) {
+ int count = parcel.readInt();
+ if (count > 0) {
+ mActions = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ mActions.add(getActionFromParcel(parcel, depth));
+ }
+ }
+ }
+
private Action getActionFromParcel(Parcel parcel, int depth) {
int tag = parcel.readInt();
switch (tag) {
@@ -3695,18 +3692,7 @@ public class RemoteViews implements Parcelable, Filter {
}
dest.writeInt(mLayoutId);
dest.writeInt(mIsWidgetCollectionChild ? 1 : 0);
- int count;
- if (mActions != null) {
- count = mActions.size();
- } else {
- count = 0;
- }
- dest.writeInt(count);
- for (int i=0; i<count; i++) {
- Action a = mActions.get(i);
- a.writeToParcel(dest, a.hasSameAppInfo(mApplication)
- ? PARCELABLE_ELIDE_DUPLICATES : 0);
- }
+ writeActionsToParcel(dest);
} else {
dest.writeInt(MODE_HAS_LANDSCAPE_AND_PORTRAIT);
// We only write the bitmap cache if we are the root RemoteViews, as this cache
@@ -3721,6 +3707,21 @@ public class RemoteViews implements Parcelable, Filter {
dest.writeInt(mReapplyDisallowed ? 1 : 0);
}
+ private void writeActionsToParcel(Parcel parcel) {
+ int count;
+ if (mActions != null) {
+ count = mActions.size();
+ } else {
+ count = 0;
+ }
+ parcel.writeInt(count);
+ for (int i = 0; i < count; i++) {
+ Action a = mActions.get(i);
+ a.writeToParcel(parcel, a.hasSameAppInfo(mApplication)
+ ? PARCELABLE_ELIDE_DUPLICATES : 0);
+ }
+ }
+
private static ApplicationInfo getApplicationInfo(String packageName, int userId) {
if (packageName == null) {
return null;
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 2e1e96365f2a..604575fae463 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -248,10 +248,7 @@ public class Switch extends CompoundButton {
com.android.internal.R.styleable.Switch_switchPadding, 0);
mSplitTrack = a.getBoolean(com.android.internal.R.styleable.Switch_splitTrack, false);
- // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES.
- // STOPSHIP if the above TODO is not done.
- mUseFallbackLineSpacing =
- context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT;
+ mUseFallbackLineSpacing = context.getApplicationInfo().targetSdkVersion >= VERSION_CODES.P;
ColorStateList thumbTintList = a.getColorStateList(
com.android.internal.R.styleable.Switch_thumbTint);
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 05f7c0a1ee08..f8b6837e2d39 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -61,7 +61,10 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
// This value will be set to 0 as soon as the first tab is added to TabHost.
private int mSelectedTab = -1;
+ @Nullable
private Drawable mLeftStrip;
+
+ @Nullable
private Drawable mRightStrip;
private boolean mDrawBottomStrips = true;
@@ -374,23 +377,36 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
final Drawable leftStrip = mLeftStrip;
final Drawable rightStrip = mRightStrip;
- leftStrip.setState(selectedChild.getDrawableState());
- rightStrip.setState(selectedChild.getDrawableState());
+ if (leftStrip != null) {
+ leftStrip.setState(selectedChild.getDrawableState());
+ }
+ if (rightStrip != null) {
+ rightStrip.setState(selectedChild.getDrawableState());
+ }
if (mStripMoved) {
final Rect bounds = mBounds;
bounds.left = selectedChild.getLeft();
bounds.right = selectedChild.getRight();
final int myHeight = getHeight();
- leftStrip.setBounds(Math.min(0, bounds.left - leftStrip.getIntrinsicWidth()),
- myHeight - leftStrip.getIntrinsicHeight(), bounds.left, myHeight);
- rightStrip.setBounds(bounds.right, myHeight - rightStrip.getIntrinsicHeight(),
- Math.max(getWidth(), bounds.right + rightStrip.getIntrinsicWidth()), myHeight);
+ if (leftStrip != null) {
+ leftStrip.setBounds(Math.min(0, bounds.left - leftStrip.getIntrinsicWidth()),
+ myHeight - leftStrip.getIntrinsicHeight(), bounds.left, myHeight);
+ }
+ if (rightStrip != null) {
+ rightStrip.setBounds(bounds.right, myHeight - rightStrip.getIntrinsicHeight(),
+ Math.max(getWidth(), bounds.right + rightStrip.getIntrinsicWidth()),
+ myHeight);
+ }
mStripMoved = false;
}
- leftStrip.draw(canvas);
- rightStrip.draw(canvas);
+ if (leftStrip != null) {
+ leftStrip.draw(canvas);
+ }
+ if (rightStrip != null) {
+ rightStrip.draw(canvas);
+ }
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2de552777756..791a8fae418f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1256,9 +1256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mUseInternationalizedInput = targetSdkVersion >= VERSION_CODES.O;
- // TODO: replace CUR_DEVELOPMENT with P once P is added to android.os.Build.VERSION_CODES.
- // STOPSHIP if the above TODO is not done.
- mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.CUR_DEVELOPMENT;
+ mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.P;
if (inputMethod != null) {
Class<?> c;
diff --git a/core/java/com/android/internal/app/NightDisplayController.java b/core/java/com/android/internal/app/NightDisplayController.java
index 860c5c4c3d3b..7a1383c7a01c 100644
--- a/core/java/com/android/internal/app/NightDisplayController.java
+++ b/core/java/com/android/internal/app/NightDisplayController.java
@@ -32,8 +32,12 @@ import com.android.internal.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Calendar;
-import java.util.Locale;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeParseException;
/**
* Controller for managing Night display settings.
@@ -116,8 +120,9 @@ public final class NightDisplayController {
*/
public boolean setActivated(boolean activated) {
if (isActivated() != activated) {
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, System.currentTimeMillis(),
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ LocalDateTime.now().toString(),
mUserId);
}
return Secure.putIntForUser(mContext.getContentResolver(),
@@ -128,17 +133,22 @@ public final class NightDisplayController {
* Returns the time when Night display's activation state last changed, or {@code null} if it
* has never been changed.
*/
- public Calendar getLastActivatedTime() {
+ public LocalDateTime getLastActivatedTime() {
final ContentResolver cr = mContext.getContentResolver();
- final long lastActivatedTimeMillis = Secure.getLongForUser(
- cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1, mUserId);
- if (lastActivatedTimeMillis < 0) {
- return null;
+ final String lastActivatedTime = Secure.getStringForUser(
+ cr, Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, mUserId);
+ if (lastActivatedTime != null) {
+ try {
+ return LocalDateTime.parse(lastActivatedTime);
+ } catch (DateTimeParseException ignored) {}
+ // Uses the old epoch time.
+ try {
+ return LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(Long.parseLong(lastActivatedTime)),
+ ZoneId.systemDefault());
+ } catch (DateTimeException|NumberFormatException ignored) {}
}
-
- final Calendar lastActivatedTime = Calendar.getInstance();
- lastActivatedTime.setTimeInMillis(lastActivatedTimeMillis);
- return lastActivatedTime;
+ return null;
}
/**
@@ -183,8 +193,10 @@ public final class NightDisplayController {
}
if (getAutoMode() != autoMode) {
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, -1L, mUserId);
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ null,
+ mUserId);
}
return Secure.putIntForUser(mContext.getContentResolver(),
Secure.NIGHT_DISPLAY_AUTO_MODE, autoMode, mUserId);
@@ -206,7 +218,7 @@ public final class NightDisplayController {
R.integer.config_defaultNightDisplayCustomStartTime);
}
- return LocalTime.valueOf(startTimeValue);
+ return LocalTime.ofSecondOfDay(startTimeValue / 1000);
}
/**
@@ -221,7 +233,7 @@ public final class NightDisplayController {
throw new IllegalArgumentException("startTime cannot be null");
}
return Secure.putIntForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toMillis(), mUserId);
+ Secure.NIGHT_DISPLAY_CUSTOM_START_TIME, startTime.toSecondOfDay() * 1000, mUserId);
}
/**
@@ -240,7 +252,7 @@ public final class NightDisplayController {
R.integer.config_defaultNightDisplayCustomEndTime);
}
- return LocalTime.valueOf(endTimeValue);
+ return LocalTime.ofSecondOfDay(endTimeValue / 1000);
}
/**
@@ -255,7 +267,7 @@ public final class NightDisplayController {
throw new IllegalArgumentException("endTime cannot be null");
}
return Secure.putIntForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toMillis(), mUserId);
+ Secure.NIGHT_DISPLAY_CUSTOM_END_TIME, endTime.toSecondOfDay() * 1000, mUserId);
}
/**
@@ -379,106 +391,6 @@ public final class NightDisplayController {
}
/**
- * A time without a time-zone or date.
- */
- public static class LocalTime {
-
- /**
- * The hour of the day from 0 - 23.
- */
- public final int hourOfDay;
- /**
- * The minute within the hour from 0 - 59.
- */
- public final int minute;
-
- public LocalTime(int hourOfDay, int minute) {
- if (hourOfDay < 0 || hourOfDay > 23) {
- throw new IllegalArgumentException("Invalid hourOfDay: " + hourOfDay);
- } else if (minute < 0 || minute > 59) {
- throw new IllegalArgumentException("Invalid minute: " + minute);
- }
-
- this.hourOfDay = hourOfDay;
- this.minute = minute;
- }
-
- /**
- * Returns the first date time corresponding to this local time that occurs before the
- * provided date time.
- *
- * @param time the date time to compare against
- * @return the prior date time corresponding to this local time
- */
- public Calendar getDateTimeBefore(Calendar time) {
- final Calendar c = Calendar.getInstance();
- c.set(Calendar.YEAR, time.get(Calendar.YEAR));
- c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
- c.set(Calendar.HOUR_OF_DAY, hourOfDay);
- c.set(Calendar.MINUTE, minute);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
-
- // Check if the local time has past, if so return the same time tomorrow.
- if (c.after(time)) {
- c.add(Calendar.DATE, -1);
- }
-
- return c;
- }
-
- /**
- * Returns the first date time corresponding to this local time that occurs after the
- * provided date time.
- *
- * @param time the date time to compare against
- * @return the next date time corresponding to this local time
- */
- public Calendar getDateTimeAfter(Calendar time) {
- final Calendar c = Calendar.getInstance();
- c.set(Calendar.YEAR, time.get(Calendar.YEAR));
- c.set(Calendar.DAY_OF_YEAR, time.get(Calendar.DAY_OF_YEAR));
-
- c.set(Calendar.HOUR_OF_DAY, hourOfDay);
- c.set(Calendar.MINUTE, minute);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
-
- // Check if the local time has past, if so return the same time tomorrow.
- if (c.before(time)) {
- c.add(Calendar.DATE, 1);
- }
-
- return c;
- }
-
- /**
- * Returns a local time corresponding the given number of milliseconds from midnight.
- *
- * @param millis the number of milliseconds from midnight
- * @return the corresponding local time
- */
- private static LocalTime valueOf(int millis) {
- final int hourOfDay = (millis / 3600000) % 24;
- final int minutes = (millis / 60000) % 60;
- return new LocalTime(hourOfDay, minutes);
- }
-
- /**
- * Returns the local time represented as milliseconds from midnight.
- */
- private int toMillis() {
- return hourOfDay * 3600000 + minute * 60000;
- }
-
- @Override
- public String toString() {
- return String.format(Locale.US, "%02d:%02d", hourOfDay, minute);
- }
- }
-
- /**
* Callback invoked whenever the Night display settings are changed.
*/
public interface Callback {
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 42e9273c5ba2..64e12b4ec05c 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -560,7 +560,7 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA
if (stream.get()) {
std::unique_ptr<SkStreamRewindable> bufferedStream(
- SkFrontBufferedStream::Create(stream.release(), SkCodec::MinBufferedBytesNeeded()));
+ SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
SkASSERT(bufferedStream.get() != NULL);
bitmap = doDecode(env, std::move(bufferedStream), padding, options);
}
@@ -610,7 +610,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
// Use a buffered stream. Although an SkFILEStream can be rewound, this
// ensures that SkImageDecoder::Factory never rewinds beyond the
// current position of the file descriptor.
- std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
+ std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
SkCodec::MinBufferedBytesNeeded()));
return doDecode(env, std::move(stream), padding, bitmapFactoryOptions);
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index b243817803ad..4c10a85c8257 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -104,7 +104,8 @@ static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
// will only read 6.
// FIXME: Get this number from SkImageDecoder
// bufferedStream takes ownership of strm
- std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
+ std::unique_ptr<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Make(
+ std::unique_ptr<SkStream>(strm), 6));
SkASSERT(bufferedStream.get() != NULL);
Movie* moov = Movie::DecodeStream(bufferedStream.get());
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 8934c1e50aba..630220a4c9ed 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -42,7 +42,7 @@ bool AssetStreamAdaptor::isAtEnd() const {
return fAsset->getRemainingLength() == 0;
}
-SkStreamRewindable* AssetStreamAdaptor::duplicate() const {
+SkStreamRewindable* AssetStreamAdaptor::onDuplicate() const {
// Cannot create a duplicate, since each AssetStreamAdaptor
// would be modifying the Asset.
//return new AssetStreamAdaptor(fAsset);
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index fffec5b87b81..69930a581468 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -36,7 +36,9 @@ public:
virtual size_t getLength() const;
virtual bool isAtEnd() const;
- virtual SkStreamRewindable* duplicate() const;
+protected:
+ SkStreamRewindable* onDuplicate() const override;
+
private:
Asset* fAsset;
};
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 863ca8b0bc02..b610b35e45cd 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -484,14 +484,14 @@ static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobjec
sp<ANativeWindow> anw;
if ((anw = getNativeWindow(env, surface)) == NULL) {
- jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+ jniThrowException(env, "java/lang/UnsupportedOperationException;",
"Could not retrieve native window from surface.");
return BAD_VALUE;
}
int32_t usage = 0;
status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
if(err != NO_ERROR) {
- jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+ jniThrowException(env, "java/lang/UnsupportedOperationException;",
"Error while querying surface usage bits");
return err;
}
@@ -511,7 +511,7 @@ static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz
status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
if(err != NO_ERROR) {
- jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+ jniThrowException(env, "java/lang/UnsupportedOperationException;",
"Error while disconnecting surface");
return err;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 883d4db04890..af5d12bd2510 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -20,8 +20,6 @@
#include "android_os_Parcel.h"
#include "android_util_Binder.h"
-#include <nativehelper/JNIHelp.h>
-
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -44,8 +42,9 @@
#include <utils/SystemClock.h>
#include <utils/threads.h>
-#include <nativehelper/ScopedUtfChars.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
#include "core_jni_helpers.h"
@@ -174,8 +173,49 @@ static JNIEnv* javavm_to_jnienv(JavaVM* vm)
return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
}
-// Report a java.lang.Error (or subclass). This may terminate the runtime.
-static void report_java_lang_error(JNIEnv* env, jthrowable error)
+// Report a java.lang.Error (or subclass). This will terminate the runtime by
+// calling FatalError with a message derived from the given error.
+static void report_java_lang_error_fatal_error(JNIEnv* env, jthrowable error,
+ const char* msg)
+{
+ // Report an error: reraise the exception and ask the runtime to abort.
+
+ // Try to get the exception string. Sometimes logcat isn't available,
+ // so try to add it to the abort message.
+ std::string exc_msg = "(Unknown exception message)";
+ {
+ ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(error));
+ jmethodID method_id = env->GetMethodID(exc_class.get(), "toString",
+ "()Ljava/lang/String;");
+ ScopedLocalRef<jstring> jstr(
+ env,
+ reinterpret_cast<jstring>(
+ env->CallObjectMethod(error, method_id)));
+ env->ExceptionClear(); // Just for good measure.
+ if (jstr.get() != nullptr) {
+ ScopedUtfChars jstr_utf(env, jstr.get());
+ if (jstr_utf.c_str() != nullptr) {
+ exc_msg = jstr_utf.c_str();
+ } else {
+ env->ExceptionClear();
+ }
+ }
+ }
+
+ env->Throw(error);
+ ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
+ env->ExceptionDescribe();
+
+ std::string error_msg = base::StringPrintf(
+ "java.lang.Error thrown during binder transaction: %s",
+ exc_msg.c_str());
+ env->FatalError(error_msg.c_str());
+}
+
+// Report a java.lang.Error (or subclass). This will terminate the runtime, either by
+// the uncaught exception handler, or explicitly by calling
+// report_java_lang_error_fatal_error.
+static void report_java_lang_error(JNIEnv* env, jthrowable error, const char* msg)
{
// Try to run the uncaught exception machinery.
jobject thread = env->CallStaticObjectMethod(gThreadDispatchOffsets.mClass,
@@ -187,77 +227,39 @@ static void report_java_lang_error(JNIEnv* env, jthrowable error)
}
// Some error occurred that meant that either dispatchUncaughtException could not be
// called or that it had an error itself (as this should be unreachable under normal
- // conditions). Clear the exception.
+ // conditions). As the binder code cannot handle Errors, attempt to log the error and
+ // abort.
env->ExceptionClear();
+ report_java_lang_error_fatal_error(env, error, msg);
}
static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
{
env->ExceptionClear();
- jstring tagstr = env->NewStringUTF(LOG_TAG);
- jstring msgstr = NULL;
- if (tagstr != NULL) {
- msgstr = env->NewStringUTF(msg);
+ ScopedLocalRef<jstring> tagstr(env, env->NewStringUTF(LOG_TAG));
+ ScopedLocalRef<jstring> msgstr(env);
+ if (tagstr != nullptr) {
+ msgstr.reset(env->NewStringUTF(msg));
}
- if ((tagstr == NULL) || (msgstr == NULL)) {
+ if ((tagstr != nullptr) && (msgstr != nullptr)) {
+ env->CallStaticIntMethod(gLogOffsets.mClass, gLogOffsets.mLogE,
+ tagstr.get(), msgstr.get(), excep);
+ if (env->ExceptionCheck()) {
+ // Attempting to log the failure has failed.
+ ALOGW("Failed trying to log exception, msg='%s'\n", msg);
+ env->ExceptionClear();
+ }
+ } else {
env->ExceptionClear(); /* assume exception (OOM?) was thrown */
ALOGE("Unable to call Log.e()\n");
ALOGE("%s", msg);
- goto bail;
- }
-
- env->CallStaticIntMethod(
- gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep);
- if (env->ExceptionCheck()) {
- /* attempting to log the failure has failed */
- ALOGW("Failed trying to log exception, msg='%s'\n", msg);
- env->ExceptionClear();
}
if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
- // Try to report the error. This should not return under normal circumstances.
- report_java_lang_error(env, excep);
- // The traditional handling: re-raise and abort.
-
- /*
- * It's an Error: Reraise the exception and ask the runtime to abort.
- */
-
- // Try to get the exception string. Sometimes logcat isn't available,
- // so try to add it to the abort message.
- std::string exc_msg = "(Unknown exception message)";
- {
- ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep));
- jmethodID method_id = env->GetMethodID(exc_class.get(),
- "toString",
- "()Ljava/lang/String;");
- ScopedLocalRef<jstring> jstr(
- env,
- reinterpret_cast<jstring>(
- env->CallObjectMethod(excep, method_id)));
- env->ExceptionClear(); // Just for good measure.
- if (jstr.get() != nullptr) {
- ScopedUtfChars jstr_utf(env, jstr.get());
- exc_msg = jstr_utf.c_str();
- }
- }
-
- env->Throw(excep);
- ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
- env->ExceptionDescribe();
-
- std::string error_msg = base::StringPrintf(
- "java.lang.Error thrown during binder transaction: %s",
- exc_msg.c_str());
- env->FatalError(error_msg.c_str());
+ report_java_lang_error(env, excep, msg);
}
-
-bail:
- /* discard local refs created for us by VM */
- env->DeleteLocalRef(tagstr);
- env->DeleteLocalRef(msgstr);
}
class JavaBBinderHolder;
@@ -309,14 +311,11 @@ protected:
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
if (env->ExceptionCheck()) {
- jthrowable excep = env->ExceptionOccurred();
- report_exception(env, excep,
+ ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+ report_exception(env, excep.get(),
"*** Uncaught remote exception! "
"(Exceptions are not yet supported across processes.)");
res = JNI_FALSE;
-
- /* clean up JNI local ref -- we don't return to Java code */
- env->DeleteLocalRef(excep);
}
// Check if the strict mode state changed while processing the
@@ -328,11 +327,9 @@ protected:
}
if (env->ExceptionCheck()) {
- jthrowable excep = env->ExceptionOccurred();
- report_exception(env, excep,
+ ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
+ report_exception(env, excep.get(),
"*** Uncaught exception in onBinderStrictModePolicyChange");
- /* clean up JNI local ref -- we don't return to Java code */
- env->DeleteLocalRef(excep);
}
// Need to always call through the native implementation of
@@ -475,9 +472,8 @@ public:
if (mObject != NULL) {
result = env->IsSameObject(obj, mObject);
} else {
- jobject me = env->NewLocalRef(mObjectWeak);
- result = env->IsSameObject(obj, me);
- env->DeleteLocalRef(me);
+ ScopedLocalRef<jobject> me(env, env->NewLocalRef(mObjectWeak));
+ result = env->IsSameObject(obj, me.get());
}
return result;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 33f1c7d393af..bf8bbf53295a 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -736,13 +736,11 @@ static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject
ctrl->reparentChildren(handle);
}
-static void nativeReparentChild(JNIEnv* env, jclass clazz, jlong nativeObject,
- jobject newParentObject, jobject childObject) {
+static void nativeReparent(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject newParentObject) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
sp<IBinder> parentHandle = ibinderForJavaObject(env, newParentObject);
- sp<IBinder> childHandle = ibinderForJavaObject(env, childObject);
-
- ctrl->reparentChild(parentHandle, childHandle);
+ ctrl->reparent(parentHandle);
}
static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
@@ -868,8 +866,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeDeferTransactionUntilSurface },
{"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
(void*)nativeReparentChildren } ,
- {"nativeReparentChild", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
- (void*)nativeReparentChild },
+ {"nativeReparent", "(JLandroid/os/IBinder;)V",
+ (void*)nativeReparent },
{"nativeSeverChildren", "(J)V",
(void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JI)V",
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
new file mode 100644
index 000000000000..d5ecacc8f72c
--- /dev/null
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+
+package com.android.server.am.proto;
+
+option java_multiple_files = true;
+
+message ActivityManagerServiceProto {
+ ActivityStackSupervisorProto activities = 1;
+}
+
+message ActivityStackSupervisorProto {
+ .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+ repeated ActivityDisplayProto displays = 2;
+ KeyguardControllerProto keyguard_controller = 3;
+ int32 focused_stack_id = 4;
+ .com.android.server.wm.proto.IdentifierProto resumed_activity = 5;
+}
+
+/* represents ActivityStackSupervisor.ActivityDisplay */
+message ActivityDisplayProto {
+ .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+ int32 id = 2;
+ repeated ActivityStackProto stacks = 3;
+}
+
+message ActivityStackProto {
+ .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+ int32 id = 2;
+ repeated TaskRecordProto tasks = 3;
+ .com.android.server.wm.proto.IdentifierProto resumed_activity = 4;
+ int32 display_id = 5;
+ bool fullscreen = 6;
+ .android.graphics.RectProto bounds = 7;
+}
+
+message TaskRecordProto {
+ .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+ int32 id = 2;
+ repeated ActivityRecordProto activities = 3;
+ int32 stack_id = 4;
+ .android.graphics.RectProto last_non_fullscreen_bounds = 5;
+ string real_activity = 6;
+ string orig_activity = 7;
+ int32 activity_type = 8;
+ int32 return_to_type = 9;
+ int32 resize_mode = 10;
+ bool fullscreen = 11;
+ .android.graphics.RectProto bounds = 12;
+ int32 min_width = 13;
+ int32 min_height = 14;
+}
+
+message ActivityRecordProto {
+ .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
+ .com.android.server.wm.proto.IdentifierProto identifier = 2;
+ string state = 3;
+ bool visible = 4;
+ bool front_of_task = 5;
+ int32 proc_id = 6;
+}
+
+message KeyguardControllerProto {
+ bool keyguard_showing = 1;
+ bool keyguard_occluded = 2;
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aa94e0ff19e6..695fdac70280 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3074,6 +3074,12 @@
<permission android:name="android.permission.BATTERY_STATS"
android:protectionLevel="signature|privileged|development" />
+ <!--Allows an application to manage statscompanion.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.STATSCOMPANION"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control the backup and restore process.
<p>Not for use by third-party applications.
@hide pending API council -->
@@ -3859,6 +3865,16 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.stats.StatsCompanionService$AnomalyAlarmReceiver"
+ android:permission="android.permission.STATSCOMPANION"
+ android:exported="false">
+ </receiver>
+
+ <receiver android:name="com.android.server.stats.StatsCompanionService$PollingAlarmReceiver"
+ android:permission="android.permission.STATSCOMPANION"
+ android:exported="false">
+ </receiver>
+
<service android:name="android.hardware.location.GeofenceHardwareService"
android:permission="android.permission.LOCATION_HARDWARE"
android:exported="false" />
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2c64789f2121..16c857894d05 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -346,11 +346,6 @@
<dimen name="notification_text_size">14sp</dimen>
<!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
<dimen name="notification_title_text_size">14sp</dimen>
-
- <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) when colorized -->
- <dimen name="notification_text_size_colorized">16sp</dimen>
- <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) when colorized -->
- <dimen name="notification_title_text_size_colorized">20sp</dimen>
<!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
<dimen name="notification_subtext_size">12sp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c4a45ee11098..1877d421736f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3058,9 +3058,6 @@
<java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
<java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
- <java-symbol type="dimen" name="notification_text_size_colorized" />
- <java-symbol type="dimen" name="notification_title_text_size_colorized" />
-
<java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
<java-symbol type="dimen" name="config_inCallNotificationVolume" />
<java-symbol type="string" name="config_inCallNotificationSound" />
diff --git a/core/tests/coretests/src/android/text/DynamicLayoutTest.java b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
index ed6bfbfa3491..639cefbcf26b 100644
--- a/core/tests/coretests/src/android/text/DynamicLayoutTest.java
+++ b/core/tests/coretests/src/android/text/DynamicLayoutTest.java
@@ -259,4 +259,21 @@ public class DynamicLayoutTest {
assertEquals(2 * textSize, layout.getLineDescent(2));
}
}
+
+ @Test
+ public void testBuilder_defaultTextDirection() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder
+ .obtain("", new TextPaint(), WIDTH);
+ final DynamicLayout layout = builder.build();
+ assertEquals(TextDirectionHeuristics.FIRSTSTRONG_LTR, layout.getTextDirectionHeuristic());
+ }
+
+ @Test
+ public void testBuilder_setTextDirection() {
+ final DynamicLayout.Builder builder = DynamicLayout.Builder
+ .obtain("", new TextPaint(), WIDTH)
+ .setTextDirection(TextDirectionHeuristics.ANYRTL_LTR);
+ final DynamicLayout layout = builder.build();
+ assertEquals(TextDirectionHeuristics.ANYRTL_LTR, layout.getTextDirectionHeuristic());
+ }
}
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index d26437eafa07..ddf9876d3dae 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -20,7 +20,9 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -382,4 +384,19 @@ public class RemoteViewsTest {
RemoteViews.CREATOR.createFromParcel(p);
p.recycle();
}
+
+ @Test
+ public void copyWithBinders() throws Exception {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+ for (int i = 1; i < 10; i++) {
+ PendingIntent pi = PendingIntent.getBroadcast(mContext, 0,
+ new Intent("android.widget.RemoteViewsTest_" + i), PendingIntent.FLAG_ONE_SHOT);
+ views.setOnClickPendingIntent(i, pi);
+ }
+ try {
+ new RemoteViews(views);
+ } catch (Throwable t) {
+ throw new Exception(t);
+ }
+ }
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 7e245309e756..2333feceb1db 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -160,6 +160,9 @@
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
+ <assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
+ <assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
+
<!-- This is a list of all the libraries available for application
code to link against. -->
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index fe427a73bf96..8707ad017f51 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -204,7 +204,6 @@ public class MediaRouter {
audioRoutesChanged = true;
}
- final int mainType = mCurAudioRoutesInfo.mainType;
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -231,8 +230,11 @@ public class MediaRouter {
}
if (audioRoutesChanged) {
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+ if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
+ || mSelectedRoute == mBluetoothA2dpRoute) {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+ }
}
}
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index 2309ec6f1f8d..c2167f3e608d 100644
--- a/packages/SettingsLib/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_two_target.xml
@@ -33,6 +33,7 @@
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:clipToPadding="false"
+ android:layout_marginStart="4dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 9b75c00aeb3a..35ba6ae975d8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -26,7 +26,6 @@ import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -320,6 +319,15 @@ public class TileUtils {
Context context, UserHandle user, Intent intent,
Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon) {
+ getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles,
+ usePriority, checkCategory, forceTintExternalIcon, false /* shouldUpdateTiles */);
+ }
+
+ public static void getTilesForIntent(
+ Context context, UserHandle user, Intent intent,
+ Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles,
+ boolean usePriority, boolean checkCategory, boolean forceTintExternalIcon,
+ boolean shouldUpdateTiles) {
PackageManager pm = context.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
PackageManager.GET_META_DATA, user.getIdentifier());
@@ -357,9 +365,11 @@ public class TileUtils {
updateTileData(context, tile, activityInfo, activityInfo.applicationInfo,
pm, providerMap, forceTintExternalIcon);
if (DEBUG) Log.d(LOG_TAG, "Adding tile " + tile.title);
-
addedCache.put(key, tile);
+ } else if (shouldUpdateTiles) {
+ updateSummaryAndTitle(context, providerMap, tile);
}
+
if (!tile.userHandle.contains(user)) {
tile.userHandle.add(user);
}
@@ -380,7 +390,6 @@ public class TileUtils {
String summary = null;
String keyHint = null;
boolean isIconTintable = false;
- RemoteViews remoteViews = null;
// Get the activity's meta-data
try {
@@ -428,7 +437,8 @@ public class TileUtils {
}
if (metaData.containsKey(META_DATA_PREFERENCE_CUSTOM_VIEW)) {
int layoutId = metaData.getInt(META_DATA_PREFERENCE_CUSTOM_VIEW);
- remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+ tile.remoteViews = new RemoteViews(applicationInfo.packageName, layoutId);
+ updateSummaryAndTitle(context, providerMap, tile);
}
}
} catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
@@ -462,7 +472,6 @@ public class TileUtils {
// Suggest a key for this tile
tile.key = keyHint;
tile.isIconTintable = isIconTintable;
- tile.remoteViews = remoteViews;
return true;
}
@@ -470,6 +479,26 @@ public class TileUtils {
return false;
}
+ private static void updateSummaryAndTitle(
+ Context context, Map<String, IContentProvider> providerMap, Tile tile) {
+ if (tile == null || tile.metaData == null
+ || !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
+ return;
+ }
+
+ String uriString = tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI);
+ Bundle bundle = getBundleFromUri(context, uriString, providerMap);
+ String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
+ String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
+ if (overrideSummary != null) {
+ tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
+ }
+
+ if (overrideTitle != null) {
+ tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
+ }
+ }
+
/**
* Gets the icon package name and resource id from content provider.
* @param context context
@@ -535,37 +564,6 @@ public class TileUtils {
}
}
- public static void updateTileUsingSummaryUri(Context context, final Tile tile) {
- if (tile == null || tile.metaData == null ||
- !tile.metaData.containsKey(META_DATA_PREFERENCE_SUMMARY_URI)) {
- return;
- }
-
- new AsyncTask<Void, Void, Bundle>() {
- @Override
- protected Bundle doInBackground(Void... params) {
- return getBundleFromUri(context,
- tile.metaData.getString(META_DATA_PREFERENCE_SUMMARY_URI), new HashMap<>());
- }
-
- @Override
- protected void onPostExecute(Bundle bundle) {
- if (bundle == null) {
- return;
- }
- final String overrideSummary = getString(bundle, META_DATA_PREFERENCE_SUMMARY);
- final String overrideTitle = getString(bundle, META_DATA_PREFERENCE_TITLE);
-
- if (overrideSummary != null) {
- tile.remoteViews.setTextViewText(android.R.id.summary, overrideSummary);
- }
- if (overrideTitle != null) {
- tile.remoteViews.setTextViewText(android.R.id.title, overrideTitle);
- }
- }
- }.execute();
- }
-
private static String getString(Bundle bundle, String key) {
return bundle == null ? null : bundle.getString(key);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
index 00f32b2839af..56b84415e907 100644
--- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionParser.java
@@ -195,7 +195,7 @@ public class SuggestionParser {
intent.setPackage(category.pkg);
}
TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
- mAddCache, null, suggestions, true, false, false);
+ mAddCache, null, suggestions, true, false, false, true /* shouldUpdateTiles */);
filterSuggestions(suggestions, countBefore, isSmartSuggestionEnabled);
if (!category.multiple && suggestions.size() > (countBefore + 1)) {
// If there are too many, remove them all and only re-add the one with the highest
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index 76f6a20959fb..3e90435b21d7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -22,12 +22,10 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
@@ -66,7 +64,9 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.internal.ShadowExtractor;
import java.util.ArrayList;
import java.util.Collections;
@@ -75,7 +75,8 @@ import java.util.Map;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH,
- sdk = TestConfig.SDK_VERSION)
+ sdk = TestConfig.SDK_VERSION,
+ shadows = {TileUtilsTest.TileUtilsShadowRemoteViews.class})
public class TileUtilsTest {
@Mock
@@ -420,12 +421,24 @@ public class TileUtilsTest {
}
@Test
- public void updateTileUsingSummaryUri_summaryUriSpecified_shouldOverrideRemoteViewSummary()
+ public void getTilesForIntent_summaryUriSpecified_shouldOverrideRemoteViewSummary()
throws RemoteException {
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+ null, URI_GET_SUMMARY);
+ resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+ R.layout.user_preference);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
// Mock the content provider interaction.
Bundle bundle = new Bundle();
- String expectedSummary = "new summary text";
- bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, expectedSummary);
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
when(mIContentProvider.call(anyString(),
eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
any())).thenReturn(bundle);
@@ -434,14 +447,57 @@ public class TileUtilsTest {
when(mContentResolver.acquireUnstableProvider(any(Uri.class)))
.thenReturn(mIContentProvider);
- Tile tile = new Tile();
- tile.metaData = new Bundle();
- tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, URI_GET_SUMMARY);
- tile.remoteViews = mock(RemoteViews.class);
- TileUtils.updateTileUsingSummaryUri(mContext, tile);
- ShadowApplication.runBackgroundTasks();
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */, true /* forceTintExternalIcon */);
- verify(tile.remoteViews, times(1)).setTextViewText(anyInt(), eq(expectedSummary));
+ assertThat(outTiles.size()).isEqualTo(1);
+ Tile tile = outTiles.get(0);
+ assertThat(tile.remoteViews).isNotNull();
+ assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+ // Make sure the summary TextView got a new text string.
+ TileUtilsShadowRemoteViews shadowRemoteViews =
+ (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ assertThat(shadowRemoteViews.overrideViewId).isEqualTo(android.R.id.summary);
+ assertThat(shadowRemoteViews.overrideText).isEqualTo("new summary text");
+ }
+
+ @Test
+ public void getTilesForIntent_providerUnavailable_shouldNotOverrideRemoteViewSummary()
+ throws RemoteException {
+ Intent intent = new Intent();
+ Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>();
+ List<Tile> outTiles = new ArrayList<>();
+ List<ResolveInfo> info = new ArrayList<>();
+ ResolveInfo resolveInfo = newInfo(true, null /* category */, null,
+ null, URI_GET_SUMMARY);
+ resolveInfo.activityInfo.metaData.putInt("com.android.settings.custom_view",
+ R.layout.user_preference);
+ info.add(resolveInfo);
+
+ when(mPackageManager.queryIntentActivitiesAsUser(eq(intent), anyInt(), anyInt()))
+ .thenReturn(info);
+
+ // Mock the content provider interaction.
+ Bundle bundle = new Bundle();
+ bundle.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY, "new summary text");
+ when(mIContentProvider.call(anyString(),
+ eq(TileUtils.getMethodFromUri(Uri.parse(URI_GET_SUMMARY))), eq(URI_GET_SUMMARY),
+ any())).thenReturn(bundle);
+
+ TileUtils.getTilesForIntent(mContext, UserHandle.CURRENT, intent, addedCache,
+ null /* defaultCategory */, outTiles, false /* usePriority */,
+ false /* checkCategory */, true /* forceTintExternalIcon */);
+
+ assertThat(outTiles.size()).isEqualTo(1);
+ Tile tile = outTiles.get(0);
+ assertThat(tile.remoteViews).isNotNull();
+ assertThat(tile.remoteViews.getLayoutId()).isEqualTo(R.layout.user_preference);
+ // Make sure the summary TextView didn't get any text view updates.
+ TileUtilsShadowRemoteViews shadowRemoteViews =
+ (TileUtilsShadowRemoteViews) ShadowExtractor.extract(tile.remoteViews);
+ assertThat(shadowRemoteViews.overrideViewId).isNull();
+ assertThat(shadowRemoteViews.overrideText).isNull();
}
public static ResolveInfo newInfo(boolean systemApp, String category) {
@@ -502,4 +558,16 @@ public class TileUtilsTest {
}
}
+ @Implements(RemoteViews.class)
+ public static class TileUtilsShadowRemoteViews {
+
+ private Integer overrideViewId;
+ private CharSequence overrideText;
+
+ @Implementation
+ public void setTextViewText(int viewId, CharSequence text) {
+ overrideViewId = viewId;
+ overrideText = text;
+ }
+ }
}
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
deleted file mode 100644
index baefdd51ef7c..000000000000
--- a/packages/SystemUI/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-set noparent  # do not inherit owners in parent directories
-
-per-file Android.bp = build.master@android.com  # special file expert
-per-file Android.bp = android-sysui-eng+reviews@google.com
-per-file Android.mk = build.master@android.com  # special file expert
-per-file Android.mk = android-sysui-eng+reviews@google.com
-
-android-sysui-eng+reviews@google.com
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e6a357fc7be8..9901f6ff8fda 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -80,12 +80,6 @@
<!-- Height of a small notification in the status bar which was used before android N -->
<dimen name="notification_min_height_legacy">64dp</dimen>
- <!-- The increase in minHeight that is allowed when the notification is colorized -->
- <dimen name="notification_height_increase_colorized">11sp</dimen>
-
- <!-- The increase in minHeight that is allowed when the notification is colorized and has increased height (i.e messages) -->
- <dimen name="notification_height_increase_colorized_increased">13sp</dimen>
-
<!-- Height of a large notification in the status bar -->
<dimen name="notification_max_height">284dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index b3f992db1b6b..bae9ef8abfba 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -30,6 +30,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pair;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
import android.view.IWindowManager;
@@ -70,11 +71,11 @@ public class PipManager implements BasePipManager {
*/
TaskStackListener mTaskStackListener = new TaskStackListener() {
@Override
- public void onActivityPinned(String packageName, int taskId) {
+ public void onActivityPinned(String packageName, int userId, int taskId) {
mTouchHandler.onActivityPinned();
mMediaController.onActivityPinned();
mMenuController.onActivityPinned();
- mNotificationController.onActivityPinned(packageName,
+ mNotificationController.onActivityPinned(packageName, userId,
true /* deferUntilAnimationEnds */);
SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
@@ -82,13 +83,15 @@ public class PipManager implements BasePipManager {
@Override
public void onActivityUnpinned() {
- ComponentName topPipActivity = PipUtils.getTopPinnedActivity(mContext,
- mActivityManager);
- mMenuController.onActivityUnpinned(topPipActivity);
- mTouchHandler.onActivityUnpinned(topPipActivity);
- mNotificationController.onActivityUnpinned(topPipActivity);
-
- SystemServicesProxy.getInstance(mContext).setPipVisibility(topPipActivity != null);
+ final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity(
+ mContext, mActivityManager);
+ final ComponentName topActivity = topPipActivityInfo.first;
+ final int userId = topActivity != null ? topPipActivityInfo.second : 0;
+ mMenuController.onActivityUnpinned();
+ mTouchHandler.onActivityUnpinned(topActivity);
+ mNotificationController.onActivityUnpinned(topActivity, userId);
+
+ SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index b3a0794f742f..174a7ef19cbd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -230,7 +230,7 @@ public class PipMediaController {
private void resolveActiveMediaController(List<MediaController> controllers) {
if (controllers != null) {
final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext,
- mActivityManager);
+ mActivityManager).first;
if (topActivity != null) {
for (int i = 0; i < controllers.size(); i++) {
final MediaController controller = controllers.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 34666fb30689..68743b34884d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -223,7 +223,7 @@ public class PipMenuActivityController {
}
}
- public void onActivityUnpinned(ComponentName topPipActivity) {
+ public void onActivityUnpinned() {
hideMenu();
setStartActivityRequested(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
index 696fdbc811e7..6d083e9d601d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
@@ -35,10 +35,15 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.graphics.drawable.Icon;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
import android.util.Log;
+import android.util.Pair;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
@@ -57,22 +62,29 @@ public class PipNotificationController {
private IActivityManager mActivityManager;
private AppOpsManager mAppOpsManager;
private NotificationManager mNotificationManager;
+ private IconDrawableFactory mIconDrawableFactory;
private PipMotionHelper mMotionHelper;
// Used when building a deferred notification
private String mDeferredNotificationPackageName;
+ private int mDeferredNotificationUserId;
private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
@Override
public void onOpChanged(String op, String packageName) {
try {
// Dismiss the PiP once the user disables the app ops setting for that package
- final ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(
- packageName, 0);
- if (mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, packageName)
- != MODE_ALLOWED) {
- mMotionHelper.dismissPip();
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+ if (topPipActivityInfo.first != null) {
+ final ApplicationInfo appInfo = mContext.getPackageManager()
+ .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
+ if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
+ mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
+ packageName) != MODE_ALLOWED) {
+ mMotionHelper.dismissPip();
+ }
}
} catch (NameNotFoundException e) {
// Unregister the listener if the package can't be found
@@ -88,16 +100,18 @@ public class PipNotificationController {
mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mNotificationManager = NotificationManager.from(context);
mMotionHelper = motionHelper;
+ mIconDrawableFactory = IconDrawableFactory.newInstance(context);
}
- public void onActivityPinned(String packageName, boolean deferUntilAnimationEnds) {
+ public void onActivityPinned(String packageName, int userId, boolean deferUntilAnimationEnds) {
// Clear any existing notification
mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
if (deferUntilAnimationEnds) {
mDeferredNotificationPackageName = packageName;
+ mDeferredNotificationUserId = userId;
} else {
- showNotificationForApp(mDeferredNotificationPackageName);
+ showNotificationForApp(packageName, userId);
}
// Register for changes to the app ops setting for this package while it is in PiP
@@ -106,22 +120,25 @@ public class PipNotificationController {
public void onPinnedStackAnimationEnded() {
if (mDeferredNotificationPackageName != null) {
- showNotificationForApp(mDeferredNotificationPackageName);
+ showNotificationForApp(mDeferredNotificationPackageName, mDeferredNotificationUserId);
mDeferredNotificationPackageName = null;
+ mDeferredNotificationUserId = 0;
}
}
- public void onActivityUnpinned(ComponentName topPipActivity) {
+ public void onActivityUnpinned(ComponentName topPipActivity, int userId) {
// Unregister for changes to the previously PiP'ed package
unregisterAppOpsListener();
// Reset the deferred notification package
mDeferredNotificationPackageName = null;
+ mDeferredNotificationUserId = 0;
if (topPipActivity != null) {
// onActivityUnpinned() is only called after the transition is complete, so we don't
// need to defer until the animation ends to update the notification
- onActivityPinned(topPipActivity.getPackageName(), false /* deferUntilAnimationEnds */);
+ onActivityPinned(topPipActivity.getPackageName(), userId,
+ false /* deferUntilAnimationEnds */);
} else {
mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
}
@@ -130,20 +147,27 @@ public class PipNotificationController {
/**
* Builds and shows the notification for the given app.
*/
- private void showNotificationForApp(String packageName) {
+ private void showNotificationForApp(String packageName, int userId) {
// Build a new notification
- final Notification.Builder builder =
- new Notification.Builder(mContext, NotificationChannels.GENERAL)
- .setLocalOnly(true)
- .setOngoing(true)
- .setSmallIcon(R.drawable.pip_notification_icon)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
- if (updateNotificationForApp(builder, packageName)) {
- SystemUI.overrideNotificationAppName(mContext, builder);
-
- // Show the new notification
- mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+ try {
+ final UserHandle user = UserHandle.of(userId);
+ final Context userContext = mContext.createPackageContextAsUser(
+ mContext.getPackageName(), 0, user);
+ final Notification.Builder builder =
+ new Notification.Builder(userContext, NotificationChannels.GENERAL)
+ .setLocalOnly(true)
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.pip_notification_icon)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+ if (updateNotificationForApp(builder, packageName, user)) {
+ SystemUI.overrideNotificationAppName(mContext, builder);
+
+ // Show the new notification
+ mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not show notification for application", e);
}
}
@@ -151,33 +175,33 @@ public class PipNotificationController {
* Updates the notification builder with app-specific information, returning whether it was
* successful.
*/
- private boolean updateNotificationForApp(Notification.Builder builder, String packageName) {
+ private boolean updateNotificationForApp(Notification.Builder builder, String packageName,
+ UserHandle user) throws NameNotFoundException {
final PackageManager pm = mContext.getPackageManager();
final ApplicationInfo appInfo;
try {
- appInfo = pm.getApplicationInfo(packageName, 0);
+ appInfo = pm.getApplicationInfoAsUser(packageName, 0, user.getIdentifier());
} catch (NameNotFoundException e) {
Log.e(TAG, "Could not update notification for application", e);
return false;
}
if (appInfo != null) {
- final String appName = pm.getApplicationLabel(appInfo).toString();
+ final String appName = pm.getUserBadgedLabel(pm.getApplicationLabel(appInfo), user)
+ .toString();
final String message = mContext.getString(R.string.pip_notification_message, appName);
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
Uri.fromParts("package", packageName, null));
+ settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- final Icon appIcon = appInfo.icon != 0
- ? Icon.createWithResource(packageName, appInfo.icon)
- : Icon.createWithResource(Resources.getSystem(),
- com.android.internal.R.drawable.sym_def_app_icon);
+ final Drawable iconDrawable = mIconDrawableFactory.getBadgedIcon(appInfo);
builder.setContentTitle(mContext.getString(R.string.pip_notification_title, appName))
.setContentText(message)
- .setContentIntent(PendingIntent.getActivity(mContext, packageName.hashCode(),
- settingsIntent, FLAG_CANCEL_CURRENT))
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, packageName.hashCode(),
+ settingsIntent, FLAG_CANCEL_CURRENT, null, user))
.setStyle(new Notification.BigTextStyle().bigText(message))
- .setLargeIcon(appIcon);
+ .setLargeIcon(createBitmap(iconDrawable).createAshmemBitmap());
return true;
}
return false;
@@ -191,4 +215,17 @@ public class PipNotificationController {
private void unregisterAppOpsListener() {
mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
}
+
+ /**
+ * Bakes a drawable into a bitmap.
+ */
+ private Bitmap createBitmap(Drawable d) {
+ Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+ Config.ARGB_8888);
+ Canvas c = new Canvas(bitmap);
+ d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ d.draw(c);
+ c.setBitmap(null);
+ return bitmap;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index a8cdd1bdb802..56275fd043cf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -24,16 +24,17 @@ import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pair;
public class PipUtils {
private static final String TAG = "PipUtils";
/**
- * @return the ComponentName of the top non-SystemUI activity in the pinned stack, or null if
- * none exists.
+ * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
+ * The component name may be null if no such activity exists.
*/
- public static ComponentName getTopPinnedActivity(Context context,
+ public static Pair<ComponentName, Integer> getTopPinnedActivity(Context context,
IActivityManager activityManager) {
try {
final String sysUiPackageName = context.getPackageName();
@@ -44,13 +45,13 @@ public class PipUtils {
ComponentName cn = ComponentName.unflattenFromString(
pinnedStackInfo.taskNames[i]);
if (cn != null && !cn.getPackageName().equals(sysUiPackageName)) {
- return cn;
+ return new Pair<>(cn, pinnedStackInfo.taskUserIds[i]);
}
}
}
} catch (RemoteException e) {
Log.w(TAG, "Unable to get pinned stack.");
}
- return null;
+ return new Pair<>(null, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index e8c129521010..186de5c4e121 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -654,7 +654,7 @@ public class PipManager implements BasePipManager {
}
@Override
- public void onActivityPinned(String packageName, int taskId) {
+ public void onActivityPinned(String packageName, int userId, int taskId) {
if (DEBUG) Log.d(TAG, "onActivityPinned()");
if (!checkCurrentUserId(mContext, DEBUG)) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
new file mode 100644
index 000000000000..2c7ec70a5fff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/AlphaControlledSignalTileView.java
@@ -0,0 +1,86 @@
+/*
+ * 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.systemui.qs;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import com.android.systemui.qs.tileimpl.SlashImageView;
+
+
+/**
+ * Creates AlphaControlledSlashImageView instead of SlashImageView
+ */
+public class AlphaControlledSignalTileView extends SignalTileView {
+ public AlphaControlledSignalTileView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected SlashImageView createSlashImageView(Context context) {
+ return new AlphaControlledSlashImageView(context);
+ }
+
+ /**
+ * Creates AlphaControlledSlashDrawable instead of regular SlashDrawables
+ */
+ public static class AlphaControlledSlashImageView extends SlashImageView {
+ public AlphaControlledSlashImageView(Context context) {
+ super(context);
+ }
+
+ public void setFinalImageTintList(ColorStateList tint) {
+ super.setImageTintList(tint);
+ final SlashDrawable slash = getSlash();
+ if (slash != null) {
+ ((AlphaControlledSlashDrawable)slash).setFinalTintList(tint);
+ }
+ }
+
+ @Override
+ protected void ensureSlashDrawable() {
+ if (getSlash() == null) {
+ final SlashDrawable slash = new AlphaControlledSlashDrawable(getDrawable());
+ setSlash(slash);
+ slash.setAnimationEnabled(getAnimationEnabled());
+ setImageViewDrawable(slash);
+ }
+ }
+ }
+
+ /**
+ * SlashDrawable that disobeys orders to change its drawable's tint except when you tell
+ * it not to disobey. The slash still will animate its alpha.
+ */
+ public static class AlphaControlledSlashDrawable extends SlashDrawable {
+ AlphaControlledSlashDrawable(Drawable d) {
+ super(d);
+ }
+
+ @Override
+ protected void setDrawableTintList(ColorStateList tint) {
+ }
+
+ /**
+ * Set a target tint list instead of
+ */
+ public void setFinalTintList(ColorStateList tint) {
+ super.setDrawableTintList(tint);
+ }
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index b300e4a35a5a..9ee40ccf8893 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -63,13 +63,17 @@ public class SignalTileView extends QSIconViewImpl {
@Override
protected View createIcon() {
mIconFrame = new FrameLayout(mContext);
- mSignal = new SlashImageView(mContext);
+ mSignal = createSlashImageView(mContext);
mIconFrame.addView(mSignal);
mOverlay = new ImageView(mContext);
mIconFrame.addView(mOverlay, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
return mIconFrame;
}
+ protected SlashImageView createSlashImageView(Context context) {
+ return new SlashImageView(context);
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
index c35614893098..a9b2376e46e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -197,11 +197,15 @@ public class SlashDrawable extends Drawable {
public void setTintList(@Nullable ColorStateList tint) {
mTintList = tint;
super.setTintList(tint);
- mDrawable.setTintList(tint);
+ setDrawableTintList(tint);
mPaint.setColor(tint.getDefaultColor());
invalidateSelf();
}
+ protected void setDrawableTintList(@Nullable ColorStateList tint) {
+ mDrawable.setTintList(tint);
+ }
+
@Override
public void setTintMode(@NonNull Mode tintMode) {
mTintMode = tintMode;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 8074cb9b0443..e8c8b9075792 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -33,6 +33,7 @@ import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView;
import java.util.Objects;
public class QSIconViewImpl extends QSIconView {
@@ -138,7 +139,12 @@ public class QSIconViewImpl extends QSIconView {
animateGrayScale(mTint, color, iv);
mTint = color;
} else {
- setTint(iv, color);
+ if (iv instanceof AlphaControlledSlashImageView) {
+ ((AlphaControlledSlashImageView)iv)
+ .setFinalImageTintList(ColorStateList.valueOf(color));
+ } else {
+ setTint(iv, color);
+ }
mTint = color;
}
}
@@ -149,6 +155,10 @@ public class QSIconViewImpl extends QSIconView {
}
public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+ if (iv instanceof AlphaControlledSlashImageView) {
+ ((AlphaControlledSlashImageView)iv)
+ .setFinalImageTintList(ColorStateList.valueOf(toColor));
+ }
if (ValueAnimator.areAnimatorsEnabled()) {
final float fromAlpha = Color.alpha(fromColor);
final float toAlpha = Color.alpha(toColor);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
index 97e9c3dfd82c..63d6f82ce9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -34,7 +34,15 @@ public class SlashImageView extends ImageView {
super(context);
}
- private void ensureSlashDrawable() {
+ protected SlashDrawable getSlash() {
+ return mSlash;
+ }
+
+ protected void setSlash(SlashDrawable slash) {
+ mSlash = slash;
+ }
+
+ protected void ensureSlashDrawable() {
if (mSlash == null) {
mSlash = new SlashDrawable(getDrawable());
mSlash.setAnimationEnabled(mAnimationEnabled);
@@ -56,10 +64,18 @@ public class SlashImageView extends ImageView {
}
}
+ protected void setImageViewDrawable(SlashDrawable slash) {
+ super.setImageDrawable(slash);
+ }
+
public void setAnimationEnabled(boolean enabled) {
mAnimationEnabled = enabled;
}
+ public boolean getAnimationEnabled() {
+ return mAnimationEnabled;
+ }
+
private void setSlashState(@NonNull SlashState slashState) {
ensureSlashDrawable();
mSlash.setRotation(slashState.rotation);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 33b15121b47e..23702736b0db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -37,10 +37,10 @@ import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.qs.AlphaControlledSignalTileView;
import com.android.systemui.qs.QSDetailItems;
import com.android.systemui.qs.QSDetailItems.Item;
import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.SignalTileView;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
@@ -104,7 +104,7 @@ public class WifiTile extends QSTileImpl<SignalState> {
@Override
public QSIconView createTileView(Context context) {
- return new SignalTileView(context);
+ return new AlphaControlledSignalTileView(context);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index aecf95fc677f..43227ab4f313 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -173,7 +173,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
@Override
- public void onActivityPinned(String packageName, int taskId) {
+ public void onActivityPinned(String packageName, int userId, int taskId) {
// Check this is for the right user
if (!checkCurrentUserId(mContext, false /* debug */)) {
return;
@@ -565,8 +565,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Launch the task
ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
- null /* resultListener */);
+ mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
}
/**
@@ -639,8 +638,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Launch the task
ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, INVALID_STACK_ID,
- null /* resultListener */);
+ mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
}
public void showNextAffiliatedTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
index 3db106e7200f..862a1eee8c39 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -16,6 +16,9 @@
package com.android.systemui.recents.events.activity;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import android.graphics.Rect;
import com.android.systemui.recents.events.EventBus;
@@ -30,15 +33,23 @@ public class LaunchTaskEvent extends EventBus.Event {
public final TaskView taskView;
public final Task task;
public final Rect targetTaskBounds;
- public final int targetTaskStack;
+ public final int targetWindowingMode;
+ public final int targetActivityType;
public final boolean screenPinningRequested;
- public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack,
+ public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds,
boolean screenPinningRequested) {
+ this(taskView, task, targetTaskBounds, screenPinningRequested,
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds,
+ boolean screenPinningRequested, int windowingMode, int activityType) {
this.taskView = taskView;
this.task = task;
this.targetTaskBounds = targetTaskBounds;
- this.targetTaskStack = targetTaskStack;
+ this.targetWindowingMode = windowingMode;
+ this.targetActivityType = activityType;
this.screenPinningRequested = screenPinningRequested;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 717778228989..5a5251e19337 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -23,6 +23,10 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import android.annotation.NonNull;
@@ -172,7 +176,7 @@ public class SystemServicesProxy {
public void onTaskStackChangedBackground() { }
public void onTaskStackChanged() { }
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
- public void onActivityPinned(String packageName, int taskId) { }
+ public void onActivityPinned(String packageName, int userId, int taskId) { }
public void onActivityUnpinned() { }
public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
public void onPinnedStackAnimationStarted() { }
@@ -227,9 +231,10 @@ public class SystemServicesProxy {
}
@Override
- public void onActivityPinned(String packageName, int taskId) throws RemoteException {
+ public void onActivityPinned(String packageName, int userId, int taskId)
+ throws RemoteException {
mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
- mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, taskId, 0, packageName).sendToTarget();
+ mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, userId, taskId, packageName).sendToTarget();
}
@Override
@@ -576,7 +581,7 @@ public class SystemServicesProxy {
try {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
- options.setLaunchStackId(DOCKED_STACK_ID);
+ options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
mIam.startActivityFromRecents(taskId, options.toBundle());
return true;
} catch (Exception e) {
@@ -1120,9 +1125,16 @@ public class SystemServicesProxy {
opts != null ? opts.toBundle() : null, UserHandle.CURRENT));
}
+ public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
+ ActivityOptions options,
+ @Nullable final StartActivityFromRecentsResultListener resultListener) {
+ startActivityFromRecents(context, taskKey, taskName, options,
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener);
+ }
+
/** Starts an activity from recents. */
public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options, int stackId,
+ ActivityOptions options, int windowingMode, int activityType,
@Nullable final StartActivityFromRecentsResultListener resultListener) {
if (mIam == null) {
return;
@@ -1133,12 +1145,14 @@ public class SystemServicesProxy {
if (options == null) {
options = ActivityOptions.makeBasic();
}
- options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID);
- } else if (stackId != INVALID_STACK_ID) {
+ options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ } else if (windowingMode != WINDOWING_MODE_UNDEFINED
+ || activityType != ACTIVITY_TYPE_UNDEFINED) {
if (options == null) {
options = ActivityOptions.makeBasic();
}
- options.setLaunchStackId(stackId);
+ options.setLaunchWindowingMode(windowingMode);
+ options.setLaunchActivityType(activityType);
}
final ActivityOptions finalOptions = options;
@@ -1343,7 +1357,8 @@ public class SystemServicesProxy {
}
case ON_ACTIVITY_PINNED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1);
+ mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1,
+ msg.arg2);
}
break;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index b2675d7ac858..4d3321638e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -21,6 +21,15 @@ import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.Nullable;
import android.app.ActivityManager.StackId;
@@ -107,7 +116,7 @@ public class RecentsTransitionHelper {
*/
public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
final TaskStackView stackView, final TaskView taskView,
- final boolean screenPinningRequested, final int destinationStack) {
+ final boolean screenPinningRequested, final int windowingMode, final int activityType) {
final ActivityOptions.OnAnimationStartedListener animStartedListener;
final AppTransitionAnimationSpecsFuture transitionFuture;
@@ -116,8 +125,8 @@ public class RecentsTransitionHelper {
// Fetch window rect here already in order not to be blocked on lock contention in WM
// when the future calls it.
final Rect windowRect = Recents.getSystemServices().getWindowRect();
- transitionFuture = getAppTransitionFuture(
- () -> composeAnimationSpecs(task, stackView, destinationStack, windowRect));
+ transitionFuture = getAppTransitionFuture(() -> composeAnimationSpecs(
+ task, stackView, windowingMode, activityType, windowRect));
animStartedListener = new OnAnimationStartedListener() {
private boolean mHandled;
@@ -180,7 +189,8 @@ public class RecentsTransitionHelper {
if (taskView == null) {
// If there is no task view, then we do not need to worry about animating out occluding
// task views, and we can launch immediately
- startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
+ startTaskActivity(stack, task, taskView, opts, transitionFuture,
+ windowingMode, activityType);
} else {
LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
screenPinningRequested);
@@ -189,13 +199,14 @@ public class RecentsTransitionHelper {
@Override
public void run() {
startTaskActivity(stack, task, taskView, opts, transitionFuture,
- destinationStack);
+ windowingMode, activityType);
}
});
EventBus.getDefault().send(launchStartedEvent);
} else {
EventBus.getDefault().send(launchStartedEvent);
- startTaskActivity(stack, task, taskView, opts, transitionFuture, destinationStack);
+ startTaskActivity(stack, task, taskView, opts, transitionFuture,
+ windowingMode, activityType);
}
}
Recents.getSystemServices().sendCloseSystemWindows(
@@ -224,13 +235,13 @@ public class RecentsTransitionHelper {
*
* @param taskView this is the {@link TaskView} that we are launching from. This can be null if
* we are toggling recents and the launch-to task is now offscreen.
- * @param destinationStack id of the stack to put the task into.
*/
private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
- int destinationStack) {
+ int windowingMode, int activityType) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(mContext, task.key, task.title, opts, destinationStack,
+ ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode,
+ activityType,
succeeded -> {
if (succeeded) {
// Keep track of the index of the task launch
@@ -310,11 +321,9 @@ public class RecentsTransitionHelper {
* Composes the animation specs for all the tasks in the target stack.
*/
private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
- final TaskStackView stackView, final int destinationStack, Rect windowRect) {
- // Ensure we have a valid target stack id
- final int targetStackId = destinationStack != INVALID_STACK_ID ?
- destinationStack : task.key.stackId;
- if (!StackId.useAnimationSpecForAppTransition(targetStackId)) {
+ final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
+ if (activityType == ACTIVITY_TYPE_RECENTS || activityType == ACTIVITY_TYPE_HOME
+ || windowingMode == WINDOWING_MODE_PINNED) {
return null;
}
@@ -329,9 +338,12 @@ public class RecentsTransitionHelper {
List<AppTransitionAnimationSpec> specs = new ArrayList<>();
// TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
- // check for INVALID_STACK_ID
- if (targetStackId == FULLSCREEN_WORKSPACE_STACK_ID || targetStackId == DOCKED_STACK_ID
- || targetStackId == ASSISTANT_STACK_ID || targetStackId == INVALID_STACK_ID) {
+ // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED)
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ || activityType == ACTIVITY_TYPE_ASSISTANT
+ || windowingMode == WINDOWING_MODE_UNDEFINED) {
if (taskView == null) {
specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
} else {
@@ -353,7 +365,7 @@ public class RecentsTransitionHelper {
int taskCount = tasks.size();
for (int i = taskCount - 1; i >= 0; i--) {
Task t = tasks.get(i);
- if (t.isFreeformTask() || targetStackId == FREEFORM_WORKSPACE_STACK_ID) {
+ if (t.isFreeformTask() || windowingMode == WINDOWING_MODE_FREEFORM) {
TaskView tv = stackView.getChildViewForTask(t);
if (tv == null) {
// TODO: Create a different animation task rect for this case (though it should
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c44cd7287625..fd1b806abf24 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -338,8 +338,7 @@ public class RecentsView extends FrameLayout {
Task task = mTaskStackView.getFocusedTask();
if (task != null) {
TaskView taskView = mTaskStackView.getChildViewForTask(task);
- EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
- INVALID_STACK_ID, false));
+ EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false));
if (logEvent != 0) {
MetricsLogger.action(getContext(), logEvent,
@@ -363,32 +362,13 @@ public class RecentsView extends FrameLayout {
Task task = getStack().getLaunchTarget();
if (task != null) {
TaskView taskView = mTaskStackView.getChildViewForTask(task);
- EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
- INVALID_STACK_ID, false));
+ EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null, false));
return true;
}
}
return false;
}
- /** Launches a given task. */
- public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
- if (mTaskStackView != null) {
- // Iterate the stack views and try and find the given task.
- List<TaskView> taskViews = mTaskStackView.getTaskViews();
- int taskViewCount = taskViews.size();
- for (int j = 0; j < taskViewCount; j++) {
- TaskView tv = taskViews.get(j);
- if (tv.getTask() == task) {
- EventBus.getDefault().send(new LaunchTaskEvent(tv, task, taskBounds,
- destinationStack, false));
- return true;
- }
- }
- }
- return false;
- }
-
/**
* Hides the task stack and shows the empty view.
*/
@@ -570,7 +550,8 @@ public class RecentsView extends FrameLayout {
public final void onBusEvent(LaunchTaskEvent event) {
mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
- event.taskView, event.screenPinningRequested, event.targetTaskStack);
+ event.taskView, event.screenPinningRequested, event.targetWindowingMode,
+ event.targetActivityType);
if (Recents.getConfiguration().isLowRamDevice) {
hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, false /* translate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 8899e307bb16..74e9ef2b3efb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1487,7 +1487,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
Task frontTask = tasks.get(tasks.size() - 1);
if (frontTask != null && frontTask.isFreeformTask()) {
EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
- frontTask, null, INVALID_STACK_ID, false));
+ frontTask, null, false));
return true;
}
}
@@ -2369,12 +2369,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public void run() {
EventBus.getDefault().send(new LaunchTaskEvent(
getChildViewForTask(task), task, null,
- INVALID_STACK_ID, false /* screenPinningRequested */));
+ false /* screenPinningRequested */));
}
});
} else {
- EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task),
- task, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+ EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(task), task, null,
+ false /* screenPinningRequested */));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index ceeebd96a3e1..c64f6dfcea4a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -674,8 +674,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
mActionButtonView.setTranslationZ(0f);
screenPinningRequested = true;
}
- EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
- screenPinningRequested));
+ EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, screenPinningRequested));
MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
mTask.key.getComponent().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index ae922fcc218e..198ecae2d1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -16,6 +16,11 @@
package com.android.systemui.recents.views;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
@@ -57,10 +62,6 @@ import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
/* The task bar view */
public class TaskViewHeader extends FrameLayout
implements View.OnClickListener, View.OnLongClickListener {
@@ -172,7 +173,7 @@ public class TaskViewHeader extends FrameLayout
int mTaskBarViewLightTextColor;
int mTaskBarViewDarkTextColor;
int mDisabledTaskBarBackgroundColor;
- int mMoveTaskTargetStackId = INVALID_STACK_ID;
+ int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED;
// Header background
private HighlightColorDrawable mBackground;
@@ -485,12 +486,12 @@ public class TaskViewHeader extends FrameLayout
// current task
if (mMoveTaskButton != null) {
if (t.isFreeformTask()) {
- mMoveTaskTargetStackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ mTaskWindowingMode = WINDOWING_MODE_FULLSCREEN;
mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
? mLightFullscreenIcon
: mDarkFullscreenIcon);
} else {
- mMoveTaskTargetStackId = FREEFORM_WORKSPACE_STACK_ID;
+ mTaskWindowingMode = WINDOWING_MODE_FREEFORM;
mMoveTaskButton.setImageDrawable(t.useLightOnPrimaryColor
? mLightFreeformIcon
: mDarkFreeformIcon);
@@ -621,8 +622,8 @@ public class TaskViewHeader extends FrameLayout
Constants.Metrics.DismissSourceHeaderButton);
} else if (v == mMoveTaskButton) {
TaskView tv = Utilities.findParent(this, TaskView.class);
- EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null,
- mMoveTaskTargetStackId, false));
+ EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null, false,
+ mTaskWindowingMode, ACTIVITY_TYPE_UNDEFINED));
} else if (v == mAppInfoView) {
EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
} else if (v == mAppIconView) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 6bfef20c9f53..44e60eed8c7c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -93,7 +93,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private static final int LOG_VALUE_UNDOCK_MAX_OTHER = 1;
private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
- private static final boolean SWAPPING_ENABLED = false;
/**
* How much the background gets scaled when we are in the minimized dock state.
@@ -153,7 +152,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private boolean mEntranceAnimationRunning;
private boolean mExitAnimationRunning;
private int mExitStartPosition;
- private GestureDetector mGestureDetector;
private boolean mDockedStackMinimized;
private boolean mHomeStackResizable;
private boolean mAdjustedForIme;
@@ -295,21 +293,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
landscape ? TYPE_HORIZONTAL_DOUBLE_ARROW : TYPE_VERTICAL_DOUBLE_ARROW));
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
mHandle.setAccessibilityDelegate(mHandleDelegate);
- mGestureDetector = new GestureDetector(mContext, new SimpleOnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- if (SWAPPING_ENABLED) {
- updateDockSide();
- SystemServicesProxy ssp = Recents.getSystemServices();
- if (mDockSide != WindowManager.DOCKED_INVALID
- && !ssp.isRecentsActivityVisible()) {
- mWindowManagerProxy.swapTasks();
- return true;
- }
- }
- return false;
- }
- });
}
@Override
@@ -478,7 +461,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
@Override
public boolean onTouch(View v, MotionEvent event) {
convertToScreenCoordinates(event);
- mGestureDetector.onTouchEvent(event);
final int action = event.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index c24512649c2f..185f6e369f76 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -120,17 +120,6 @@ public class WindowManagerProxy {
}
};
- private final Runnable mSwapRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- ActivityManager.getService().swapDockedAndFullscreenStack();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to resize stack: " + e);
- }
- }
- };
-
private final Runnable mSetTouchableRegionRunnable = new Runnable() {
@Override
public void run() {
@@ -218,10 +207,6 @@ public class WindowManagerProxy {
mExecutor.execute(mDimLayerRunnable);
}
- public void swapTasks() {
- mExecutor.execute(mSwapRunnable);
- }
-
public void setTouchRegion(Rect region) {
synchronized (mDockedRect) {
mTouchableRegion.set(region);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8fa904e10b4a..966e78997244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -64,10 +64,10 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.NotificationGuts.GutsContent;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
+import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -436,9 +436,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
minHeight = mNotificationMinHeight;
}
- NotificationViewWrapper collapsedWrapper = layout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_CONTRACTED);
- minHeight += collapsedWrapper.getMinHeightIncrease(mUseIncreasedCollapsedHeight);
boolean headsUpCustom = layout.getHeadsUpChild() != null &&
layout.getHeadsUpChild().getId()
!= com.android.internal.R.id.status_bar_latest_event_content;
@@ -450,11 +447,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
headsUpheight = mMaxHeadsUpHeight;
}
- NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
- NotificationContentView.VISIBLE_TYPE_HEADSUP);
- if (headsUpWrapper != null) {
- headsUpheight += headsUpWrapper.getMinHeightIncrease(mUseIncreasedCollapsedHeight);
- }
layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
mNotificationAmbientHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 7e08d5605f40..9d2d71e28e5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -15,6 +15,12 @@
*/
package com.android.systemui.statusbar.car;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.Intent;
@@ -117,7 +123,8 @@ class CarNavigationBarController {
// Set up the persistent docked task if needed.
if (mPersistentTaskIntent != null && !mStatusBar.hasDockedTask()
&& stackId != StackId.HOME_STACK_ID) {
- mStatusBar.startActivityOnStack(mPersistentTaskIntent, StackId.DOCKED_STACK_ID);
+ mStatusBar.startActivityOnStack(mPersistentTaskIntent,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_UNDEFINED);
}
}
@@ -375,13 +382,15 @@ class CarNavigationBarController {
// rather than the "preferred/last run" app.
intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
- int stackId = StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+ int windowingMode = WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
+ int activityType = ACTIVITY_TYPE_UNDEFINED;
if (intent.getCategories().contains(Intent.CATEGORY_HOME)) {
- stackId = StackId.HOME_STACK_ID;
+ windowingMode = WINDOWING_MODE_UNDEFINED;
+ activityType = ACTIVITY_TYPE_HOME;
}
setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent, stackId);
+ mStatusBar.startActivityOnStack(intent, windowingMode, activityType);
}
/**
@@ -391,6 +400,7 @@ class CarNavigationBarController {
*/
private void onFacetLongClicked(Intent intent, int index) {
setCurrentFacet(index);
- mStatusBar.startActivityOnStack(intent, StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ mStatusBar.startActivityOnStack(intent,
+ WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_UNDEFINED);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 680f693a83f8..10fc496fcfd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -378,9 +378,10 @@ public class CarStatusBar extends StatusBar implements
return result;
}
- public int startActivityOnStack(Intent intent, int stackId) {
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(stackId);
+ public int startActivityOnStack(Intent intent, int windowingMode, int activityType) {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(windowingMode);
+ options.setLaunchActivityType(activityType);
return startActivityWithOptions(intent, options.toBundle());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 9bfa7a9752a8..bb979ebd1288 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -25,7 +25,6 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
@@ -48,7 +47,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
private int mContentHeight;
private int mMinHeightHint;
- private boolean mColorized;
protected NotificationTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
@@ -164,9 +162,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
public void onContentUpdated(ExpandableNotificationRow row) {
// Reinspect the notification. Before the super call, because the super call also updates
// the transformation types and we need to have our values set by then.
- StatusBarNotification sbn = row.getStatusBarNotification();
- resolveTemplateViews(sbn);
- mColorized = sbn.getNotification().isColorized();
+ resolveTemplateViews(row.getStatusBarNotification());
super.onContentUpdated(row);
}
@@ -269,17 +265,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
updateActionOffset();
}
- @Override
- public int getMinHeightIncrease(boolean useIncreasedCollapsedHeight) {
- if (mColorized) {
- int dimen = useIncreasedCollapsedHeight
- ? R.dimen.notification_height_increase_colorized_increased
- : R.dimen.notification_height_increase_colorized;
- return mRow.getResources().getDimensionPixelSize(dimen);
- }
- return super.getMinHeightIncrease(useIncreasedCollapsedHeight);
- }
-
private void updateActionOffset() {
if (mActionsContainer != null) {
// We should never push the actions higher than they are in the headsup view.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 085bce971ffc..5200d6962ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -190,14 +190,4 @@ public abstract class NotificationViewWrapper implements TransformableView {
public boolean disallowSingleClick(float x, float y) {
return false;
}
-
- /**
- * Get the amount that the minheight is allowed to be increased based on this layout.
- *
- * @param increasedHeight is the view allowed to show even bigger, i.e for messaging layouts
- * @return
- */
- public int getMinHeightIncrease(boolean increasedHeight) {
- return 0;
- }
}
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 200cada972a7..4739a2eed6de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -20,6 +20,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
@@ -37,7 +38,6 @@ import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackId;
import android.app.ActivityOptions;
import android.app.INotificationManager;
import android.app.KeyguardManager;
@@ -1057,6 +1057,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationData.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
+ putComponent(HeadsUpManager.class, mHeadsUpManager);
if (MULTIUSER_DEBUG) {
mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
@@ -5931,7 +5932,7 @@ public class StatusBar extends SystemUI implements DemoMode,
private boolean superOnClickHandler(View view, PendingIntent pendingIntent,
Intent fillInIntent) {
return super.onClickHandler(view, pendingIntent, fillInIntent,
- StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
}
private boolean handleRemoteInput(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -7148,10 +7149,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
protected Bundle getActivityOptions() {
- // Anything launched from the notification shade should always go into the
- // fullscreen stack.
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+ // Anything launched from the notification shade should always go into the secondary
+ // split-screen windowing mode.
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
return options.toBundle();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index a3aca6e1b649..7bb987ca7cf0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -524,18 +524,17 @@ public class ZenModePanel extends FrameLayout {
bindGenericCountdown();
bindNextAlarm(getTimeUntilNextAlarmCondition());
} else if (isForever(c)) {
+
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
bindGenericCountdown();
bindNextAlarm(getTimeUntilNextAlarmCondition());
} else {
if (isAlarm(c)) {
bindGenericCountdown();
-
bindNextAlarm(c);
getConditionTagAt(COUNTDOWN_ALARM_CONDITION_INDEX).rb.setChecked(true);
} else if (isCountdown(c)) {
bindNextAlarm(getTimeUntilNextAlarmCondition());
-
bind(c, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
COUNTDOWN_CONDITION_INDEX);
getConditionTagAt(COUNTDOWN_CONDITION_INDEX).rb.setChecked(true);
@@ -568,8 +567,8 @@ public class ZenModePanel extends FrameLayout {
tag = (ConditionTag) alarmContent.getTag();
boolean showAlarm = tag != null && tag.condition != null;
mZenRadioGroup.getChildAt(COUNTDOWN_ALARM_CONDITION_INDEX).setVisibility(
- showAlarm ? View.VISIBLE : View.GONE);
- alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.GONE);
+ showAlarm ? View.VISIBLE : View.INVISIBLE);
+ alarmContent.setVisibility(showAlarm ? View.VISIBLE : View.INVISIBLE);
}
private Condition forever() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java
new file mode 100644
index 000000000000..3e677c01fd57
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/AlphaControlledSignalTileViewTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.systemui.qs;
+
+
+import static org.junit.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashDrawable;
+import com.android.systemui.qs.AlphaControlledSignalTileView.AlphaControlledSlashImageView;
+import org.junit.Test;
+
+@SmallTest
+public class AlphaControlledSignalTileViewTest extends SysuiTestCase {
+
+ private AlphaControlledSignalTileView mTileView;
+
+ @Test
+ public void testTileView_createsAlphaControlledSlashImageView() {
+ mTileView = new AlphaControlledSignalTileView(mContext);
+
+ assertTrue(mTileView.createSlashImageView(mContext)
+ instanceof AlphaControlledSlashImageView);
+ }
+
+ /// AlphaControlledSlashImageView tests
+ @Test
+ public void testSlashImageView_createsAlphaControlledSlashDrawable() {
+ TestableSlashImageView iv = new TestableSlashImageView(mContext);
+
+ iv.ensureSlashDrawable();
+ assertTrue(iv.getSlashDrawable() instanceof AlphaControlledSlashDrawable);
+ }
+
+ /// AlphaControlledSlashDrawable tests
+ @Test
+ public void testSlashDrawable_doesNotSetTintList() {
+ Drawable mockDrawable = mock(Drawable.class);
+ AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable);
+ ColorStateList list = ColorStateList.valueOf(0xffffff);
+ drawable.setTintList(list);
+ verify(mockDrawable, never()).setTintList(any());
+ }
+
+ @Test
+ public void testSlashDrawable_setsFinalTintList() {
+ Drawable mockDrawable = mock(Drawable.class);
+ AlphaControlledSlashDrawable drawable = new AlphaControlledSlashDrawable(mockDrawable);
+ ColorStateList list = ColorStateList.valueOf(0xffffff);
+ drawable.setFinalTintList(list);
+ verify(mockDrawable, atLeastOnce()).setTintList(list);
+ }
+
+ // Expose getSlashDrawable
+ private static class TestableSlashImageView extends AlphaControlledSlashImageView {
+ TestableSlashImageView(Context c) {
+ super(c);
+ }
+
+ private SlashDrawable getSlashDrawable() {
+ return mSlash;
+ }
+
+ @Override
+ protected void setSlash(SlashDrawable slash) {
+ super.setSlash(slash);
+ }
+ }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 07302706d134..523e6b2a7b63 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4610,6 +4610,11 @@ message MetricsEvent {
// OS: P
DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1158;
+ // OPEN: Settings > Developer options > OEM unlocking > Info dialog
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_ENABLE_OEM_UNLOCKING = 1159;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a1c75bfc16c0..b9bea163a8a5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -120,6 +120,18 @@ public final class AutofillManagerService extends SystemService {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+ if (sDebug) Slog.d(TAG, "Close system dialogs");
+
+ // TODO(b/64940307): we need to destroy all sessions that are finished but showing
+ // Save UI because there is no way to show the Save UI back when the activity
+ // beneath it is brought back to top. Ideally, we should just hide the UI and
+ // bring it back when the activity resumes.
+ synchronized (mLock) {
+ for (int i = 0; i < mServicesCache.size(); i++) {
+ mServicesCache.valueAt(i).destroyFinishedSessionsLocked();
+ }
+ }
+
mUi.hideAll(null);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 77ce87171a4b..59022e3ff14e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -452,7 +452,7 @@ final class AutofillManagerServiceImpl {
final int sessionCount = mSessions.size();
for (int i = sessionCount - 1; i >= 0; i--) {
final Session session = mSessions.valueAt(i);
- if (session.isSaveUiPendingForToken(token)) {
+ if (session.isSaveUiPendingForTokenLocked(token)) {
session.onPendingSaveUi(operation, token);
return;
}
@@ -638,7 +638,7 @@ final class AutofillManagerServiceImpl {
void destroySessionsLocked() {
if (mSessions.size() == 0) {
- mUi.destroyAll(null, null);
+ mUi.destroyAll(null, null, false);
return;
}
while (mSessions.size() > 0) {
@@ -646,6 +646,18 @@ final class AutofillManagerServiceImpl {
}
}
+ // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
+ void destroyFinishedSessionsLocked() {
+ final int sessionCount = mSessions.size();
+ for (int i = sessionCount - 1; i >= 0; i--) {
+ final Session session = mSessions.valueAt(i);
+ if (session.isSavingLocked()) {
+ if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
+ session.forceRemoveSelfLocked();
+ }
+ }
+ }
+
void listSessionsLocked(ArrayList<String> output) {
final int numSessions = mSessions.size();
for (int i = 0; i < numSessions; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f315148547e9..af55807ff1f0 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -578,9 +578,8 @@ final class RemoteFillService implements DeathRecipient {
public void run() {
synchronized (mLock) {
if (isCancelledLocked()) {
- // TODO(b/653742740): we should probably return here, but for now we're justing
- // logging to confirm this is the problem if it happens again.
- Slog.e(LOG_TAG, "run() called after canceled: " + mRequest);
+ if (sDebug) Slog.d(LOG_TAG, "run() called after canceled: " + mRequest);
+ return;
}
}
final RemoteFillService remoteService = getService();
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 09ecdd534da9..f81ecf247ac7 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -471,7 +471,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if ((response.getDatasets() == null || response.getDatasets().isEmpty())
&& response.getAuthentication() == null) {
// Response is "empty" from an UI point of view, need to notify client.
- notifyUnavailableToClient();
+ notifyUnavailableToClient(false);
}
synchronized (mLock) {
processResponseLocked(response, requestFlags);
@@ -572,6 +572,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// FillServiceCallbacks
@Override
public void authenticate(int requestId, int datasetIndex, IntentSender intent, Bundle extras) {
+ if (sDebug) {
+ Slog.d(TAG, "authenticate(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+ + "; intentSender=" + intent);
+ }
final Intent fillInIntent;
synchronized (mLock) {
if (mDestroyed) {
@@ -580,6 +584,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
return;
}
fillInIntent = createAuthFillInIntentLocked(requestId, extras);
+ if (fillInIntent == null) {
+ forceRemoveSelfLocked();
+ return;
+ }
}
mService.setAuthenticationSelected(id, mClientState);
@@ -1361,11 +1369,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
- private void notifyUnavailableToClient() {
+ private void notifyUnavailableToClient(boolean sessionFinished) {
synchronized (mLock) {
- if (!mHasCallback || mCurrentViewId == null) return;
+ if (mCurrentViewId == null) return;
try {
- mClient.notifyNoFillUi(id, mCurrentViewId);
+ if (mHasCallback) {
+ mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinished);
+ } else if (sessionFinished) {
+ mClient.setSessionFinished(AutofillManager.STATE_FINISHED);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
}
@@ -1453,7 +1465,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
mService.resetLastResponse();
// Nothing to be done, but need to notify client.
- notifyUnavailableToClient();
+ notifyUnavailableToClient(true);
removeSelf();
}
@@ -1572,6 +1584,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
void autoFill(int requestId, int datasetIndex, Dataset dataset, boolean generateEvent) {
+ if (sDebug) {
+ Slog.d(TAG, "autoFill(): requestId=" + requestId + "; datasetIdx=" + datasetIndex
+ + "; dataset=" + dataset);
+ }
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#autoFill() rejected - session: "
@@ -1592,10 +1608,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState);
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState);
-
+ if (fillInIntent == null) {
+ forceRemoveSelfLocked();
+ return;
+ }
final int authenticationId = AutofillManager.makeAuthenticationId(requestId,
datasetIndex);
startAuthentication(authenticationId, dataset.getAuthentication(), fillInIntent);
+
}
}
@@ -1605,14 +1625,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
}
+ // TODO: this should never be null, but we got at least one occurrence, probably due to a race.
+ @Nullable
private Intent createAuthFillInIntentLocked(int requestId, Bundle extras) {
final Intent fillInIntent = new Intent();
final FillContext context = getFillContextByRequestIdLocked(requestId);
if (context == null) {
- // TODO(b/653742740): this will crash system_server. We need to handle it, but we're
- // keeping it crashing for now so we can diagnose when it happens again
- Slog.wtf(TAG, "no FillContext for requestId" + requestId + "; mContexts= " + mContexts);
+ Slog.wtf(TAG, "createAuthFillInIntentLocked(): no FillContext. requestId=" + requestId
+ + "; mContexts= " + mContexts);
+ return null;
}
fillInIntent.putExtra(AutofillManager.EXTRA_ASSIST_STRUCTURE, context.getStructure());
fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE, extras);
@@ -1759,7 +1781,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (mDestroyed) {
return null;
}
- mUi.destroyAll(mPendingSaveUi, this);
+ mUi.destroyAll(mPendingSaveUi, this, true);
mUi.clearCallback(this);
mDestroyed = true;
writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
@@ -1773,9 +1795,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
void forceRemoveSelfLocked() {
if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
+ final boolean isPendingSaveUi = isSaveUiPendingLocked();
mPendingSaveUi = null;
removeSelfLocked();
- mUi.destroyAll(mPendingSaveUi, this);
+ mUi.destroyAll(mPendingSaveUi, this, false);
+ if (!isPendingSaveUi) {
+ try {
+ mClient.setSessionFinished(AutofillManager.STATE_UNKNOWN);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error notifying client to finish session", e);
+ }
+ }
}
/**
@@ -1798,7 +1828,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
+ id + " destroyed");
return;
}
- if (isSaveUiPending()) {
+ if (isSaveUiPendingLocked()) {
Slog.i(TAG, "removeSelfLocked() ignored, waiting for pending save ui");
return;
}
@@ -1819,14 +1849,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
* a specific {@code token} created by
* {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}.
*/
- boolean isSaveUiPendingForToken(@NonNull IBinder token) {
- return isSaveUiPending() && token.equals(mPendingSaveUi.getToken());
+ boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) {
+ return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken());
}
/**
* Checks whether this session is hiding the Save UI to handle a custom description link.
*/
- private boolean isSaveUiPending() {
+ private boolean isSaveUiPendingLocked() {
return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 434b590d2d12..36b95fc02ed8 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -275,7 +275,7 @@ public final class AutoFillUI {
if (mCallback != null) {
mCallback.save();
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
@Override
@@ -293,7 +293,7 @@ public final class AutoFillUI {
if (mCallback != null) {
mCallback.cancelSave();
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
@Override
@@ -335,8 +335,8 @@ public final class AutoFillUI {
* Destroy all UI affordances.
*/
public void destroyAll(@Nullable PendingUi pendingSaveUi,
- @Nullable AutoFillUiCallback callback) {
- mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback));
+ @Nullable AutoFillUiCallback callback, boolean notifyClient) {
+ mHandler.post(() -> destroyAllUiThread(pendingSaveUi, callback, notifyClient));
}
public void dump(PrintWriter pw) {
@@ -379,7 +379,7 @@ public final class AutoFillUI {
}
@android.annotation.UiThread
- private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi) {
+ private void destroySaveUiUiThread(@Nullable PendingUi pendingSaveUi, boolean notifyClient) {
if (mSaveUi == null) {
// Calling destroySaveUiUiThread() twice is normal - it usually happens when the
// first call is made after the SaveUI is hidden and the second when the session is
@@ -391,7 +391,7 @@ public final class AutoFillUI {
if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): " + pendingSaveUi);
mSaveUi.destroy();
mSaveUi = null;
- if (pendingSaveUi != null) {
+ if (pendingSaveUi != null && notifyClient) {
try {
if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
@@ -403,9 +403,9 @@ public final class AutoFillUI {
@android.annotation.UiThread
private void destroyAllUiThread(@Nullable PendingUi pendingSaveUi,
- @Nullable AutoFillUiCallback callback) {
+ @Nullable AutoFillUiCallback callback, boolean notifyClient) {
hideFillUiUiThread(callback);
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, notifyClient);
}
@android.annotation.UiThread
@@ -417,7 +417,7 @@ public final class AutoFillUI {
Slog.d(TAG, "hideAllUiThread(): "
+ "destroying Save UI because pending restoration is finished");
}
- destroySaveUiUiThread(pendingSaveUi);
+ destroySaveUiUiThread(pendingSaveUi, true);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 32f4d69fc3e3..cd9bdb7205b1 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -263,9 +263,7 @@ final class SaveUi {
} else {
noButton.setText(R.string.autofill_save_no);
}
- final View.OnClickListener cancelListener =
- (v) -> mListener.onCancel(info.getNegativeActionListener());
- noButton.setOnClickListener(cancelListener);
+ noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener()));
final View yesButton = view.findViewById(R.id.autofill_save_yes);
yesButton.setOnClickListener((v) -> mListener.onSave());
@@ -273,9 +271,6 @@ final class SaveUi {
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
mDialog.setContentView(view);
- // Dialog can be dismissed when touched outside.
- mDialog.setOnDismissListener((d) -> mListener.onCancel(info.getNegativeActionListener()));
-
final Window window = mDialog.getWindow();
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -305,7 +300,7 @@ final class SaveUi {
if (actualWidth <= maxWidth && actualHeight <= maxHeight) {
if (sDebug) {
- Slog.d(TAG, "Addingservice icon "
+ Slog.d(TAG, "Adding service icon "
+ "(" + actualWidth + "x" + actualHeight + ") as it's less than maximum "
+ "(" + maxWidth + "x" + maxHeight + ").");
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bfe50404a26a..3ac6f2e847f6 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -128,7 +128,6 @@ import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.MockableSystemProperties;
-import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor;
@@ -2205,7 +2204,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// A network factory has connected. Send it all current NetworkRequests.
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.isListen()) continue;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
(nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
}
@@ -2282,9 +2281,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
- NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
+ NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- mNetworkForRequestId.remove(request.requestId);
+ clearNetworkForRequest(request.requestId);
sendUpdatedScoreToFactories(request, 0);
}
}
@@ -2360,7 +2359,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
rematchAllNetworksAndRequests(null, 0);
- if (nri.request.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) {
+ if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
sendUpdatedScoreToFactories(nri.request, 0);
}
}
@@ -2415,7 +2414,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 2. Unvalidated WiFi will not be reaped when validated cellular
// is currently satisfying the request. This is desirable when
// WiFi ends up validating and out scoring cellular.
- mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
+ getNetworkForRequest(nri.request.requestId).getCurrentScore() <
nai.getCurrentScoreAsValidated())) {
return false;
}
@@ -2442,7 +2441,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (mNetworkRequests.get(nri.request) == null) {
return;
}
- if (mNetworkForRequestId.get(nri.request.requestId) != null) {
+ if (getNetworkForRequest(nri.request.requestId) != null) {
return;
}
if (VDBG || (DBG && nri.request.isRequest())) {
@@ -2482,7 +2481,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
boolean wasKept = false;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+ NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
if (nai != null) {
boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
nai.removeRequest(nri.request.requestId);
@@ -2499,7 +2498,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
wasKept = true;
}
- mNetworkForRequestId.remove(nri.request.requestId);
+ clearNetworkForRequest(nri.request.requestId);
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
// Went from foreground to background.
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -4296,7 +4295,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
* and the are the highest scored network available.
* the are keyed off the Requests requestId.
*/
- // TODO: Yikes, this is accessed on multiple threads: add synchronization.
+ // NOTE: Accessed on multiple threads, must be synchronized on itself.
+ @GuardedBy("mNetworkForRequestId")
private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
new SparseArray<NetworkAgentInfo>();
@@ -4326,8 +4326,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
// priority networks like Wi-Fi are active.
private final NetworkRequest mDefaultMobileDataRequest;
+ private NetworkAgentInfo getNetworkForRequest(int requestId) {
+ synchronized (mNetworkForRequestId) {
+ return mNetworkForRequestId.get(requestId);
+ }
+ }
+
+ private void clearNetworkForRequest(int requestId) {
+ synchronized (mNetworkForRequestId) {
+ mNetworkForRequestId.remove(requestId);
+ }
+ }
+
+ private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
+ synchronized (mNetworkForRequestId) {
+ mNetworkForRequestId.put(requestId, nai);
+ }
+ }
+
private NetworkAgentInfo getDefaultNetwork() {
- return mNetworkForRequestId.get(mDefaultRequest.requestId);
+ return getNetworkForRequest(mDefaultRequest.requestId);
}
private boolean isDefaultNetwork(NetworkAgentInfo nai) {
@@ -4881,7 +4899,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// requests or not, and doesn't affect the network's score.
if (nri.request.isListen()) continue;
- final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+ final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
final boolean satisfies = newNetwork.satisfies(nri.request);
if (newNetwork == currentNetwork && satisfies) {
if (VDBG) {
@@ -4913,7 +4931,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG) log(" accepting network in place of null");
}
newNetwork.unlingerRequest(nri.request);
- mNetworkForRequestId.put(nri.request.requestId, newNetwork);
+ setNetworkForRequest(nri.request.requestId, newNetwork);
if (!newNetwork.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
}
@@ -4947,7 +4965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
newNetwork.removeRequest(nri.request.requestId);
if (currentNetwork == newNetwork) {
- mNetworkForRequestId.remove(nri.request.requestId);
+ clearNetworkForRequest(nri.request.requestId);
sendUpdatedScoreToFactories(nri.request, 0);
} else {
Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 8ae592f7978a..98e08e09049b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -5285,7 +5285,7 @@ public class AccountManagerService
== PackageManager.PERMISSION_GRANTED) {
// Checks runtime permission revocation.
final int opCode = AppOpsManager.permissionToOpCode(perm);
- if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+ if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
opCode, uid, packageName) == AppOpsManager.MODE_ALLOWED) {
return true;
}
@@ -5306,7 +5306,7 @@ public class AccountManagerService
Log.v(TAG, " caller uid " + callingUid + " has " + perm);
}
final int opCode = AppOpsManager.permissionToOpCode(perm);
- if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+ if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOpNoThrow(
opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d516d696ff84..12778d82d387 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -145,7 +145,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKSCREEN;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
@@ -163,7 +162,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
@@ -177,6 +175,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.am.proto.ActivityManagerServiceProto.ACTIVITIES;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_RELAUNCH;
import static com.android.server.wm.AppTransition.TRANSIT_NONE;
@@ -349,6 +348,7 @@ import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -402,6 +402,7 @@ import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
+import com.android.server.utils.PriorityDump;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
@@ -707,6 +708,42 @@ public class ActivityManagerService extends IActivityManager.Stub
@VisibleForTesting
long mWaitForNetworkTimeoutMs;
+ /**
+ * Helper class which parses out priority arguments and dumps sections according to their
+ * priority. If priority arguments are omitted, function calls the legacy dump command.
+ */
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, new String[] {"activities"});
+ }
+
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, new String[] {"settings"});
+ doDump(fd, pw, new String[] {"intents"});
+ doDump(fd, pw, new String[] {"broadcasts"});
+ doDump(fd, pw, new String[] {"providers"});
+ doDump(fd, pw, new String[] {"permissions"});
+ doDump(fd, pw, new String[] {"services"});
+ doDump(fd, pw, new String[] {"recents"});
+ doDump(fd, pw, new String[] {"lastanr"});
+ doDump(fd, pw, new String[] {"starter"});
+ if (mAssociations.size() > 0) {
+ doDump(fd, pw, new String[] {"associations"});
+ }
+ doDump(fd, pw, new String[] {"processes"});
+ doDump(fd, pw, new String[] {"-v", "all"});
+ doDump(fd, pw, new String[] {"service", "all"});
+ doDump(fd, pw, new String[] {"provider", "all"});
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, args);
+ }
+ };
+
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown
&& !mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)
@@ -2503,6 +2540,14 @@ public class ActivityManagerService extends IActivityManager.Stub
static class MemBinder extends Binder {
ActivityManagerService mActivityManagerService;
+ private final PriorityDump.PriorityDumper mPriorityDumper =
+ new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
+ }
+ };
+
MemBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@@ -2511,7 +2556,7 @@ public class ActivityManagerService extends IActivityManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
"meminfo", pw)) return;
- mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, " ", args, false, null);
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
}
@@ -2545,19 +2590,27 @@ public class ActivityManagerService extends IActivityManager.Stub
static class CpuBinder extends Binder {
ActivityManagerService mActivityManagerService;
+ private final PriorityDump.PriorityDumper mPriorityDumper =
+ new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
+ "cpuinfo", pw)) return;
+ synchronized (mActivityManagerService.mProcessCpuTracker) {
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
+ pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
+ SystemClock.uptimeMillis()));
+ }
+ }
+ };
+
CpuBinder(ActivityManagerService activityManagerService) {
mActivityManagerService = activityManagerService;
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
- "cpuinfo", pw)) return;
- synchronized (mActivityManagerService.mProcessCpuTracker) {
- pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentLoad());
- pw.print(mActivityManagerService.mProcessCpuTracker.printCurrentState(
- SystemClock.uptimeMillis()));
- }
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
}
}
@@ -9957,7 +10010,7 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
"getTaskDescription()");
final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
return tr.lastTaskDescription;
}
@@ -10070,7 +10123,7 @@ public class ActivityManagerService extends IActivityManager.Stub
public void setTaskResizeable(int taskId, int resizeableMode) {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(
- taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+ taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
return;
@@ -10133,7 +10186,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
return rect;
@@ -10165,7 +10218,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
- MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+ MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
return;
@@ -10184,7 +10237,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
synchronized (this) {
final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId,
- MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+ MATCH_TASK_IN_STACKS_ONLY);
if (task == null) {
Slog.w(TAG, "cancelTaskThumbnailTransition: taskId=" + taskId + " not found");
return;
@@ -10204,7 +10257,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final TaskRecord task;
synchronized (this) {
task = mStackSupervisor.anyTaskForIdLocked(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (task == null) {
Slog.w(TAG, "getTaskSnapshot: taskId=" + taskId + " not found");
return null;
@@ -10518,56 +10571,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- @Override
- public void swapDockedAndFullscreenStack() throws RemoteException {
- enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "swapDockedAndFullscreenStack()");
- synchronized (this) {
- long ident = Binder.clearCallingIdentity();
- try {
- final ActivityStack fullscreenStack = mStackSupervisor.getStack(
- FULLSCREEN_WORKSPACE_STACK_ID);
- final TaskRecord topTask = fullscreenStack != null ? fullscreenStack.topTask()
- : null;
- final ActivityStack dockedStack = mStackSupervisor.getStack(DOCKED_STACK_ID);
- final ArrayList<TaskRecord> tasks = dockedStack != null ? dockedStack.getAllTasks()
- : null;
- if (topTask == null || tasks == null || tasks.size() == 0) {
- Slog.w(TAG,
- "Unable to swap tasks, either docked or fullscreen stack is empty.");
- return;
- }
-
- // TODO: App transition
- mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_RELAUNCH, false);
-
- // Defer the resume until we move all the docked tasks to the fullscreen stack below
- topTask.reparent(DOCKED_STACK_ID, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE,
- DEFER_RESUME, "swapDockedAndFullscreenStack - DOCKED_STACK");
- final int size = tasks.size();
- for (int i = 0; i < size; i++) {
- final int id = tasks.get(i).taskId;
- if (id == topTask.taskId) {
- continue;
- }
-
- // Defer the resume until after all the tasks have been moved
- tasks.get(i).reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
- REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, DEFER_RESUME,
- "swapDockedAndFullscreenStack - FULLSCREEN_STACK");
- }
-
- // Because we deferred the resume to avoid conflicts with stack switches while
- // resuming, we need to do it after all the tasks are moved.
- mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
-
- mWindowManager.executeAppTransition();
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
/**
* Moves the input task to the docked stack.
*
@@ -14843,6 +14846,13 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
+ }
+
+ /**
+ * Wrapper function to print out debug data filtered by specified arguments.
+ */
+ private void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
boolean dumpAll = false;
@@ -14851,6 +14861,7 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean dumpCheckinFormat = false;
boolean dumpVisibleStacksOnly = false;
boolean dumpFocusedStackOnly = false;
+ boolean useProto = false;
String dumpPackage = null;
int opti = 0;
@@ -14884,12 +14895,26 @@ public class ActivityManagerService extends IActivityManager.Stub
} else if ("-h".equals(opt)) {
ActivityManagerShellCommand.dumpHelp(pw, true);
return;
+ } else if ("--proto".equals(opt)) {
+ useProto = true;
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
}
long origId = Binder.clearCallingIdentity();
+
+ if (useProto) {
+ //TODO: Options when dumping proto
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ synchronized (this) {
+ writeActivitiesToProtoLocked(proto);
+ }
+ proto.flush();
+ Binder.restoreCallingIdentity(origId);
+ return;
+ }
+
boolean more = false;
// Is the caller requesting to dump a particular piece of data?
if (opti < args.length) {
@@ -15233,6 +15258,10 @@ public class ActivityManagerService extends IActivityManager.Stub
Binder.restoreCallingIdentity(origId);
}
+ private void writeActivitiesToProtoLocked(ProtoOutputStream proto) {
+ mStackSupervisor.writeToProto(proto, ACTIVITIES);
+ }
+
private void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 6901d2de6f00..5e0724e94b41 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -75,6 +75,8 @@ import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityManager.RESIZE_MODE_USER;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -115,7 +117,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
private boolean mStreaming; // Streaming the profiling output to a file.
private String mAgent; // Agent to attach on startup.
private int mDisplayId;
- private int mStackId;
+ private int mWindowingMode;
+ private int mActivityType;
private int mTaskId;
private boolean mIsTaskOverlay;
@@ -271,7 +274,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
mStreaming = false;
mUserId = defUser;
mDisplayId = INVALID_DISPLAY;
- mStackId = INVALID_STACK_ID;
+ mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ mActivityType = ACTIVITY_TYPE_UNDEFINED;
mTaskId = INVALID_TASK_ID;
mIsTaskOverlay = false;
@@ -308,8 +312,10 @@ final class ActivityManagerShellCommand extends ShellCommand {
mReceiverPermission = getNextArgRequired();
} else if (opt.equals("--display")) {
mDisplayId = Integer.parseInt(getNextArgRequired());
- } else if (opt.equals("--stack")) {
- mStackId = Integer.parseInt(getNextArgRequired());
+ } else if (opt.equals("--windowingMode")) {
+ mWindowingMode = Integer.parseInt(getNextArgRequired());
+ } else if (opt.equals("--activityType")) {
+ mActivityType = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--task")) {
mTaskId = Integer.parseInt(getNextArgRequired());
} else if (opt.equals("--task-overlay")) {
@@ -396,9 +402,17 @@ final class ActivityManagerShellCommand extends ShellCommand {
options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(mDisplayId);
}
- if (mStackId != INVALID_STACK_ID) {
- options = ActivityOptions.makeBasic();
- options.setLaunchStackId(mStackId);
+ if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchWindowingMode(mWindowingMode);
+ }
+ if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchActivityType(mActivityType);
}
if (mTaskId != INVALID_TASK_ID) {
options = ActivityOptions.makeBasic();
@@ -2661,6 +2675,7 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" -p: limit output to given package.");
pw.println(" --checkin: output checkin format, resetting data.");
pw.println(" --C: output checkin format, not resetting data.");
+ pw.println(" --proto: output dump in protocol buffer format.");
} else {
pw.println("Activity manager (activity) commands:");
pw.println(" help");
@@ -2685,7 +2700,8 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println(" --track-allocation: enable tracking of object allocations");
pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
pw.println(" specified then run as the current user.");
- pw.println(" --stack <STACK_ID>: Specify into which stack should the activity be put.");
+ pw.println(" --windowingMode <WINDOWING_MODE>: The windowing mode to launch the activity into.");
+ pw.println(" --activityType <ACTIVITY_TYPE>: The activity type to launch the activity as.");
pw.println(" start-service [--user <USER_ID> | current] <INTENT>");
pw.println(" Start a Service. Options are:");
pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 0ccb45f74ec2..142c97ba0e7b 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,7 +17,6 @@
package com.android.server.am;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
@@ -36,7 +35,6 @@ import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.content.Intent.ACTION_MAIN;
@@ -89,10 +87,8 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -116,6 +112,16 @@ import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.am.TaskPersister.DEBUG;
import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.am.proto.ActivityRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.proto.ActivityRecordProto.FRONT_OF_TASK;
+import static com.android.server.am.proto.ActivityRecordProto.IDENTIFIER;
+import static com.android.server.am.proto.ActivityRecordProto.PROC_ID;
+import static com.android.server.am.proto.ActivityRecordProto.STATE;
+import static com.android.server.am.proto.ActivityRecordProto.VISIBLE;
+import static com.android.server.wm.proto.IdentifierProto.HASH_CODE;
+import static com.android.server.wm.proto.IdentifierProto.TITLE;
+import static com.android.server.wm.proto.IdentifierProto.USER_ID;
+
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -153,6 +159,7 @@ import android.util.Log;
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
@@ -1038,7 +1045,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
} else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
activityType = ACTIVITY_TYPE_RECENTS;
- } else if (options != null && options.getLaunchStackId() == ASSISTANT_STACK_ID
+ } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
&& canLaunchAssistActivity(launchedFromPackage)) {
activityType = ACTIVITY_TYPE_ASSISTANT;
}
@@ -1157,8 +1164,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* can be put a secondary screen.
*/
boolean canBeLaunchedOnDisplay(int displayId) {
+ final TaskRecord task = getTask();
+
+ // The resizeability of an Activity's parent task takes precendence over the ActivityInfo.
+ // This allows for a non resizable activity to be launched into a resizeable task.
+ final boolean resizeable =
+ task != null ? task.isResizeable() : supportsResizeableMultiWindow();
+
return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
- supportsResizeableMultiWindow(), launchedFromPid, launchedFromUid, info);
+ resizeable, launchedFromPid, launchedFromUid, info);
}
/**
@@ -2770,4 +2784,25 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
stringName = sb.toString();
return toString();
}
+
+ void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(HASH_CODE, System.identityHashCode(this));
+ proto.write(USER_ID, userId);
+ proto.write(TITLE, intent.getComponent().flattenToShortString());
+ proto.end(token);
+ }
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, CONFIGURATION_CONTAINER);
+ writeIdentifierToProto(proto, IDENTIFIER);
+ proto.write(STATE, state.toString());
+ proto.write(VISIBLE, visible);
+ proto.write(FRONT_OF_TASK, frontOfTask);
+ if (app != null) {
+ proto.write(PROC_ID, app.pid);
+ }
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6140c266f96b..8d21862142d7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -78,6 +78,13 @@ import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.am.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.am.proto.ActivityStackProto.BOUNDS;
+import static com.android.server.am.proto.ActivityStackProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.proto.ActivityStackProto.DISPLAY_ID;
+import static com.android.server.am.proto.ActivityStackProto.FULLSCREEN;
+import static com.android.server.am.proto.ActivityStackProto.ID;
+import static com.android.server.am.proto.ActivityStackProto.RESUMED_ACTIVITY;
+import static com.android.server.am.proto.ActivityStackProto.TASKS;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_NONE;
@@ -86,6 +93,7 @@ import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN_BEHIND;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK;
import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
+
import static java.lang.Integer.MAX_VALUE;
import android.app.Activity;
@@ -122,6 +130,7 @@ import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
@@ -5357,4 +5366,23 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
boolean shouldSleepOrShutDownActivities() {
return shouldSleepActivities() || mService.isShuttingDownLocked();
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, CONFIGURATION_CONTAINER);
+ proto.write(ID, mStackId);
+ for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = mTaskHistory.get(taskNdx);
+ task.writeToProto(proto, TASKS);
+ }
+ if (mResumedActivity != null) {
+ mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+ }
+ proto.write(DISPLAY_ID, mDisplayId);
+ if (mBounds != null) {
+ mBounds.writeToProto(proto, BOUNDS);
+ }
+ proto.write(FULLSCREEN, mFullscreen);
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c8a2a230a7e1..45c4df993801 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -21,6 +21,7 @@ import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
@@ -31,13 +32,20 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.getStackIdForActivityType;
+import static android.app.ActivityManager.StackId.getStackIdForWindowingMode;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_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;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
@@ -83,17 +91,26 @@ import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
import static com.android.server.am.ActivityStack.STACK_VISIBLE;
+import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
+import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.proto.ActivityDisplayProto.STACKS;
+import static com.android.server.am.proto.ActivityDisplayProto.ID;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static java.lang.Integer.MAX_VALUE;
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -147,6 +164,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
@@ -156,6 +174,7 @@ import com.android.internal.os.TransferPipe;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.proto.ActivityDisplayProto;
import com.android.server.wm.ConfigurationContainer;
import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
@@ -707,24 +726,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
TaskRecord anyTaskForIdLocked(int id) {
- return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
- INVALID_STACK_ID);
+ return anyTaskForIdLocked(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
+ }
+
+ TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
+ return anyTaskForIdLocked(id, matchMode, null);
}
/**
* Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise.
* @param id Id of the task we would like returned.
* @param matchMode The mode to match the given task id in.
- * @param stackId The stack to restore the task to (default launch stack will be used if
- * stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}). Only
- * valid if the matchMode is
- * {@link #MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE}.
+ * @param aOptions The activity options to use for restoration. Can be null.
*/
- TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode, int stackId) {
+ TaskRecord anyTaskForIdLocked(int id, @AnyTaskForIdMatchTaskMode int matchMode,
+ @Nullable ActivityOptions aOptions) {
// If there is a stack id set, ensure that we are attempting to actually restore a task
- if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE &&
- stackId != INVALID_STACK_ID) {
- throw new IllegalArgumentException("Should not specify stackId for non-restore lookup");
+ // TODO: Don't really know if this is needed...
+ if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
+ throw new IllegalArgumentException("Should not specify activity options for non-restore"
+ + " lookup");
}
int numDisplays = mActivityDisplays.size();
@@ -762,7 +783,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
// Implicitly, this case is MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE
- if (!restoreRecentTaskLocked(task, stackId)) {
+ if (!restoreRecentTaskLocked(task, aOptions)) {
if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
"Couldn't restore task id=" + id + " found in recents");
return null;
@@ -857,8 +878,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// was 10, user 0 could only have taskIds 0 to 9, user 1: 10 to 19, user 2: 20 to 29, so on.
int candidateTaskId = nextTaskIdForUser(currentTaskId, userId);
while (mRecentTasks.taskIdTakenForUserLocked(candidateTaskId, userId)
- || anyTaskForIdLocked(candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
- INVALID_STACK_ID) != null) {
+ || anyTaskForIdLocked(
+ candidateTaskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
candidateTaskId = nextTaskIdForUser(candidateTaskId, userId);
if (candidateTaskId == currentTaskId) {
// Something wrong!
@@ -2084,38 +2105,35 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// we'll just indicate that this task returns to the home task.
task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
}
- ActivityStack currentStack = task.getStack();
+ final ActivityStack currentStack = task.getStack();
if (currentStack == null) {
Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task="
+ task + " to front. Stack is null");
return;
}
- if (task.isResizeable() && options != null) {
- int stackId = options.getLaunchStackId();
- if (canUseActivityOptionsLaunchBounds(options, stackId)) {
- final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
- task.updateOverrideConfiguration(bounds);
- if (stackId == INVALID_STACK_ID) {
- stackId = task.getLaunchStackId();
- }
- if (stackId != currentStack.mStackId) {
- task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
- DEFER_RESUME, "findTaskToMoveToFrontLocked");
- stackId = currentStack.mStackId;
- // moveTaskToStackUncheckedLocked() should already placed the task on top,
- // still need moveTaskToFrontLocked() below for any transition settings.
- }
- if (StackId.resizeStackWithLaunchBounds(stackId)) {
- resizeStackLocked(stackId, bounds,
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME);
- } else {
- // WM resizeTask must be done after the task is moved to the correct stack,
- // because Task's setBounds() also updates dim layer's bounds, but that has
- // dependency on the stack.
- task.resizeWindowContainer();
- }
+ if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) {
+ final Rect bounds = TaskRecord.validateBounds(options.getLaunchBounds());
+ task.updateOverrideConfiguration(bounds);
+
+ int stackId = getLaunchStackId(null, options, task);
+
+ if (stackId != currentStack.mStackId) {
+ task.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
+ DEFER_RESUME, "findTaskToMoveToFrontLocked");
+ stackId = currentStack.mStackId;
+ // moveTaskToStackUncheckedLocked() should already placed the task on top,
+ // still need moveTaskToFrontLocked() below for any transition settings.
+ }
+ if (StackId.resizeStackWithLaunchBounds(stackId)) {
+ resizeStackLocked(stackId, bounds,
+ null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ !PRESERVE_WINDOWS, true /* allowResizeInDockedMode */, !DEFER_RESUME);
+ } else {
+ // WM resizeTask must be done after the task is moved to the correct stack,
+ // because Task's setBounds() also updates dim layer's bounds, but that has
+ // dependency on the stack.
+ task.resizeWindowContainer();
}
}
@@ -2126,17 +2144,18 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (DEBUG_STACK) Slog.d(TAG_STACK,
"findTaskToMoveToFront: moved to front of stack=" + currentStack);
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
+ handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY,
currentStack.mStackId, forceNonResizeable);
}
- boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
+ boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
// We use the launch bounds in the activity options is the device supports freeform
// window management or is launching into the pinned stack.
- if (options.getLaunchBounds() == null) {
+ if (options == null || options.getLaunchBounds() == null) {
return false;
}
- return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+ return (mService.mSupportsPictureInPicture
+ && options.getLaunchWindowingMode() == WINDOWING_MODE_PINNED)
|| mService.mSupportsFreeformWindowManagement;
}
@@ -2161,6 +2180,179 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return (T) createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
}
+ private int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable TaskRecord task) {
+
+ // First preference if the windowing mode in the activity options if set.
+ int windowingMode = (options != null)
+ ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
+
+ // If windowing mode is unset, then next preference is the candidate task, then the
+ // activity record.
+ if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+ if (task != null) {
+ windowingMode = task.getWindowingMode();
+ }
+ if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
+ windowingMode = r.getWindowingMode();
+ }
+ }
+
+ // Make sure the windowing mode we are trying to use makes sense for what is supported.
+ if (!mService.mSupportsMultiWindow && windowingMode != WINDOWING_MODE_FULLSCREEN) {
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
+ }
+
+ if (!mService.mSupportsSplitScreenMultiWindow
+ && (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)) {
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
+ }
+
+ if (windowingMode == WINDOWING_MODE_FREEFORM
+ && !mService.mSupportsFreeformWindowManagement) {
+ windowingMode = WINDOWING_MODE_FULLSCREEN;
+ }
+
+ return windowingMode;
+ }
+
+ private int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable TaskRecord task) {
+ // First preference if the activity type in the activity options if set.
+ int activityType = (options != null)
+ ? options.getLaunchActivityType() : ACTIVITY_TYPE_UNDEFINED;
+
+ if (activityType != ACTIVITY_TYPE_UNDEFINED) {
+ return activityType;
+ }
+
+ // If activity type is unset, then next preference is the task, then the activity record.
+ if (task != null) {
+ activityType = task.getActivityType();
+ }
+ if (activityType == ACTIVITY_TYPE_UNDEFINED && r != null) {
+ activityType = r.getActivityType();
+ }
+ return activityType;
+ }
+
+ int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable TaskRecord candidateTask) {
+ return getLaunchStackId(r, options, candidateTask, INVALID_DISPLAY);
+ }
+
+ /**
+ * Returns the right stack to use for launching factoring in all the input parameters.
+ *
+ * @param r The activity we are trying to launch. Can be null.
+ * @param options The activity options used to the launch. Can be null.
+ * @param candidateTask The possible task the activity might be launched in. Can be null.
+ *
+ * @return The stack to use for the launch or INVALID_STACK_ID.
+ */
+ int getLaunchStackId(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
+ @Nullable TaskRecord candidateTask, int candidateDisplayId) {
+ int taskId = INVALID_TASK_ID;
+ int displayId = INVALID_DISPLAY;
+ //Rect bounds = null;
+
+ // We give preference to the launch preference in activity options.
+ if (options != null) {
+ taskId = options.getLaunchTaskId();
+ displayId = options.getLaunchDisplayId();
+ // TODO: Need to work this into the equation...
+ //bounds = options.getLaunchBounds();
+ }
+
+ // First preference for stack goes to the task Id set in the activity options. Use the stack
+ // associated with that if possible.
+ if (taskId != INVALID_TASK_ID) {
+ // Temporarily set the task id to invalid in case in re-entry.
+ options.setLaunchTaskId(INVALID_TASK_ID);
+ final TaskRecord task = anyTaskForIdLocked(taskId,
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options);
+ options.setLaunchTaskId(taskId);
+ if (task != null) {
+ return task.getStack().mStackId;
+ }
+ }
+
+ final int windowingMode = resolveWindowingMode(r, options, candidateTask);
+ final int activityType = resolveActivityType(r, options, candidateTask);
+ ActivityStack stack = null;
+
+ // Next preference for stack goes to the display Id set in the activity options or the
+ // candidate display.
+ if (displayId == INVALID_DISPLAY) {
+ displayId = candidateDisplayId;
+ }
+ if (displayId != INVALID_DISPLAY) {
+ if (r != null) {
+ // TODO: This should also take in the windowing mode and activity type into account.
+ stack = getValidLaunchStackOnDisplay(displayId, r);
+ if (stack != null) {
+ return stack.mStackId;
+ }
+ }
+ final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
+ if (display != null) {
+ for (int i = display.mStacks.size() - 1; i >= 0; --i) {
+ stack = display.mStacks.get(i);
+ if (stack.getWindowingMode() == windowingMode
+ && stack.getActivityType() == activityType) {
+ return stack.mStackId;
+ }
+ }
+ // TODO: We should create the stack we want on the display at this point.
+ }
+ }
+
+ // Give preference to the stack and display of the input task and activity if they match the
+ // mode we want to launch into.
+ if (candidateTask != null) {
+ stack = candidateTask.getStack();
+ }
+ if (stack == null && r != null) {
+ stack = r.getStack();
+ }
+ if (stack != null) {
+ if (stack.getWindowingMode() == windowingMode
+ && stack.getActivityType() == activityType) {
+ return stack.mStackId;
+ }
+ ActivityDisplay display = stack.getDisplay();
+
+ if (display != null) {
+ for (int i = display.mStacks.size() - 1; i >= 0; --i) {
+ stack = display.mStacks.get(i);
+ if (stack.getWindowingMode() == windowingMode
+ && stack.getActivityType() == activityType) {
+ return stack.mStackId;
+ }
+ }
+ }
+ }
+
+ // Give preference to the type of activity we are trying to launch followed by the windowing
+ // mode.
+ int stackId = getStackIdForActivityType(activityType);
+ if (stackId != INVALID_STACK_ID) {
+ return stackId;
+ }
+ stackId = getStackIdForWindowingMode(windowingMode);
+ if (stackId != INVALID_STACK_ID) {
+ return stackId;
+ }
+
+ // Whatever...return some default for now.
+ if (candidateTask != null && candidateTask.mBounds != null
+ && mService.mSupportsFreeformWindowManagement) {
+ return FREEFORM_WORKSPACE_STACK_ID;
+ }
+ return FULLSCREEN_WORKSPACE_STACK_ID;
+ }
+
/**
* Get a topmost stack on the display, that is a valid launch stack for specified activity.
* If there is no such stack, new dynamic stack can be created.
@@ -2178,7 +2370,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Return the topmost valid stack on the display.
for (int i = activityDisplay.mStacks.size() - 1; i >= 0; --i) {
final ActivityStack stack = activityDisplay.mStacks.get(i);
- if (mService.mActivityStarter.isValidLaunchStackId(stack.mStackId, displayId, r)) {
+ if (isValidLaunchStackId(stack.mStackId, displayId, r)) {
return stack;
}
}
@@ -2186,7 +2378,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// If there is no valid stack on the external display - check if new dynamic stack will do.
if (displayId != Display.DEFAULT_DISPLAY) {
final int newDynamicStackId = getNextStackId();
- if (mService.mActivityStarter.isValidLaunchStackId(newDynamicStackId, displayId, r)) {
+ if (isValidLaunchStackId(newDynamicStackId, displayId, r)) {
return createStackOnDisplay(newDynamicStackId, displayId, true /*onTop*/);
}
}
@@ -2195,6 +2387,32 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return null;
}
+ boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
+ switch (stackId) {
+ case INVALID_STACK_ID:
+ case HOME_STACK_ID:
+ return false;
+ case FULLSCREEN_WORKSPACE_STACK_ID:
+ return true;
+ case FREEFORM_WORKSPACE_STACK_ID:
+ return r.supportsFreeform();
+ case DOCKED_STACK_ID:
+ return r.supportsSplitScreen();
+ case PINNED_STACK_ID:
+ return r.supportsPictureInPicture();
+ case RECENTS_STACK_ID:
+ return r.isActivityTypeRecents();
+ case ASSISTANT_STACK_ID:
+ return r.isActivityTypeAssistant();
+ default:
+ if (StackId.isDynamicStack(stackId)) {
+ return r.canBeLaunchedOnDisplay(displayId);
+ }
+ Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
+ return false;
+ }
+ }
+
ArrayList<ActivityStack> getStacks() {
ArrayList<ActivityStack> allStacks = new ArrayList<>();
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -2345,8 +2563,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
continueUpdateBounds(RECENTS_STACK_ID);
for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
final int taskId = mResizingTasksDuringAnimation.valueAt(i);
- final TaskRecord task =
- anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY, INVALID_STACK_ID);
+ final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY);
if (task != null) {
task.setTaskDockedResizing(false);
}
@@ -2641,8 +2858,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
*/
boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
boolean pauseImmediately) {
- final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
- INVALID_STACK_ID);
+ final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
if (tr != null) {
tr.removeTaskActivitiesLocked(pauseImmediately);
cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
@@ -2741,23 +2957,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
/**
* Restores a recent task to a stack
* @param task The recent task to be restored.
- * @param stackId The stack to restore the task to (default launch stack will be used
- * if stackId is {@link android.app.ActivityManager.StackId#INVALID_STACK_ID}
- * or is not a static stack).
+ * @param aOptions The activity options to use for restoration.
* @return true if the task has been restored successfully.
*/
- boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
- if (!StackId.isStaticStack(stackId)) {
- // If stack is not static (or stack id is invalid) - use the default one.
- // This means that tasks that were on external displays will be restored on the
- // primary display.
- stackId = task.getLaunchStackId();
- } else if (stackId == DOCKED_STACK_ID && !task.supportsSplitScreen()) {
- // Preferred stack is the docked stack, but the task can't go in the docked stack.
- // Put it in the fullscreen stack.
- stackId = FULLSCREEN_WORKSPACE_STACK_ID;
- }
-
+ boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions) {
+ final int stackId = getLaunchStackId(null, aOptions, task);
final ActivityStack currentStack = task.getStack();
if (currentStack != null) {
// Task has already been restored once. See if we need to do anything more
@@ -2770,15 +2974,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
}
- final ActivityStack stack =
- getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
-
- if (stack == null) {
- // What does this mean??? Not sure how we would get here...
- if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
- "Unable to find/create stack to restore recent task=" + task);
- return false;
- }
+ final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, !ON_TOP);
stack.addTask(task, false /* toTop */, "restoreRecentTask");
// TODO: move call for creation here and other place into Stack.addTask()
@@ -2984,7 +3180,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
resumeFocusedStackTopActivityLocked();
- mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName,
+ mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName, r.userId,
r.getTask().taskId);
}
@@ -3045,6 +3241,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// tasks should always have lower priority than any affinity-matching tasks
// in the fullscreen stacks
affinityMatch = mTmpFindTaskResult.r;
+ } else if (DEBUG_TASKS && mTmpFindTaskResult.matchedByRootAffinity) {
+ Slog.d(TAG_TASKS, "Skipping match on different display "
+ + mTmpFindTaskResult.r.getDisplayId() + " " + displayId);
}
}
}
@@ -3568,6 +3767,26 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
mService.mLockTaskController.dump(pw, prefix);
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, CONFIGURATION_CONTAINER);
+ for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
+ ActivityDisplay activityDisplay = mActivityDisplays.valueAt(displayNdx);
+ activityDisplay.writeToProto(proto, DISPLAYS);
+ }
+ mKeyguardController.writeToProto(proto, KEYGUARD_CONTROLLER);
+ if (mFocusedStack != null) {
+ proto.write(FOCUSED_STACK_ID, mFocusedStack.mStackId);
+ ActivityRecord focusedActivity = getResumedActivityLocked();
+ if (focusedActivity != null) {
+ focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+ }
+ } else {
+ proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
+ }
+ proto.end(token);
+ }
+
/**
* Dump all connected displays' configurations.
* @param prefix Prefix to apply to each line of the dump.
@@ -4015,21 +4234,20 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return list;
}
- void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+ void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
int preferredDisplayId, int actualStackId) {
- handleNonResizableTaskIfNeeded(task, preferredStackId, preferredDisplayId, actualStackId,
- false /* forceNonResizable */);
+ handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
+ actualStackId, false /* forceNonResizable */);
}
- void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId,
+ void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
int preferredDisplayId, int actualStackId, boolean forceNonResizable) {
final boolean isSecondaryDisplayPreferred =
- (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
- || StackId.isDynamicStack(preferredStackId);
+ (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
final ActivityStack actualStack = getStack(actualStackId);
final boolean inSplitScreenMode = actualStack != null
&& actualStack.inSplitScreenWindowingMode();
- if (((!inSplitScreenMode && preferredStackId != DOCKED_STACK_ID)
+ if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
&& !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
return;
}
@@ -4390,6 +4608,17 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
void setIsSleeping(boolean asleep) {
mSleeping = asleep;
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, ActivityDisplayProto.CONFIGURATION_CONTAINER);
+ proto.write(ID, mDisplayId);
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = mStacks.get(stackNdx);
+ stack.writeToProto(proto, STACKS);
+ }
+ proto.end(token);
+ }
}
ActivityStack findStackBehind(ActivityStack stack) {
@@ -4424,18 +4653,22 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final String callingPackage;
final Intent intent;
final int userId;
+ int activityType = ACTIVITY_TYPE_UNDEFINED;
+ int windowingMode = WINDOWING_MODE_UNDEFINED;
final ActivityOptions activityOptions = (bOptions != null)
? new ActivityOptions(bOptions) : null;
- final int launchStackId = (activityOptions != null)
- ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
- if (StackId.isHomeOrRecentsStack(launchStackId)) {
+ if (activityOptions != null) {
+ activityType = activityOptions.getLaunchActivityType();
+ windowingMode = activityOptions.getLaunchWindowingMode();
+ }
+ if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+ taskId + " can't be launch in the home/recents stack.");
}
mWindowManager.deferSurfaceLayout();
try {
- if (launchStackId == DOCKED_STACK_ID) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
mWindowManager.setDockedStackCreateState(
activityOptions.getDockCreateMode(), null /* initialBounds */);
@@ -4447,7 +4680,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE,
- launchStackId);
+ activityOptions);
if (task == null) {
continueUpdateBounds(RECENTS_STACK_ID);
mWindowManager.executeAppTransition();
@@ -4458,14 +4691,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Since we don't have an actual source record here, we assume that the currently
// focused activity was the source.
final ActivityStack focusedStack = getFocusedStack();
- final ActivityRecord sourceRecord =
- focusedStack != null ? focusedStack.topActivity() : null;
+ final ActivityRecord sourceRecord = focusedStack != null
+ ? focusedStack.topActivity() : null;
+ final int stackId = getLaunchStackId(null, activityOptions, task);
- if (launchStackId != INVALID_STACK_ID) {
- if (task.getStackId() != launchStackId) {
- task.reparent(launchStackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE,
- DEFER_RESUME, "startActivityFromRecents");
- }
+ if (stackId != INVALID_STACK_ID && task.getStackId() != stackId) {
+ task.reparent(stackId, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
+ "startActivityFromRecents");
}
// If the user must confirm credentials (e.g. when first launching a work app and the
@@ -4484,7 +4716,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// If we are launching the task in the docked stack, put it into resizing mode so
// the window renders full-screen with the background filling the void. Also only
// call this at the end to make sure that tasks exists on the window manager side.
- if (launchStackId == DOCKED_STACK_ID) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
setResizingDuringAnimation(task);
}
@@ -4502,7 +4734,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
userId = task.userId;
int result = mService.startActivityInPackage(callingUid, callingPackage, intent, null,
null, null, 0, 0, bOptions, userId, task, "startActivityFromRecents");
- if (launchStackId == DOCKED_STACK_ID) {
+ if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
setResizingDuringAnimation(task);
}
return result;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 16abcfb620d9..fab4d0d21b8e 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -39,6 +39,8 @@ import static android.app.ActivityManager.StackId.isDynamicStack;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -167,7 +169,8 @@ class ActivityStarter {
private boolean mDoResume;
private int mStartFlags;
private ActivityRecord mSourceRecord;
- private int mSourceDisplayId;
+ // The display to launch the activity onto, barring any strong reason to do otherwise.
+ private int mPreferredDisplayId;
private TaskRecord mInTask;
private boolean mAddingToTask;
@@ -222,7 +225,7 @@ class ActivityStarter {
mDoResume = false;
mStartFlags = 0;
mSourceRecord = null;
- mSourceDisplayId = INVALID_DISPLAY;
+ mPreferredDisplayId = INVALID_DISPLAY;
mInTask = null;
mAddingToTask = false;
@@ -1024,10 +1027,12 @@ class ActivityStarter {
ActivityRecord reusedActivity = getReusableIntentActivity();
- final int preferredLaunchStackId =
- (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
- final int preferredLaunchDisplayId =
- (mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
+ int preferredWindowingMode = WINDOWING_MODE_UNDEFINED;
+ int preferredLaunchDisplayId = DEFAULT_DISPLAY;
+ if (mOptions != null) {
+ preferredWindowingMode = mOptions.getLaunchWindowingMode();
+ preferredLaunchDisplayId = mOptions.getLaunchDisplayId();
+ }
if (reusedActivity != null) {
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
@@ -1158,7 +1163,7 @@ class ActivityStarter {
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
- mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
+ mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
@@ -1173,8 +1178,7 @@ class ActivityStarter {
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
- result = setTaskFromReuseOrCreateNewTask(
- taskToAffiliate, preferredLaunchStackId, topStack);
+ result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
@@ -1241,7 +1245,7 @@ class ActivityStarter {
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
- mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
+ mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredWindowingMode,
preferredLaunchDisplayId, mTargetStack.mStackId);
return START_SUCCESS;
@@ -1260,7 +1264,7 @@ class ActivityStarter {
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
- mSourceDisplayId = getSourceDisplayId(mSourceRecord, mStartActivity);
+ mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
mLaunchBounds = getOverrideBounds(r, options, inTask);
@@ -1515,7 +1519,7 @@ class ActivityStarter {
!mLaunchSingleTask);
} else {
// Otherwise find the best task to put the activity in.
- intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
+ intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId);
}
}
return intentActivity;
@@ -1523,10 +1527,12 @@ class ActivityStarter {
/**
* Returns the ID of the display to use for a new activity. If the device is in VR mode,
- * then return the Vr mode's virtual display ID. If not, if the source activity has
- * a explicit display ID set, use that to launch the activity.
+ * then return the Vr mode's virtual display ID. If not, if the activity was started with
+ * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID
+ * set, use that to launch the activity.
*/
- private int getSourceDisplayId(ActivityRecord sourceRecord, ActivityRecord startingActivity) {
+ private int getPreferedDisplayId(
+ ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) {
// Check if the Activity is a VR activity. If so, the activity should be launched in
// main display.
if (startingActivity != null && startingActivity.requestedVrComponent != null) {
@@ -1543,6 +1549,13 @@ class ActivityStarter {
return displayId;
}
+ // If the caller requested a display, prefer that display.
+ final int launchDisplayId =
+ (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY;
+ if (launchDisplayId != INVALID_DISPLAY) {
+ return launchDisplayId;
+ }
+
displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY;
// If the activity has a displayId set explicitly, launch it on the same displayId.
if (displayId != INVALID_DISPLAY) {
@@ -1654,8 +1667,8 @@ class ActivityStarter {
mTargetStack.moveToFront("intentActivityFound");
}
- mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(), INVALID_STACK_ID,
- DEFAULT_DISPLAY, mTargetStack.mStackId);
+ mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
+ WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack.mStackId);
// If the caller has requested that the target task be reset, then do so.
if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1675,8 +1688,7 @@ class ActivityStarter {
// Task will be launched over the home stack, so return home.
task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
return;
- } else if (focusedStack != null && focusedStack != task.getStack() &&
- focusedStack.isActivityTypeAssistant()) {
+ } else if (focusedStack != task.getStack() && focusedStack.isActivityTypeAssistant()) {
// Task was launched over the assistant stack, so return there
task.setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT);
return;
@@ -1779,7 +1791,7 @@ class ActivityStarter {
}
private int setTaskFromReuseOrCreateNewTask(
- TaskRecord taskToAffiliate, int preferredLaunchStackId, ActivityStack topStack) {
+ TaskRecord taskToAffiliate, ActivityStack topStack) {
mTargetStack = computeStackFocus(
mStartActivity, true, mLaunchBounds, mLaunchFlags, mOptions);
@@ -1821,8 +1833,10 @@ class ActivityStarter {
// If stack id is specified in activity options, usually it means that activity is
// launched not from currently focused stack (e.g. from SysUI or from shell) - in
// that case we check the target stack.
+ // TODO: Not sure I understand the value or use of the commented out code and the
+ // comment above. See if this causes any issues and why...
updateTaskReturnToType(mStartActivity.getTask(), mLaunchFlags,
- preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : topStack);
+ /*preferredLaunchStackId != INVALID_STACK_ID ? mTargetStack : */topStack);
}
if (mDoResume) {
mTargetStack.moveToFront("reuseOrNewTask");
@@ -1964,7 +1978,8 @@ class ActivityStarter {
if (mLaunchBounds != null) {
mInTask.updateOverrideConfiguration(mLaunchBounds);
- int stackId = mInTask.getLaunchStackId();
+ // TODO: Shouldn't we already know what stack to use by the time we get here?
+ int stackId = mSupervisor.getLaunchStackId(null, null, mInTask);
if (stackId != mInTask.getStackId()) {
mInTask.reparent(stackId, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE,
DEFER_RESUME, "inTaskToFront");
@@ -2079,15 +2094,15 @@ class ActivityStarter {
return mSupervisor.mFocusedStack;
}
- if (mSourceDisplayId != DEFAULT_DISPLAY) {
+ if (mPreferredDisplayId != DEFAULT_DISPLAY) {
// Try to put the activity in a stack on a secondary display.
- stack = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
+ stack = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r);
if (stack == null) {
// If source display is not suitable - look for topmost valid stack in the system.
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Can't launch on mSourceDisplayId=" + mSourceDisplayId
- + ", looking on all displays.");
- stack = mSupervisor.getNextValidLaunchStackLocked(r, mSourceDisplayId);
+ "computeStackFocus: Can't launch on mPreferredDisplayId="
+ + mPreferredDisplayId + ", looking on all displays.");
+ stack = mSupervisor.getNextValidLaunchStackLocked(r, mPreferredDisplayId);
}
}
if (stack == null) {
@@ -2102,9 +2117,10 @@ class ActivityStarter {
}
}
// If there is no suitable dynamic stack then we figure out which static stack to use.
- final int stackId = task != null ? task.getLaunchStackId() :
- bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
- FULLSCREEN_WORKSPACE_STACK_ID;
+ final int stackId = task != null ? mSupervisor.getLaunchStackId(r, aOptions, task)
+ // TODO: This should go in mSupervisor.getLaunchStackId method...
+ : bounds != null && mService.mSupportsFreeformWindowManagement
+ ? FREEFORM_WORKSPACE_STACK_ID : FULLSCREEN_WORKSPACE_STACK_ID;
stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
@@ -2142,8 +2158,8 @@ class ActivityStarter {
}
return canUseFocusedStack && !newTask
- // We strongly prefer to launch activities on the same display as their source.
- && (mSourceDisplayId == focusedStack.mDisplayId);
+ // Using the focus stack isn't important enough to override the prefered display.
+ && (mPreferredDisplayId == focusedStack.mDisplayId);
}
private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
@@ -2165,18 +2181,16 @@ class ActivityStarter {
return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
- final int launchDisplayId =
- (aOptions != null) ? aOptions.getLaunchDisplayId() : INVALID_DISPLAY;
-
- final int launchStackId =
- (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
-
- if (launchStackId != INVALID_STACK_ID && launchDisplayId != INVALID_DISPLAY) {
- throw new IllegalArgumentException(
- "Stack and display id can't be set at the same time.");
+ int launchDisplayId = INVALID_DISPLAY;
+ int launchStackId = INVALID_STACK_ID;
+ if (aOptions != null) {
+ launchDisplayId = aOptions.getLaunchDisplayId();
+ final int vrDisplayId = mUsingVr2dDisplay ? mPreferredDisplayId : INVALID_DISPLAY;
+ launchStackId = mSupervisor.getLaunchStackId(r, aOptions, task, vrDisplayId);
}
- if (isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
+ // TODO: Will no longer be needed once we are on longer using static stack ids.
+ if (mSupervisor.isValidLaunchStackId(launchStackId, launchDisplayId, r)) {
return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
}
if (launchStackId == DOCKED_STACK_ID) {
@@ -2184,14 +2198,16 @@ class ActivityStarter {
// for this activity, so we put the activity in the fullscreen stack.
return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
+ // TODO: Can probably be removed since ASS.getLaunchStackId() does display resolution.
if (launchDisplayId != INVALID_DISPLAY) {
// Stack id has higher priority than display id.
return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r);
}
// If we are using Vr2d display, find the virtual display stack.
+ // TODO: Can be removed.
if (mUsingVr2dDisplay) {
- ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
+ ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mPreferredDisplayId, r);
if (DEBUG_STACK) {
Slog.v(TAG, "Launch stack for app: " + r.toString() +
", on virtual display stack:" + as.toString());
@@ -2200,7 +2216,7 @@ class ActivityStarter {
}
if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
- || mSourceDisplayId != DEFAULT_DISPLAY) {
+ || mPreferredDisplayId != DEFAULT_DISPLAY) {
return null;
}
// Otherwise handle adjacent launch.
@@ -2240,39 +2256,11 @@ class ActivityStarter {
}
}
- boolean isValidLaunchStackId(int stackId, int displayId, ActivityRecord r) {
- switch (stackId) {
- case INVALID_STACK_ID:
- case HOME_STACK_ID:
- return false;
- case FULLSCREEN_WORKSPACE_STACK_ID:
- return true;
- case FREEFORM_WORKSPACE_STACK_ID:
- return r.supportsFreeform();
- case DOCKED_STACK_ID:
- return r.supportsSplitScreen();
- case PINNED_STACK_ID:
- return r.supportsPictureInPicture();
- case RECENTS_STACK_ID:
- return r.isActivityTypeRecents();
- case ASSISTANT_STACK_ID:
- return r.isActivityTypeAssistant();
- default:
- if (StackId.isDynamicStack(stackId)) {
- return r.canBeLaunchedOnDisplay(displayId);
- }
- Slog.e(TAG, "isValidLaunchStackId: Unexpected stackId=" + stackId);
- return false;
- }
- }
-
- Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+ private Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
Rect newBounds = null;
- if (options != null && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
- if (mSupervisor.canUseActivityOptionsLaunchBounds(
- options, options.getLaunchStackId())) {
- newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
- }
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(options)
+ && (r.isResizeable() || (inTask != null && inTask.isResizeable()))) {
+ newBounds = TaskRecord.validateBounds(options.getLaunchBounds());
}
return newBounds;
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3105e37f618f..e839003b957e 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -300,10 +300,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// TODO: remove this once we figure out properly where and how
// PROCESS_EVENT = 1112
- // EVENT SUBTYPE: START = 1
- // KEY_NAME: 1
+ // KEY_STATE = 1
+ // KEY_PACKAGE_NAME: 1002
// KEY_UID: 2
- StatsLog.writeArray(1112, 1, 1, name, 2, uid);
+ StatsLog.writeArray(1112, 1, 1, 1002, name, 2, uid);
}
}
@@ -313,10 +313,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// TODO: remove this once we figure out properly where and how
// PROCESS_EVENT = 1112
- // EVENT SUBTYPE: CRASH = 2
- // KEY_NAME: 1
+ // KEY_STATE = 1
+ // KEY_PACKAGE_NAME: 1002
// KEY_UID: 2
- StatsLog.writeArray(1112, 2, 1, name, 2, uid);
+ StatsLog.writeArray(1112, 1, 2, 1002, name, 2, uid);
}
}
@@ -550,10 +550,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
synchronized (mStats) {
mStats.noteScreenStateLocked(state);
// TODO: remove this once we figure out properly where and how
- // SCREEN_EVENT = 1003
- // State key: 1
+ // SCREEN_EVENT = 2
+ // KEY_STATE: 1
// State value: state. We can change this to our own def later.
- StatsLog.writeArray(1003, 1, state);
+ StatsLog.writeArray(2, 1, state);
}
if (DBG) Slog.d(TAG, "end noteScreenState");
}
@@ -564,14 +564,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mStats.noteScreenBrightnessLocked(brightness);
}
}
-
+
public void noteUserActivity(int uid, int event) {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteUserActivityLocked(uid, event);
}
}
-
+
public void noteWakeUp(String reason, int reasonUid) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 85961135d84f..e03c530d0c92 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -26,6 +26,8 @@ import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WAL
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_OCCLUDED;
+import static com.android.server.am.proto.KeyguardControllerProto.KEYGUARD_SHOWING;
import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -39,6 +41,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.wm.WindowManagerService;
@@ -362,4 +365,11 @@ class KeyguardController {
pw.println(prefix + " mDismissalRequested=" + mDismissalRequested);
pw.println(prefix + " mVisibilityTransactionDepth=" + mVisibilityTransactionDepth);
}
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(KEYGUARD_SHOWING, mKeyguardShowing);
+ proto.write(KEYGUARD_OCCLUDED, mOccluded);
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 241e58391144..72b5de88e50f 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -25,6 +25,7 @@ import static android.app.StatusBarManager.DISABLE_HOME;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.StatusBarManager.DISABLE_NONE;
import static android.app.StatusBarManager.DISABLE_RECENT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.Context.STATUS_BAR_SERVICE;
import static android.os.UserHandle.USER_ALL;
@@ -431,8 +432,8 @@ public class LockTaskController {
mSupervisor.resumeFocusedStackTopActivityLocked();
mWindowManager.executeAppTransition();
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
- mSupervisor.handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, DEFAULT_DISPLAY,
- task.getStackId(), true /* forceNonResizable */);
+ mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
+ DEFAULT_DISPLAY, task.getStackId(), true /* forceNonResizable */);
}
}
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 82971696d670..6a986bb8a684 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -95,7 +95,7 @@ class TaskChangeNotificationController {
};
private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
- l.onActivityPinned((String) m.obj, m.arg1);
+ l.onActivityPinned((String) m.obj, m.arg1, m.arg2);
};
private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
@@ -278,10 +278,10 @@ class TaskChangeNotificationController {
}
/** Notifies all listeners when an Activity is pinned. */
- void notifyActivityPinned(String packageName, int taskId) {
+ void notifyActivityPinned(String packageName, int userId, int taskId) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
- taskId, 0, packageName);
+ userId, taskId, packageName);
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 74c4826f583b..f6e20cd2e1b4 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -472,8 +472,7 @@ public class TaskPersister {
final int taskId = task.taskId;
if (mStackSupervisor.anyTaskForIdLocked(taskId,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
- INVALID_STACK_ID) != null) {
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS) != null) {
// Should not happen.
Slog.wtf(TAG, "Existing task with taskId " + taskId + "found");
} else if (userId != task.userId) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 48da6555e75c..fb8b034ab064 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -26,6 +26,7 @@ import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -65,6 +66,20 @@ import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.am.proto.TaskRecordProto.ACTIVITIES;
+import static com.android.server.am.proto.TaskRecordProto.BOUNDS;
+import static com.android.server.am.proto.TaskRecordProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.proto.TaskRecordProto.FULLSCREEN;
+import static com.android.server.am.proto.TaskRecordProto.ID;
+import static com.android.server.am.proto.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
+import static com.android.server.am.proto.TaskRecordProto.MIN_HEIGHT;
+import static com.android.server.am.proto.TaskRecordProto.MIN_WIDTH;
+import static com.android.server.am.proto.TaskRecordProto.ORIG_ACTIVITY;
+import static com.android.server.am.proto.TaskRecordProto.REAL_ACTIVITY;
+import static com.android.server.am.proto.TaskRecordProto.RESIZE_MODE;
+import static com.android.server.am.proto.TaskRecordProto.RETURN_TO_TYPE;
+import static com.android.server.am.proto.TaskRecordProto.STACK_ID;
+import static com.android.server.am.proto.TaskRecordProto.ACTIVITY_TYPE;
import static java.lang.Integer.MAX_VALUE;
@@ -94,6 +109,7 @@ import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
@@ -507,8 +523,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
updateOverrideConfiguration(bounds);
if (getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
// re-restore the task so it can have the proper stack association.
- mService.mStackSupervisor.restoreRecentTaskLocked(this,
- FREEFORM_WORKSPACE_STACK_ID);
+ mService.mStackSupervisor.restoreRecentTaskLocked(this, null);
}
return true;
}
@@ -729,7 +744,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
// TODO: Handle incorrect request to move before the actual move, not after.
- supervisor.handleNonResizableTaskIfNeeded(this, preferredStackId, DEFAULT_DISPLAY, stackId);
+ supervisor.handleNonResizableTaskIfNeeded(this, getWindowingModeForStackId(preferredStackId,
+ supervisor.getStack(DOCKED_STACK_ID) != null), DEFAULT_DISPLAY, stackId);
boolean successful = (preferredStackId == stackId);
if (successful && stackId == DOCKED_STACK_ID) {
@@ -2079,27 +2095,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
}
- /**
- * Returns the correct stack to use based on task type and currently set bounds,
- * regardless of the focused stack and current stack association of the task.
- * The task will be moved (and stack focus changed) later if necessary.
- */
- int getLaunchStackId() {
- if (isActivityTypeRecents()) {
- return RECENTS_STACK_ID;
- }
- if (isActivityTypeHome()) {
- return HOME_STACK_ID;
- }
- if (isActivityTypeAssistant()) {
- return ASSISTANT_STACK_ID;
- }
- if (mBounds != null) {
- return FREEFORM_WORKSPACE_STACK_ID;
- }
- return FULLSCREEN_WORKSPACE_STACK_ID;
- }
-
/** Returns the bounds that should be used to launch this task. */
private Rect getLaunchBounds() {
if (mStack == null) {
@@ -2257,4 +2252,34 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
stringName = sb.toString();
return toString();
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ super.writeToProto(proto, CONFIGURATION_CONTAINER);
+ proto.write(ID, taskId);
+ for (int i = mActivities.size() - 1; i >= 0; i--) {
+ ActivityRecord activity = mActivities.get(i);
+ activity.writeToProto(proto, ACTIVITIES);
+ }
+ proto.write(STACK_ID, mStack.mStackId);
+ if (mLastNonFullscreenBounds != null) {
+ mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
+ }
+ if (realActivity != null) {
+ proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
+ }
+ if (origActivity != null) {
+ proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
+ }
+ proto.write(ACTIVITY_TYPE, getActivityType());
+ proto.write(RETURN_TO_TYPE, mTaskToReturnTo);
+ proto.write(RESIZE_MODE, mResizeMode);
+ proto.write(FULLSCREEN, mFullscreen);
+ if (mBounds != null) {
+ mBounds.writeToProto(proto, BOUNDS);
+ }
+ proto.write(MIN_WIDTH, mMinWidth);
+ proto.write(MIN_HEIGHT, mMinHeight);
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index e6585ad194ec..fbbdf0051266 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -20,6 +20,7 @@ import android.net.InterfaceConfiguration;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkInfo;
import android.net.RouteInfo;
import android.os.INetworkManagementService;
import android.os.RemoteException;
@@ -44,12 +45,18 @@ public class Nat464Xlat extends BaseNetworkObserver {
// This must match the interface prefix in clatd.c.
private static final String CLAT_PREFIX = "v4-";
- // The network types we will start clatd on,
+ // The network types on which we will start clatd,
// allowing clat only on networks for which we can support IPv6-only.
private static final int[] NETWORK_TYPES = {
- ConnectivityManager.TYPE_MOBILE,
- ConnectivityManager.TYPE_WIFI,
- ConnectivityManager.TYPE_ETHERNET,
+ ConnectivityManager.TYPE_MOBILE,
+ ConnectivityManager.TYPE_WIFI,
+ ConnectivityManager.TYPE_ETHERNET,
+ };
+
+ // The network states in which running clatd is supported.
+ private static final NetworkInfo.State[] NETWORK_STATES = {
+ NetworkInfo.State.CONNECTED,
+ NetworkInfo.State.SUSPENDED,
};
private final INetworkManagementService mNMService;
@@ -81,11 +88,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
*/
public static boolean requiresClat(NetworkAgentInfo nai) {
// TODO: migrate to NetworkCapabilities.TRANSPORT_*.
- final int netType = nai.networkInfo.getType();
final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType());
- // TODO: this should also consider if the network is in SUSPENDED state to avoid stopping
- // clatd in SUSPENDED state.
- final boolean connected = nai.networkInfo.isConnected();
+ final boolean connected = ArrayUtils.contains(NETWORK_STATES, nai.networkInfo.getState());
// We only run clat on networks that don't have a native IPv4 address.
final boolean hasIPv4Address =
(nai.linkProperties != null) && nai.linkProperties.hasIPv4Address();
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 5eafe5f9f64f..057704a56c4c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -52,6 +52,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -73,6 +74,8 @@ public class OffloadController {
private static final String ANYIP = "0.0.0.0";
private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
+ private static enum UpdateType { IF_NEEDED, FORCE };
+
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
@@ -185,8 +188,8 @@ public class OffloadController {
updateStatsForAllUpstreams();
forceTetherStatsPoll();
// [2] (Re)Push all state.
- // TODO: computeAndPushLocalPrefixes()
- // TODO: push all downstream state.
+ computeAndPushLocalPrefixes(UpdateType.FORCE);
+ pushAllDownstreamState();
pushUpstreamParameters(null);
}
@@ -319,7 +322,7 @@ public class OffloadController {
}
private boolean maybeUpdateDataLimit(String iface) {
- // setDataLimit may only be called while offload is occuring on this upstream.
+ // setDataLimit may only be called while offload is occurring on this upstream.
if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) {
return true;
}
@@ -368,15 +371,15 @@ public class OffloadController {
// upstream parameters fails (probably just wait for a subsequent
// onOffloadEvent() callback to tell us offload is available again and
// then reapply all state).
- computeAndPushLocalPrefixes();
+ computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
pushUpstreamParameters(prevUpstream);
}
public void setLocalPrefixes(Set<IpPrefix> localPrefixes) {
- if (!started()) return;
-
mExemptPrefixes = localPrefixes;
- computeAndPushLocalPrefixes();
+
+ if (!started()) return;
+ computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
}
public void notifyDownstreamLinkProperties(LinkProperties lp) {
@@ -385,27 +388,38 @@ public class OffloadController {
if (Objects.equals(oldLp, lp)) return;
if (!started()) return;
+ pushDownstreamState(oldLp, lp);
+ }
- final List<RouteInfo> oldRoutes = (oldLp != null) ? oldLp.getRoutes() : new ArrayList<>();
- final List<RouteInfo> newRoutes = lp.getRoutes();
+ private void pushDownstreamState(LinkProperties oldLp, LinkProperties newLp) {
+ final String ifname = newLp.getInterfaceName();
+ final List<RouteInfo> oldRoutes =
+ (oldLp != null) ? oldLp.getRoutes() : Collections.EMPTY_LIST;
+ final List<RouteInfo> newRoutes = newLp.getRoutes();
// For each old route, if not in new routes: remove.
- for (RouteInfo oldRoute : oldRoutes) {
- if (shouldIgnoreDownstreamRoute(oldRoute)) continue;
- if (!newRoutes.contains(oldRoute)) {
- mHwInterface.removeDownstreamPrefix(ifname, oldRoute.getDestination().toString());
+ for (RouteInfo ri : oldRoutes) {
+ if (shouldIgnoreDownstreamRoute(ri)) continue;
+ if (!newRoutes.contains(ri)) {
+ mHwInterface.removeDownstreamPrefix(ifname, ri.getDestination().toString());
}
}
// For each new route, if not in old routes: add.
- for (RouteInfo newRoute : newRoutes) {
- if (shouldIgnoreDownstreamRoute(newRoute)) continue;
- if (!oldRoutes.contains(newRoute)) {
- mHwInterface.addDownstreamPrefix(ifname, newRoute.getDestination().toString());
+ for (RouteInfo ri : newRoutes) {
+ if (shouldIgnoreDownstreamRoute(ri)) continue;
+ if (!oldRoutes.contains(ri)) {
+ mHwInterface.addDownstreamPrefix(ifname, ri.getDestination().toString());
}
}
}
+ private void pushAllDownstreamState() {
+ for (LinkProperties lp : mDownstreams.values()) {
+ pushDownstreamState(null, lp);
+ }
+ }
+
public void removeDownstreamInterface(String ifname) {
final LinkProperties lp = mDownstreams.remove(ifname);
if (lp == null) return;
@@ -484,10 +498,11 @@ public class OffloadController {
return success;
}
- private boolean computeAndPushLocalPrefixes() {
+ private boolean computeAndPushLocalPrefixes(UpdateType how) {
+ final boolean force = (how == UpdateType.FORCE);
final Set<String> localPrefixStrs = computeLocalPrefixStrings(
mExemptPrefixes, mUpstreamLinkProperties);
- if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
+ if (!force && mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
mLastLocalPrefixStrs = localPrefixStrs;
return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs));
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 2f3b55960c13..205e8283cc55 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -143,6 +143,7 @@ public class SyncManager {
private static final boolean DEBUG_ACCOUNT_ACCESS = false;
+ // Only do the check on a debuggable build.
private static final boolean ENABLE_SUSPICIOUS_CHECK = Build.IS_DEBUGGABLE;
/** Delay a sync due to local changes this long. In milliseconds */
@@ -537,9 +538,11 @@ public class SyncManager {
* @return whether the device most likely has some periodic syncs.
*/
private boolean likelyHasPeriodicSyncs() {
- // STOPSHIP Remove the google specific string.
try {
- return AccountManager.get(mContext).getAccountsByType("com.google").length > 0;
+ // Each sync adapter has a daily periodic sync by default, but sync adapters can remove
+ // them by themselves. So here, we use an arbitrary threshold. If there are more than
+ // this many sync endpoints, surely one of them should have a periodic sync...
+ return mSyncStorageEngine.getAuthorityCount() >= 6;
} catch (Throwable th) {
// Just in case.
}
@@ -3775,48 +3778,10 @@ public class SyncManager {
}
if (op.isPeriodic) {
mLogger.log("Removing periodic sync ", op, " for ", why);
-
- if (ENABLE_SUSPICIOUS_CHECK && isSuspiciousPeriodicSyncRemoval(op)) {
- wtfWithLog("Suspicious removal of " + op + " for " + why);
- }
}
getJobScheduler().cancel(op.jobId);
}
- private boolean isSuspiciousPeriodicSyncRemoval(SyncOperation op) {
- // STOPSHIP Remove the google specific string.
- if (!op.isPeriodic){
- return false;
- }
- boolean found = false;
- for (UserInfo user : UserManager.get(mContext).getUsers(/*excludeDying=*/ true)) {
- if (op.target.userId == user.id) {
- found = true;
- break;
- }
- }
- if (!found) {
- return false; // User is being removed, okay.
- }
- switch (op.target.provider) {
- case "gmail-ls":
- case "com.android.contacts.metadata":
- break;
- default:
- return false;
- }
- final Account account = op.target.account;
- final Account[] accounts = AccountManager.get(mContext)
- .getAccountsByTypeAsUser(account.type, UserHandle.of(op.target.userId));
- for (Account a : accounts) {
- if (a.equals(account)) {
- return true; // Account still exists. Suspicious!
- }
- }
- // Account no longer exists. Makes sense...
- return false;
- }
-
private void wtfWithLog(String message) {
Slog.wtf(TAG, message);
mLogger.log("WTF: ", message);
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 7b277c06328e..3591871f5386 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -911,6 +911,12 @@ public class SyncStorageEngine extends Handler {
}
}
+ public int getAuthorityCount() {
+ synchronized (mAuthorities) {
+ return mAuthorities.size();
+ }
+ }
+
public AuthorityInfo getAuthority(int authorityId) {
synchronized (mAuthorities) {
return mAuthorities.get(authorityId);
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index aafc6317bfae..9cf136720881 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -48,8 +48,10 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.Calendar;
import java.util.TimeZone;
import static com.android.server.display.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
@@ -306,7 +308,7 @@ public final class NightDisplayService extends SystemService
}
@Override
- public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+ public void onCustomStartTimeChanged(LocalTime startTime) {
Slog.d(TAG, "onCustomStartTimeChanged: startTime=" + startTime);
if (mAutoMode != null) {
@@ -315,7 +317,7 @@ public final class NightDisplayService extends SystemService
}
@Override
- public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+ public void onCustomEndTimeChanged(LocalTime endTime) {
Slog.d(TAG, "onCustomEndTimeChanged: endTime=" + endTime);
if (mAutoMode != null) {
@@ -414,6 +416,36 @@ public final class NightDisplayService extends SystemService
outTemp[10] = blue;
}
+ /**
+ * Returns the first date time corresponding to the local time that occurs before the
+ * provided date time.
+ *
+ * @param compareTime the LocalDateTime to compare against
+ * @return the prior LocalDateTime corresponding to this local time
+ */
+ public static LocalDateTime getDateTimeBefore(LocalTime localTime, LocalDateTime compareTime) {
+ final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+ compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+ // Check if the local time has passed, if so return the same time yesterday.
+ return ldt.isAfter(compareTime) ? ldt.minusDays(1) : ldt;
+ }
+
+ /**
+ * Returns the first date time corresponding to this local time that occurs after the
+ * provided date time.
+ *
+ * @param compareTime the LocalDateTime to compare against
+ * @return the next LocalDateTime corresponding to this local time
+ */
+ public static LocalDateTime getDateTimeAfter(LocalTime localTime, LocalDateTime compareTime) {
+ final LocalDateTime ldt = LocalDateTime.of(compareTime.getYear(), compareTime.getMonth(),
+ compareTime.getDayOfMonth(), localTime.getHour(), localTime.getMinute());
+
+ // Check if the local time has passed, if so return the same time tomorrow.
+ return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
+ }
+
private abstract class AutoMode implements NightDisplayController.Callback {
public abstract void onStart();
@@ -425,10 +457,10 @@ public final class NightDisplayService extends SystemService
private final AlarmManager mAlarmManager;
private final BroadcastReceiver mTimeChangedReceiver;
- private NightDisplayController.LocalTime mStartTime;
- private NightDisplayController.LocalTime mEndTime;
+ private LocalTime mStartTime;
+ private LocalTime mEndTime;
- private Calendar mLastActivatedTime;
+ private LocalDateTime mLastActivatedTime;
CustomAutoMode() {
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
@@ -441,31 +473,15 @@ public final class NightDisplayService extends SystemService
}
private void updateActivated() {
- final Calendar now = Calendar.getInstance();
- final Calendar startTime = mStartTime.getDateTimeBefore(now);
- final Calendar endTime = mEndTime.getDateTimeAfter(startTime);
+ final LocalDateTime now = LocalDateTime.now();
+ final LocalDateTime start = getDateTimeBefore(mStartTime, now);
+ final LocalDateTime end = getDateTimeAfter(mEndTime, start);
+ boolean activate = now.isBefore(end);
- boolean activate = now.before(endTime);
if (mLastActivatedTime != null) {
- // Convert mLastActivatedTime to the current timezone if needed.
- final TimeZone currentTimeZone = now.getTimeZone();
- if (!currentTimeZone.equals(mLastActivatedTime.getTimeZone())) {
- final int year = mLastActivatedTime.get(Calendar.YEAR);
- final int dayOfYear = mLastActivatedTime.get(Calendar.DAY_OF_YEAR);
- final int hourOfDay = mLastActivatedTime.get(Calendar.HOUR_OF_DAY);
- final int minute = mLastActivatedTime.get(Calendar.MINUTE);
-
- mLastActivatedTime.setTimeZone(currentTimeZone);
- mLastActivatedTime.set(Calendar.YEAR, year);
- mLastActivatedTime.set(Calendar.DAY_OF_YEAR, dayOfYear);
- mLastActivatedTime.set(Calendar.HOUR_OF_DAY, hourOfDay);
- mLastActivatedTime.set(Calendar.MINUTE, minute);
- }
-
// Maintain the existing activated state if within the current period.
- if (mLastActivatedTime.before(now)
- && mLastActivatedTime.after(startTime)
- && (mLastActivatedTime.after(endTime) || now.before(endTime))) {
+ if (mLastActivatedTime.isBefore(now) && mLastActivatedTime.isAfter(start)
+ && (mLastActivatedTime.isAfter(end) || now.isBefore(end))) {
activate = mController.isActivated();
}
}
@@ -473,14 +489,16 @@ public final class NightDisplayService extends SystemService
if (mIsActivated == null || mIsActivated != activate) {
mController.setActivated(activate);
}
+
updateNextAlarm(mIsActivated, now);
}
- private void updateNextAlarm(@Nullable Boolean activated, @NonNull Calendar now) {
+ private void updateNextAlarm(@Nullable Boolean activated, @NonNull LocalDateTime now) {
if (activated != null) {
- final Calendar next = activated ? mEndTime.getDateTimeAfter(now)
- : mStartTime.getDateTimeAfter(now);
- mAlarmManager.setExact(AlarmManager.RTC, next.getTimeInMillis(), TAG, this, null);
+ final LocalDateTime next = activated ? getDateTimeAfter(mEndTime, now)
+ : getDateTimeAfter(mStartTime, now);
+ final long millis = next.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+ mAlarmManager.setExact(AlarmManager.RTC, millis, TAG, this, null);
}
}
@@ -510,18 +528,18 @@ public final class NightDisplayService extends SystemService
@Override
public void onActivated(boolean activated) {
mLastActivatedTime = mController.getLastActivatedTime();
- updateNextAlarm(activated, Calendar.getInstance());
+ updateNextAlarm(activated, LocalDateTime.now());
}
@Override
- public void onCustomStartTimeChanged(NightDisplayController.LocalTime startTime) {
+ public void onCustomStartTimeChanged(LocalTime startTime) {
mStartTime = startTime;
mLastActivatedTime = null;
updateActivated();
}
@Override
- public void onCustomEndTimeChanged(NightDisplayController.LocalTime endTime) {
+ public void onCustomEndTimeChanged(LocalTime endTime) {
mEndTime = endTime;
mLastActivatedTime = null;
updateActivated();
@@ -550,15 +568,14 @@ public final class NightDisplayService extends SystemService
}
boolean activate = state.isNight();
- final Calendar lastActivatedTime = mController.getLastActivatedTime();
+ final LocalDateTime lastActivatedTime = mController.getLastActivatedTime();
if (lastActivatedTime != null) {
- final Calendar now = Calendar.getInstance();
- final Calendar sunrise = state.sunrise();
- final Calendar sunset = state.sunset();
-
+ final LocalDateTime now = LocalDateTime.now();
+ final LocalDateTime sunrise = state.sunrise();
+ final LocalDateTime sunset = state.sunset();
// Maintain the existing activated state if within the current period.
- if (lastActivatedTime.before(now)
- && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
+ if (lastActivatedTime.isBefore(now) && (lastActivatedTime.isBefore(sunrise)
+ ^ lastActivatedTime.isBefore(sunset))) {
activate = mController.isActivated();
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 11043bd16648..14d9afb14cf9 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2366,6 +2366,13 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.w(TAG, "Invalid escrow token supplied");
return false;
}
+ if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
+ // Most likely, an untrusted credential reset happened in the past which
+ // changed the synthetic password
+ Slog.e(TAG, "Obsolete token: synthetic password derived but it fails GK "
+ + "verification.");
+ return false;
+ }
// Update PASSWORD_TYPE_KEY since it's needed by notifyActivePasswordMetricsAvailable()
// called by setLockCredentialWithAuthTokenLocked().
// TODO: refactor usage of PASSWORD_TYPE_KEY b/65239740
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 89e10503fcf3..0b11479a162a 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -462,18 +462,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
mHandler.post(new Runnable() {
@Override
public void run() {
- if (useSuggested) {
- if (AudioSystem.isStreamActive(stream, 0)) {
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
- flags, packageName, uid);
+ try {
+ if (useSuggested) {
+ if (AudioSystem.isStreamActive(stream, 0)) {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream,
+ direction, flags, packageName, uid);
+ } else {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
+ AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
+ flags | previousFlagPlaySound, packageName, uid);
+ }
} else {
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
- AudioManager.USE_DEFAULT_STREAM_TYPE, direction,
- flags | previousFlagPlaySound, packageName, uid);
+ mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
+ packageName, uid);
}
- } else {
- mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
- packageName, uid);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream="
+ + stream + ", flags=" + flags + ", packageName=" + packageName
+ + ", uid=" + uid + ", useSuggested=" + useSuggested
+ + ", previousFlagPlaySound=" + previousFlagPlaySound, e);
}
}
});
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b77ed913cd12..b9a2d184aade 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1363,6 +1363,10 @@ public class MediaSessionService extends SystemService implements Monitor {
flags, packageName, TAG);
} catch (RemoteException e) {
Log.e(TAG, "Error adjusting default volume.", e);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Cannot adjust volume: direction=" + direction
+ + ", suggestedStream=" + suggestedStream + ", flags=" + flags,
+ e);
}
}
});
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 3444ef3ec2fa..c0fbfbb20b95 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -186,6 +186,11 @@ public class ConditionProviders extends ManagedServices {
super.onPackagesChanged(removingPackage, pkgList, uid);
}
+ @Override
+ protected boolean isValidEntry(String packageOrComponent, int userId) {
+ return true;
+ }
+
public ManagedServiceInfo checkServiceToken(IConditionProvider provider) {
synchronized(mMutex) {
return checkServiceTokenLocked(provider);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index add4184fc129..b7b91a76ebf3 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -294,6 +294,7 @@ abstract public class ManagedServices {
}
if (type == XmlPullParser.START_TAG) {
if (TAG_MANAGED_SERVICES.equals(tag)) {
+ Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
final boolean isPrimary =
@@ -353,6 +354,8 @@ abstract public class ManagedServices {
protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
boolean isPrimary, boolean enabled) {
+ Slog.i(TAG,
+ (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
if (allowedByType == null) {
allowedByType = new ArrayMap<>();
@@ -460,6 +463,7 @@ abstract public class ManagedServices {
}
public void onUserRemoved(int user) {
+ Slog.i(TAG, "Removing approved services for removed user " + user);
mApproved.remove(user);
rebindServices(true);
}
@@ -543,10 +547,8 @@ abstract public class ManagedServices {
}
// State changed
- if (DEBUG) {
- Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
- component.flattenToShortString());
- }
+ Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
+ component.flattenToShortString());
synchronized (mMutex) {
final int[] userIds = mUserProfiles.getCurrentProfileIds();
@@ -628,12 +630,10 @@ abstract public class ManagedServices {
int P = approved.size();
for (int k = P - 1; k >= 0; k--) {
final String approvedPackageOrComponent = approved.valueAt(k);
- if (!hasMatchingServices(approvedPackageOrComponent, userId)){
+ if (!isValidEntry(approvedPackageOrComponent, userId)){
approved.removeAt(k);
- if (DEBUG) {
- Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no matching services found");
- }
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no matching services found");
} else {
if (DEBUG) {
Slog.v(TAG, "Keeping " + approvedPackageOrComponent
@@ -678,6 +678,10 @@ abstract public class ManagedServices {
}
}
+ protected boolean isValidEntry(String packageOrComponent, int userId) {
+ return hasMatchingServices(packageOrComponent, userId);
+ }
+
private boolean hasMatchingServices(String packageOrComponent, int userId) {
if (!TextUtils.isEmpty(packageOrComponent)) {
final String packageName = getPackageName(packageOrComponent);
@@ -830,8 +834,7 @@ abstract public class ManagedServices {
if (name.equals(info.component)
&& info.userid == userid) {
// cut old connections
- if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
- + info.service);
+ Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
removeServiceLocked(i);
if (info.connection != null) {
mContext.unbindService(info.connection);
@@ -859,7 +862,7 @@ abstract public class ManagedServices {
appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
try {
- if (DEBUG) Slog.v(TAG, "binding: " + intent);
+ Slog.v(TAG, "binding: " + intent);
ServiceConnection serviceConnection = new ServiceConnection() {
IInterface mService;
@@ -917,8 +920,7 @@ abstract public class ManagedServices {
final int N = mServices.size();
for (int i = N - 1; i >= 0; i--) {
final ManagedServiceInfo info = mServices.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
+ if (name.equals(info.component) && info.userid == userid) {
removeServiceLocked(i);
if (info.connection != null) {
try {
@@ -945,9 +947,8 @@ abstract public class ManagedServices {
final int N = mServices.size();
for (int i = N - 1; i >= 0; i--) {
final ManagedServiceInfo info = mServices.get(i);
- if (info.service.asBinder() == service.asBinder()
- && info.userid == userid) {
- if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
+ if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
+ Slog.d(TAG, "Removing active service " + info.component);
serviceInfo = removeServiceLocked(i);
}
}
diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/services/core/java/com/android/server/notification/ScheduleCalendar.java
index 9e8b2e34520b..40230bd2ba82 100644
--- a/services/core/java/com/android/server/notification/ScheduleCalendar.java
+++ b/services/core/java/com/android/server/notification/ScheduleCalendar.java
@@ -42,7 +42,8 @@ public class ScheduleCalendar {
public void maybeSetNextAlarm(long now, long nextAlarm) {
if (mSchedule != null) {
- if (mSchedule.exitAtAlarm && now > mSchedule.nextAlarm) {
+ if (mSchedule.exitAtAlarm
+ && (now > mSchedule.nextAlarm || nextAlarm < mSchedule.nextAlarm)) {
mSchedule.nextAlarm = nextAlarm;
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 415c9a9cba10..6d8cac0c661b 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -342,8 +342,7 @@ public class BackgroundDexOptService extends JobService {
DexoptOptions.DEXOPT_BOOT_COMPLETE |
(downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0);
if (is_for_primary_dex) {
- int result = pm.performDexOptWithStatus(new DexoptOptions(pkg,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
+ int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, reason,
dexoptFlags));
success = result != PackageDexOptimizer.DEX_OPT_FAILED;
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -351,8 +350,7 @@ public class BackgroundDexOptService extends JobService {
}
} else {
success = pm.performDexOpt(new DexoptOptions(pkg,
- PackageManagerService.REASON_BACKGROUND_DEXOPT,
- dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX));
+ reason, dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX));
}
if (success) {
// Dexopt succeeded, remove package from the list of failing ones.
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 0f580d818f91..4fafe34b3063 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -438,16 +438,7 @@ public class PackageDexOptimizer {
PackageDexUsage.DexUseInfo dexUseInfo = e.getValue();
pw.println(dex);
pw.increaseIndent();
- for (String isa : dexUseInfo.getLoaderIsas()) {
- String status = null;
- try {
- status = DexFile.getDexFileStatus(path, isa);
- } catch (IOException ioe) {
- status = "[Exception]: " + ioe.getMessage();
- }
- pw.println(isa + ": " + status);
- }
-
+ // TODO(calin): get the status of the oat file (needs installd call)
pw.println("class loader context: " + dexUseInfo.getClassLoaderContext());
if (dexUseInfo.isUsedByOtherApps()) {
pw.println("used be other apps: " + dexUseInfo.getLoadingPackages());
@@ -474,8 +465,9 @@ public class PackageDexOptimizer {
}
if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
- // If the dex files is used by other apps, we cannot use profile-guided compilation.
- return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+ // If the dex files is used by other apps, apply the shared filter.
+ return PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+ PackageManagerService.REASON_SHARED);
}
return targetCompilerFilter;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff52e0ebbbb9..050d9f00071a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -578,8 +578,9 @@ public class PackageManagerService extends IPackageManager.Stub
public static final int REASON_BACKGROUND_DEXOPT = 3;
public static final int REASON_AB_OTA = 4;
public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 5;
+ public static final int REASON_SHARED = 6;
- public static final int REASON_LAST = REASON_INACTIVE_PACKAGE_DOWNGRADE;
+ public static final int REASON_LAST = REASON_SHARED;
/** All dangerous permission names in the same order as the events in MetricsEvent */
private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
@@ -9819,19 +9820,6 @@ public class PackageManagerService extends IPackageManager.Stub
compilerFilter,
dexoptFlags));
- if (pkg.isSystemApp()) {
- // Only dexopt shared secondary dex files belonging to system apps to not slow down
- // too much boot after an OTA.
- int secondaryDexoptFlags = dexoptFlags |
- DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX |
- DexoptOptions.DEXOPT_ONLY_SHARED_DEX;
- mDexManager.dexoptSecondaryDex(new DexoptOptions(
- pkg.packageName,
- compilerFilter,
- secondaryDexoptFlags));
- }
-
- // TODO(shubhamajmera): Record secondary dexopt stats.
switch (primaryDexOptStaus) {
case PackageDexOptimizer.DEX_OPT_PERFORMED:
numberOfPackagesOptimized++;
@@ -25245,6 +25233,37 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
return results;
}
+
+ // NB: this differentiates between preloads and sideloads
+ @Override
+ public String getInstallerForPackage(String packageName) throws RemoteException {
+ final String installerName = getInstallerPackageName(packageName);
+ if (!TextUtils.isEmpty(installerName)) {
+ return installerName;
+ }
+ // differentiate between preload and sideload
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo appInfo = getApplicationInfo(packageName,
+ /*flags*/ 0,
+ /*userId*/ callingUser);
+ if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return "preload";
+ }
+ return "";
+ }
+
+ @Override
+ public int getVersionCodeForPackage(String packageName) throws RemoteException {
+ try {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser);
+ if (pInfo != null) {
+ return pInfo.versionCode;
+ }
+ } catch (Exception e) {
+ }
+ return 0;
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 1a97a72cf2b3..19b0d9bc4b90 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -26,14 +26,19 @@ import dalvik.system.DexFile;
public class PackageManagerServiceCompilerMapping {
// Names for compilation reasons.
static final String REASON_STRINGS[] = {
- "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive"
+ "first-boot", "boot", "install", "bg-dexopt", "ab-ota", "inactive", "shared"
};
+ static final int REASON_SHARED_INDEX = 6;
+
// Static block to ensure the strings array is of the right length.
static {
if (PackageManagerService.REASON_LAST + 1 != REASON_STRINGS.length) {
throw new IllegalStateException("REASON_STRINGS not correct");
}
+ if (!"shared".equals(REASON_STRINGS[REASON_SHARED_INDEX])) {
+ throw new IllegalStateException("REASON_STRINGS not correct because of shared index");
+ }
}
private static String getSystemPropertyName(int reason) {
@@ -52,11 +57,18 @@ public class PackageManagerServiceCompilerMapping {
!DexFile.isValidCompilerFilter(sysPropValue)) {
throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid "
+ "(reason " + REASON_STRINGS[reason] + ")");
+ } else if (!isFilterAllowedForReason(reason, sysPropValue)) {
+ throw new IllegalStateException("Value \"" + sysPropValue +"\" not allowed "
+ + "(reason " + REASON_STRINGS[reason] + ")");
}
return sysPropValue;
}
+ private static boolean isFilterAllowedForReason(int reason, String filter) {
+ return reason != REASON_SHARED_INDEX || !DexFile.isProfileGuidedCompilerFilter(filter);
+ }
+
// Check that the properties are set and valid.
// Note: this is done in a separate method so this class can be statically initialized.
static void checkProperties() {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 12ca89a93d02..338ad2a951c9 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -120,7 +120,7 @@ public final class PowerManagerService extends SystemService
implements Watchdog.Monitor {
private static final String TAG = "PowerManagerService";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final boolean DEBUG_SPEW = DEBUG && true;
// Message: Sent when a user activity timeout occurs to update the power state.
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
new file mode 100644
index 000000000000..11ae2129c339
--- /dev/null
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -0,0 +1,259 @@
+/*
+ * 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.server.stats;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IStatsCompanionService;
+import android.os.IStatsManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.SystemService;
+
+/**
+ * Helper service for statsd (the native stats management service in cmds/statsd/).
+ * Used for registering and receiving alarms on behalf of statsd.
+ */
+public class StatsCompanionService extends IStatsCompanionService.Stub {
+ static final String TAG = "StatsCompanionService";
+ static final boolean DEBUG = true;
+
+ private final Context mContext;
+ private final AlarmManager mAlarmManager;
+ @GuardedBy("sStatsdLock")
+ private static IStatsManager sStatsd;
+ private static final Object sStatsdLock = new Object();
+
+ private final PendingIntent mAnomalyAlarmIntent;
+ private final PendingIntent mPollingAlarmIntent;
+
+ public StatsCompanionService(Context context) {
+ super();
+ mContext = context;
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+ mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(mContext, AnomalyAlarmReceiver.class), 0);
+ mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(mContext, PollingAlarmReceiver.class), 0);
+ }
+
+ public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred.");
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ sStatsd.informAnomalyAlarmFired();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ }
+ }
+ // AlarmManager releases its own wakelock here.
+ }
+ };
+
+ public final static class PollingAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Slog.d(TAG, "Time to poll something.");
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd to inform it of polling alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ sStatsd.informPollAlarmFired();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to inform statsd of polling alarm firing", e);
+ }
+ }
+ // AlarmManager releases its own wakelock here.
+ }
+ };
+
+ @Override // Binder call
+ public void setAnomalyAlarm(long timestampMs) {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Setting anomaly alarm for " + timestampMs);
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+ // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
+ mAlarmManager.set(AlarmManager.RTC, timestampMs, mAnomalyAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override // Binder call
+ public void cancelAnomalyAlarm() {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ mAlarmManager.cancel(mAnomalyAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override // Binder call
+ public void setPollingAlarms(long timestampMs, long intervalMs) {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Setting polling alarm for " + timestampMs
+ + " every " + intervalMs + "ms");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+ // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+ mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs,
+ mPollingAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override // Binder call
+ public void cancelPollingAlarms() {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "Cancelling polling alarm");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ mAlarmManager.cancel(mPollingAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
+ }
+
+ @Override
+ public void statsdReady() {
+ enforceCallingPermission();
+ if (DEBUG) Slog.d(TAG, "learned that statsdReady");
+ sayHiToStatsd(); // tell statsd that we're ready too and link to it
+ }
+
+ private void enforceCallingPermission() {
+ if (Binder.getCallingPid() == Process.myPid()) {
+ return;
+ }
+ mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
+ }
+
+ // Lifecycle and related code
+
+ /** Fetches the statsd IBinder service */
+ private static IStatsManager fetchStatsdService() {
+ return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
+ }
+
+ public static final class Lifecycle extends SystemService {
+ private StatsCompanionService mStatsCompanionService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mStatsCompanionService = new StatsCompanionService(getContext());
+ try {
+ publishBinderService(Context.STATS_COMPANION_SERVICE, mStatsCompanionService);
+ if (DEBUG) Slog.d(TAG, "Published " + Context.STATS_COMPANION_SERVICE);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to publishBinderService", e);
+ }
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ super.onBootPhase(phase);
+ if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mStatsCompanionService.systemReady();
+ }
+ }
+ }
+
+ /** Now that the android system is ready, StatsCompanion is ready too, so inform statsd. */
+ private void systemReady() {
+ if (DEBUG) Slog.d(TAG, "Learned that systemReady");
+ sayHiToStatsd();
+ }
+
+ /** Tells statsd that statscompanion is ready. If the binder call returns, link to statsd. */
+ private void sayHiToStatsd() {
+ synchronized (sStatsdLock) {
+ if (sStatsd != null) {
+ Slog.e(TAG, "Trying to fetch statsd, but it was already fetched",
+ new IllegalStateException("sStatsd is not null when being fetched"));
+ return;
+ }
+ sStatsd = fetchStatsdService();
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd");
+ return;
+ }
+ if (DEBUG) Slog.d(TAG, "Saying hi to statsd");
+ try {
+ sStatsd.statsCompanionReady();
+ // If the statsCompanionReady two-way binder call returns, link to statsd.
+ try {
+ sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
+ forgetEverything();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
+ forgetEverything();
+ }
+ }
+ }
+
+ private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+ @Override
+ public void binderDied() {
+ Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
+ forgetEverything();
+ }
+ }
+
+ private void forgetEverything() {
+ synchronized (sStatsdLock) {
+ sStatsd = null;
+ cancelAnomalyAlarm();
+ cancelPollingAlarms();
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/twilight/TwilightState.java b/services/core/java/com/android/server/twilight/TwilightState.java
index 30a8cccb6ad5..71304a7a4701 100644
--- a/services/core/java/com/android/server/twilight/TwilightState.java
+++ b/services/core/java/com/android/server/twilight/TwilightState.java
@@ -18,7 +18,10 @@ package com.android.server.twilight;
import android.text.format.DateFormat;
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.TimeZone;
/**
* The twilight state, consisting of the sunrise and sunset times (in millis) for the current
@@ -45,12 +48,11 @@ public final class TwilightState {
}
/**
- * Returns a new {@link Calendar} instance initialized to {@link #sunriseTimeMillis()}.
+ * Returns a new {@link LocalDateTime} instance initialized to {@link #sunriseTimeMillis()}.
*/
- public Calendar sunrise() {
- final Calendar sunrise = Calendar.getInstance();
- sunrise.setTimeInMillis(mSunriseTimeMillis);
- return sunrise;
+ public LocalDateTime sunrise() {
+ final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunriseTimeMillis), zoneId);
}
/**
@@ -62,12 +64,11 @@ public final class TwilightState {
}
/**
- * Returns a new {@link Calendar} instance initialized to {@link #sunsetTimeMillis()}.
+ * Returns a new {@link LocalDateTime} instance initialized to {@link #sunsetTimeMillis()}.
*/
- public Calendar sunset() {
- final Calendar sunset = Calendar.getInstance();
- sunset.setTimeInMillis(mSunsetTimeMillis);
- return sunset;
+ public LocalDateTime sunset() {
+ final ZoneId zoneId = TimeZone.getDefault().toZoneId();
+ return LocalDateTime.ofInstant(Instant.ofEpochMilli(mSunsetTimeMillis), zoneId);
}
/**
diff --git a/services/core/java/com/android/server/utils/PriorityDump.java b/services/core/java/com/android/server/utils/PriorityDump.java
index c05cc3ff8827..054f1564730e 100644
--- a/services/core/java/com/android/server/utils/PriorityDump.java
+++ b/services/core/java/com/android/server/utils/PriorityDump.java
@@ -59,10 +59,10 @@ public class SpringfieldNuclearPowerPlant extends Binder {
Donuts in the box: 1
Nuclear reactor status: DANGER - MELTDOWN IMMINENT
- $ adb shell dumpsys snpp --dump_priority CRITICAL
+ $ adb shell dumpsys snpp --dump-priority CRITICAL
Donuts in the box: 1
- $ adb shell dumpsys snpp --dump_priority NORMAL
+ $ adb shell dumpsys snpp --dump-priority NORMAL
Nuclear reactor status: DANGER - MELTDOWN IMMINENT
* </code></pre>
@@ -84,7 +84,7 @@ public class SpringfieldNuclearPowerPlant extends Binder {
*/
public final class PriorityDump {
- public static final String PRIORITY_ARG = "--dump_priority";
+ public static final String PRIORITY_ARG = "--dump-priority";
private PriorityDump() {
throw new UnsupportedOperationException();
@@ -92,12 +92,12 @@ public final class PriorityDump {
/**
* Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is
- * {@code --dump_priority}, stripping the priority and its type.
+ * {@code --dump-priority}, stripping the priority and its type.
* <p>
- * For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call
+ * For example, if called as {@code --dump-priority HIGH arg1 arg2 arg3}, it will call
* <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code>
* <p>
- * If the {@code --dump_priority} is not set, it calls
+ * If the {@code --dump-priority} is not set, it calls
* {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole
* {@code args} instead.
*/
@@ -124,7 +124,7 @@ public final class PriorityDump {
}
/**
- * Gets an array without the {@code --dump_priority PRIORITY} prefix.
+ * Gets an array without the {@code --dump-priority PRIORITY} prefix.
*/
private static String[] getStrippedArgs(String[] args) {
final String[] stripped = new String[args.length - 2];
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index bf769ed46bc1..1e334b83d8b0 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -304,6 +304,6 @@ public class SystemImpl implements SystemInterface {
// flags declaring we want extra info from the package manager for webview providers
private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
- | PackageManager.MATCH_ANY_USER;
+ | PackageManager.GET_SIGNATURES | PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_ANY_USER;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6f796481cc08..6a5f6fafb275 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -247,6 +247,7 @@ import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.android.server.power.ShutdownThread;
+import com.android.server.utils.PriorityDump;
import java.io.BufferedWriter;
import java.io.DataInputStream;
@@ -391,6 +392,18 @@ public class WindowManagerService extends IWindowManager.Stub
};
final WindowSurfacePlacer mWindowPlacerLocked;
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, new String[] {"-a"});
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ doDump(fd, pw, args);
+ }
+ };
+
/**
* Current user when multi-user is enabled. Don't show windows of
* non-current user. Also see mCurrentProfileIds.
@@ -6794,8 +6807,11 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
+ }
+ private void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
boolean dumpAll = false;
boolean useProto = false;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2815da6e7a10..948c028d46ca 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,6 +103,7 @@ import com.android.server.restrictions.RestrictionsManagerService;
import com.android.server.security.KeyAttestationApplicationIdProviderService;
import com.android.server.security.KeyChainSystemService;
import com.android.server.soundtrigger.SoundTriggerService;
+import com.android.server.stats.StatsCompanionService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
import com.android.server.telecom.TelecomLoaderService;
@@ -1523,6 +1524,11 @@ public final class SystemServer {
traceEnd();
}
+ // Statsd helper
+ traceBeginAndSlog("StartStatsCompanionService");
+ mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
+ traceEnd();
+
// Before things start rolling, be sure we have decided whether
// we are in safe mode.
final boolean safeMode = wm.detectSafeMode();
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 58a4456ff4d7..3a92d638fb02 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -30,13 +30,14 @@ import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
import com.android.internal.app.NightDisplayController;
-import com.android.internal.app.NightDisplayController.LocalTime;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.display.DisplayTransformManager;
import com.android.server.display.NightDisplayService;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +46,7 @@ import org.mockito.Mockito;
import java.util.Calendar;
import java.util.HashMap;
+import java.time.LocalTime;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -926,11 +928,10 @@ public class NightDisplayServiceTest {
*/
private void setActivated(boolean activated, int lastActivatedTimeOffset) {
mNightDisplayController.setActivated(activated);
-
- final Calendar c = Calendar.getInstance();
- c.add(Calendar.MINUTE, lastActivatedTimeOffset);
- Secure.putLongForUser(mContext.getContentResolver(),
- Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, c.getTimeInMillis(), mUserId);
+ Secure.putStringForUser(mContext.getContentResolver(),
+ Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
+ LocalDateTime.now().plusMinutes(lastActivatedTimeOffset).toString(),
+ mUserId);
}
/**
@@ -969,7 +970,7 @@ public class NightDisplayServiceTest {
private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
final Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, offsetMinutes);
- return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+ return LocalTime.of(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
}
/**
@@ -984,13 +985,27 @@ public class NightDisplayServiceTest {
final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
- final Calendar now = Calendar.getInstance();
- long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
- long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+ final LocalDateTime now = LocalDateTime.now();
+ final ZoneId zoneId = ZoneId.systemDefault();
+
+ long sunsetMillis = NightDisplayService.getDateTimeBefore(sunset, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
+ long sunriseMillis = NightDisplayService.getDateTimeBefore(sunrise, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
if (sunsetMillis < sunriseMillis) {
- sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+ sunsetMillis = NightDisplayService.getDateTimeAfter(sunset, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
} else {
- sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+ sunriseMillis = NightDisplayService.getDateTimeAfter(sunrise, now)
+ .atZone(zoneId)
+ .toInstant()
+ .toEpochMilli();
}
return new TwilightState(sunriseMillis, sunsetMillis);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
index 47a3a7242a44..526f81572b07 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java
@@ -20,15 +20,19 @@ import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
import static android.view.WindowManagerPolicy.NAV_BAR_RIGHT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -46,6 +50,8 @@ public class ActivityRecordTests extends ActivityTestsBase {
private final ComponentName testActivityComponent =
ComponentName.unflattenFromString("com.foo/.BarActivity");
+ private final ComponentName secondaryActivityComponent =
+ ComponentName.unflattenFromString("com.foo/.BarActivity2");
@Test
public void testStackCleanupOnClearingTask() throws Exception {
final ActivityManagerService service = createActivityManagerService();
@@ -131,4 +137,45 @@ public class ActivityRecordTests extends ActivityTestsBase {
record.ensureActivityConfigurationLocked(0 /* globalChanges */, false /* preserveWindow */);
assertEquals(expectedActivityBounds, record.getBounds());
}
+
+
+ @Test
+ public void testCanBeLaunchedOnDisplay() throws Exception {
+ testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+ true /*activityResizeable*/, true /*expected*/);
+
+ testSupportsLaunchingResizeable(false /*taskPresent*/, true /*taskResizeable*/,
+ false /*activityResizeable*/, false /*expected*/);
+
+ testSupportsLaunchingResizeable(true /*taskPresent*/, false /*taskResizeable*/,
+ true /*activityResizeable*/, false /*expected*/);
+
+ testSupportsLaunchingResizeable(true /*taskPresent*/, true /*taskResizeable*/,
+ false /*activityResizeable*/, true /*expected*/);
+ }
+
+ private void testSupportsLaunchingResizeable(boolean taskPresent, boolean taskResizeable,
+ boolean activityResizeable, boolean expected) {
+ final ActivityManagerService service = createActivityManagerService();
+ service.mSupportsMultiWindow = true;
+
+
+ final TaskRecord task = taskPresent
+ ? createTask(service, testActivityComponent, TEST_STACK_ID) : null;
+
+ if (task != null) {
+ task.setResizeMode(taskResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+ }
+
+ final ActivityRecord record = createActivity(service, secondaryActivityComponent,
+ task);
+ record.info.resizeMode = activityResizeable ? ActivityInfo.RESIZE_MODE_RESIZEABLE
+ : ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+ record.canBeLaunchedOnDisplay(Display.DEFAULT_DISPLAY);
+
+ assertEquals(((TestActivityStackSupervisor) service.mStackSupervisor)
+ .getLastResizeableFromCanPlaceEntityOnDisplay(), expected);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
index 661dd4fc828c..cd1843b37ae2 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackSupervisorTests.java
@@ -17,7 +17,10 @@
package com.android.server.am;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -60,7 +63,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase {
public void testRestoringInvalidTask() throws Exception {
final ActivityManagerService service = createActivityManagerService();
TaskRecord task = service.mStackSupervisor.anyTaskForIdLocked(0 /*taskId*/,
- MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, 0 /*stackId*/);
+ MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null);
assertNull(task);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index b5345444f8cc..0cf1df84c073 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -163,6 +163,7 @@ public class ActivityTestsBase {
*/
protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
private final ActivityDisplay mDisplay;
+ private boolean mLastResizeable;
public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
super(service, looper);
@@ -170,6 +171,22 @@ public class ActivityTestsBase {
mDisplay = new ActivityDisplay();
}
+ // TODO: Use Mockito spy instead. Currently not possible due to TestActivityStackSupervisor
+ // access to ActivityDisplay
+ @Override
+ boolean canPlaceEntityOnDisplay(int displayId, boolean resizeable, int callingPid,
+ int callingUid, ActivityInfo activityInfo) {
+ mLastResizeable = resizeable;
+ return super.canPlaceEntityOnDisplay(displayId, resizeable, callingPid, callingUid,
+ activityInfo);
+ }
+
+ // TODO: remove and use Mockito verify once {@link #canPlaceEntityOnDisplay} override is
+ // removed.
+ public boolean getLastResizeableFromCanPlaceEntityOnDisplay() {
+ return mLastResizeable;
+ }
+
// No home stack is set.
@Override
void moveHomeStackToFront(String reason) {
diff --git a/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
index d378b7c56acb..8a312f64a846 100644
--- a/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
@@ -80,7 +80,7 @@ public class PriorityDumpTest {
@Test
public void testMissingPriority() {
final String[] args = {
- "--dump_priority"
+ "--dump-priority"
};
dump(mDumper, mFd, mPw, args);
verify(mDumper).dump(same(mFd), same(mPw), same(args));
@@ -89,7 +89,7 @@ public class PriorityDumpTest {
@Test
public void testInvalidPriorityNoExtraArgs() {
final String[] args = {
- "--dump_priority", "SUPER_HIGH"
+ "--dump-priority", "SUPER_HIGH"
};
dump(mDumper, mFd, mPw, args);
verify(mDumper).dump(same(mFd), same(mPw), same(args));
@@ -98,7 +98,7 @@ public class PriorityDumpTest {
@Test
public void testInvalidPriorityExtraArgs() {
final String[] args = {
- "--dump_priority", "SUPER_HIGH", "--high", "--five"
+ "--dump-priority", "SUPER_HIGH", "--high", "--five"
};
dump(mDumper, mFd, mPw, args);
verify(mDumper).dump(same(mFd), same(mPw), same(args));
@@ -129,7 +129,7 @@ public class PriorityDumpTest {
@Test
public void testCriticalNoExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "CRITICAL"
+ "--dump-priority", "CRITICAL"
});
verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(EMPTY_ARGS));
}
@@ -137,7 +137,7 @@ public class PriorityDumpTest {
@Test
public void testCriticalExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "CRITICAL", "--high", "--five"
+ "--dump-priority", "CRITICAL", "--high", "--five"
});
verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(new String[] {
"--high", "--five"
@@ -147,7 +147,7 @@ public class PriorityDumpTest {
@Test
public void testHighNoExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "HIGH"
+ "--dump-priority", "HIGH"
});
verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(EMPTY_ARGS));
}
@@ -155,7 +155,7 @@ public class PriorityDumpTest {
@Test
public void testHighExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "HIGH", "--high", "--five"
+ "--dump-priority", "HIGH", "--high", "--five"
});
verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(new String[] {
"--high", "--five"
@@ -165,7 +165,7 @@ public class PriorityDumpTest {
@Test
public void testNormalNoExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "NORMAL"
+ "--dump-priority", "NORMAL"
});
verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(EMPTY_ARGS));
}
@@ -173,7 +173,7 @@ public class PriorityDumpTest {
@Test
public void testNormalExtraArgs() {
dump(mDumper, mFd, mPw, new String[] {
- "--dump_priority", "NORMAL", "--high", "--five"
+ "--dump-priority", "NORMAL", "--high", "--five"
});
verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(new String[] {
"--high", "--five"
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 3788cf331600..b040a6324dbb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.START_ASSISTANT_HIDDEN_SESSION;
import static android.app.ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION;
import static android.app.ActivityManager.START_VOICE_HIDDEN_SESSION;
import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
@@ -222,8 +223,8 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
}
intent = new Intent(intent);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchStackId(StackId.ASSISTANT_STACK_ID);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchActivityType(ACTIVITY_TYPE_ASSISTANT);
return mAm.startAssistantActivity(mComponent.getPackageName(), callingPid, callingUid,
intent, resolvedType, options.toBundle(), mUser);
} catch (RemoteException e) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 629173dfa23b..7a53ef63e2a8 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -161,7 +161,7 @@ public class SmsMessage extends SmsMessageBase {
// Second byte is the MSG_LEN, length of the message
// See 3GPP2 C.S0023 3.4.27
- int size = data[1];
+ int size = data[1] & 0xFF;
// Note: Data may include trailing FF's. That's OK; message
// should still parse correctly.
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index e3f46a40e2b1..de28de6b3185 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -85,6 +85,32 @@ public class Nat464XlatTest {
}
@Test
+ public void testRequiresClat() throws Exception {
+ final int[] supportedTypes = {
+ ConnectivityManager.TYPE_MOBILE,
+ ConnectivityManager.TYPE_WIFI,
+ ConnectivityManager.TYPE_ETHERNET,
+ };
+
+ // NetworkInfo doesn't allow setting the State directly, but rather
+ // requires setting DetailedState in order set State as a side-effect.
+ final NetworkInfo.DetailedState[] supportedDetailedStates = {
+ NetworkInfo.DetailedState.CONNECTED,
+ NetworkInfo.DetailedState.SUSPENDED,
+ };
+
+ for (int type : supportedTypes) {
+ mNai.networkInfo.setType(type);
+ for (NetworkInfo.DetailedState state : supportedDetailedStates) {
+ mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
+ assertTrue(
+ String.format("requiresClat expected for type=%d state=%s", type, state),
+ Nat464Xlat.requiresClat(mNai));
+ }
+ }
+ }
+
+ @Test
public void testNormalStartAndStop() throws Exception {
Nat464Xlat nat = makeNat464Xlat();
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 7a2ff8995458..b98f63b6a5a5 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -671,6 +671,35 @@ public class OffloadControllerTest {
offload.setUpstreamLinkProperties(upstreamLp);
}
+ // Pretend that some local prefixes and downstreams have been added
+ // (and removed, for good measure).
+ final Set<IpPrefix> minimumLocalPrefixes = new HashSet<>();
+ for (String s : new String[]{
+ "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64"}) {
+ minimumLocalPrefixes.add(new IpPrefix(s));
+ }
+ offload.setLocalPrefixes(minimumLocalPrefixes);
+
+ final LinkProperties usbLinkProperties = new LinkProperties();
+ usbLinkProperties.setInterfaceName(RNDIS0);
+ usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24"));
+ usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX)));
+ offload.notifyDownstreamLinkProperties(usbLinkProperties);
+
+ final LinkProperties wifiLinkProperties = new LinkProperties();
+ wifiLinkProperties.setInterfaceName(WLAN0);
+ wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24"));
+ wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX)));
+ wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL)));
+ // Use a benchmark prefix (RFC 5180 + erratum), since the documentation
+ // prefix is included in the excluded prefix list.
+ wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64"));
+ wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64"));
+ wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64")));
+ offload.notifyDownstreamLinkProperties(wifiLinkProperties);
+
+ offload.removeDownstreamInterface(RNDIS0);
+
// Clear invocation history, especially the getForwardedStats() calls
// that happen with setUpstreamParameters().
clearInvocations(mHardware);
@@ -685,6 +714,17 @@ public class OffloadControllerTest {
verifyNoMoreInteractions(mNMService);
// TODO: verify local prefixes and downstreams are also pushed to the HAL.
+ verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture());
+ ArrayList<String> localPrefixes = mStringArrayCaptor.getValue();
+ assertEquals(4, localPrefixes.size());
+ assertArrayListContains(localPrefixes,
+ // TODO: The logic to find and exclude downstream IP prefixes
+ // is currently in Tethering's OffloadWrapper but must be moved
+ // into OffloadController proper. After this, also check for:
+ // "192.168.43.1/32", "2001:2::1/128", "2001:2::2/128"
+ "127.0.0.0/8", "192.0.2.0/24", "fe80::/64", "2001:db8::/64");
+ verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "192.168.43.0/24");
+ verify(mHardware, times(1)).addDownstreamPrefix(WLAN0, "2001:2::/64");
verify(mHardware, times(1)).setUpstreamParameters(eq(RMNET0), any(), any(), any());
verify(mHardware, times(1)).setDataLimit(eq(RMNET0), anyLong());
verifyNoMoreInteractions(mHardware);
@@ -692,7 +732,7 @@ public class OffloadControllerTest {
private static void assertArrayListContains(ArrayList<String> list, String... elems) {
for (String element : elems) {
- assertTrue(list.contains(element));
+ assertTrue(element + " not in list", list.contains(element));
}
}
}