summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java176
-rw-r--r--api/current.txt89
-rw-r--r--api/system-current.txt89
-rw-r--r--api/test-current.txt92
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java36
-rw-r--r--cmds/statsd/Android.bp2
-rw-r--r--cmds/statsd/Android.mk34
-rw-r--r--cmds/statsd/src/Log.h30
-rw-r--r--cmds/statsd/src/LogEntryPrinter.cpp76
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp35
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h20
-rw-r--r--cmds/statsd/src/StatsService.cpp258
-rw-r--r--cmds/statsd/src/StatsService.h121
-rw-r--r--cmds/statsd/src/anomaly/AnomalyMonitor.cpp (renamed from cmds/statsd/src/AnomalyMonitor.cpp)17
-rw-r--r--cmds/statsd/src/anomaly/AnomalyMonitor.h (renamed from cmds/statsd/src/AnomalyMonitor.h)11
-rw-r--r--cmds/statsd/src/anomaly/indexed_priority_queue.h (renamed from cmds/statsd/src/indexed_priority_queue.h)41
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp16
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h17
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp14
-rw-r--r--cmds/statsd/src/condition/condition_util.cpp10
-rw-r--r--cmds/statsd/src/config/ConfigKey.cpp47
-rw-r--r--cmds/statsd/src/config/ConfigKey.h94
-rw-r--r--cmds/statsd/src/config/ConfigListener.cpp31
-rw-r--r--cmds/statsd/src/config/ConfigListener.h54
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp251
-rw-r--r--cmds/statsd/src/config/ConfigManager.h102
-rw-r--r--cmds/statsd/src/external/KernelWakelockPuller.cpp (renamed from cmds/statsd/src/KernelWakelockPuller.cpp)25
-rw-r--r--cmds/statsd/src/external/KernelWakelockPuller.h (renamed from cmds/statsd/src/KernelWakelockPuller.h)2
-rw-r--r--cmds/statsd/src/external/StatsPuller.h (renamed from cmds/statsd/src/StatsPuller.h)0
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp (renamed from cmds/statsd/src/StatsPullerManager.cpp)8
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.h (renamed from cmds/statsd/src/StatsPullerManager.h)3
-rw-r--r--cmds/statsd/src/logd/LogListener.cpp41
-rw-r--r--cmds/statsd/src/logd/LogListener.h (renamed from cmds/statsd/src/LogEntryPrinter.h)41
-rw-r--r--cmds/statsd/src/logd/LogReader.cpp (renamed from cmds/statsd/src/LogReader.cpp)23
-rw-r--r--cmds/statsd/src/logd/LogReader.h (renamed from cmds/statsd/src/LogReader.h)28
-rw-r--r--cmds/statsd/src/main.cpp22
-rw-r--r--cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp13
-rw-r--r--cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp13
-rw-r--r--cmds/statsd/src/matchers/matcher_util.cpp16
-rw-r--r--cmds/statsd/src/metrics/CountAnomalyTracker.cpp5
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp4
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h5
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.cpp3
-rw-r--r--cmds/statsd/src/metrics/MetricsManager.h14
-rw-r--r--cmds/statsd/src/packages/PackageInfoListener.h (renamed from cmds/statsd/src/PackageInfoListener.h)2
-rw-r--r--cmds/statsd/src/packages/UidMap.cpp (renamed from cmds/statsd/src/UidMap.cpp)43
-rw-r--r--cmds/statsd/src/packages/UidMap.h (renamed from cmds/statsd/src/UidMap.h)15
-rw-r--r--cmds/statsd/src/stats_events_copy.proto134
-rw-r--r--cmds/statsd/src/stats_log.proto2
-rw-r--r--cmds/statsd/src/stats_util.cpp156
-rw-r--r--cmds/statsd/src/stats_util.h6
-rw-r--r--cmds/statsd/src/storage/DropboxReader.cpp (renamed from cmds/statsd/src/DropboxReader.cpp)6
-rw-r--r--cmds/statsd/src/storage/DropboxReader.h (renamed from cmds/statsd/src/DropboxReader.h)0
-rw-r--r--cmds/statsd/src/storage/DropboxWriter.cpp (renamed from cmds/statsd/src/DropboxWriter.cpp)4
-rw-r--r--cmds/statsd/src/storage/DropboxWriter.h (renamed from cmds/statsd/src/DropboxWriter.h)0
-rw-r--r--cmds/statsd/tests/AnomalyMonitor_test.cpp4
-rw-r--r--cmds/statsd/tests/ConditionTracker_test.cpp5
-rw-r--r--cmds/statsd/tests/ConfigManager_test.cpp156
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp7
-rw-r--r--cmds/statsd/tests/LogReader_test.cpp2
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp13
-rw-r--r--cmds/statsd/tests/UidMap_test.cpp6
-rw-r--r--cmds/statsd/tests/indexed_priority_queue_test.cpp2
-rw-r--r--core/java/android/accessibilityservice/GestureDescription.java12
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManager.java84
-rw-r--r--core/java/android/app/slice/Slice.java (renamed from core/java/android/slice/Slice.java)154
-rw-r--r--core/java/android/app/slice/SliceItem.java (renamed from core/java/android/slice/SliceItem.java)26
-rw-r--r--core/java/android/app/slice/SliceProvider.java (renamed from core/java/android/slice/SliceProvider.java)38
-rw-r--r--core/java/android/app/slice/SliceQuery.java (renamed from core/java/android/slice/SliceQuery.java)15
-rw-r--r--core/java/android/app/slice/views/ActionRow.java (renamed from core/java/android/slice/views/ActionRow.java)8
-rw-r--r--core/java/android/app/slice/views/GridView.java (renamed from core/java/android/slice/views/GridView.java)18
-rw-r--r--core/java/android/app/slice/views/LargeSliceAdapter.java (renamed from core/java/android/slice/views/LargeSliceAdapter.java)10
-rw-r--r--core/java/android/app/slice/views/LargeTemplateView.java (renamed from core/java/android/slice/views/LargeTemplateView.java)15
-rw-r--r--core/java/android/app/slice/views/MessageView.java (renamed from core/java/android/slice/views/MessageView.java)10
-rw-r--r--core/java/android/app/slice/views/RemoteInputView.java (renamed from core/java/android/slice/views/RemoteInputView.java)2
-rw-r--r--core/java/android/app/slice/views/ShortcutView.java (renamed from core/java/android/slice/views/ShortcutView.java)10
-rw-r--r--core/java/android/app/slice/views/SliceView.java (renamed from core/java/android/slice/views/SliceView.java)18
-rw-r--r--core/java/android/app/slice/views/SliceViewUtil.java (renamed from core/java/android/slice/views/SliceViewUtil.java)2
-rw-r--r--core/java/android/app/slice/views/SmallTemplateView.java (renamed from core/java/android/slice/views/SmallTemplateView.java)24
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java19
-rw-r--r--core/java/android/content/ContentProvider.java3
-rw-r--r--core/java/android/content/ContentResolver.java36
-rw-r--r--core/java/android/content/pm/FeatureInfo.java13
-rw-r--r--core/java/android/os/SystemProperties.java6
-rwxr-xr-xcore/java/android/provider/Settings.java1
-rw-r--r--core/java/android/view/ViewDebug.java167
-rw-r--r--core/java/android/view/autofill/AutofillManager.java8
-rw-r--r--core/java/android/view/textclassifier/SmartSelection.java63
-rw-r--r--core/java/android/widget/Editor.java17
-rw-r--r--core/java/android/widget/TextView.java30
-rw-r--r--core/java/com/android/internal/widget/Magnifier.java120
-rw-r--r--core/jni/android_text_Hyphenator.cpp2
-rw-r--r--core/proto/android/content/featureinfo.proto29
-rw-r--r--core/proto/android/os/incident.proto6
-rw-r--r--core/proto/android/service/package.proto8
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/layout/slice_grid.xml4
-rw-r--r--core/res/res/layout/slice_message.xml4
-rw-r--r--core/res/res/layout/slice_message_local.xml4
-rw-r--r--core/res/res/layout/slice_remote_input.xml4
-rw-r--r--core/res/res/values/strings.xml7
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--libs/hwui/Android.bp4
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java2
-rw-r--r--media/jni/android_media_MediaExtractor.cpp5
-rw-r--r--media/jni/android_media_MediaExtractor.h4
-rw-r--r--media/jni/soundpool/SoundPool.cpp1
-rw-r--r--packages/CtsShim/Android.mk10
-rw-r--r--packages/CtsShim/CtsShim.apkbin4807 -> 0 bytes
-rw-r--r--packages/CtsShim/CtsShimPriv.apkbin6044 -> 0 bytes
-rw-r--r--packages/CtsShim/apk/arm/CtsShim.apkbin0 -> 4817 bytes
-rw-r--r--packages/CtsShim/apk/arm/CtsShimPriv.apkbin0 -> 9938 bytes
-rw-r--r--packages/CtsShim/apk/x86/CtsShim.apkbin0 -> 4817 bytes
-rw-r--r--packages/CtsShim/apk/x86/CtsShimPriv.apkbin0 -> 10205 bytes
-rw-r--r--packages/CtsShim/build/README29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java67
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java4
-rw-r--r--packages/SystemUI/Android.mk1
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java5
-rw-r--r--packages/SystemUI/res/values/strings.xml6
-rw-r--r--packages/SystemUI/shared/Android.mk42
-rw-r--r--packages/SystemUI/shared/AndroidManifest.xml24
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java186
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java124
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java)19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java)74
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java)323
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/Task.java)34
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java27
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java)14
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java)8
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java)6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java60
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java403
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java (renamed from packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java)31
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java (renamed from packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java)13
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java (renamed from packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java)4
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java (renamed from packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java)25
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java201
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java50
-rw-r--r--packages/SystemUI/shared/tests/Android.mk53
-rw-r--r--packages/SystemUI/shared/tests/AndroidManifest.xml30
-rw-r--r--packages/SystemUI/shared/tests/AndroidTest.xml28
-rw-r--r--packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java113
-rw-r--r--packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java (renamed from packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java)21
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java247
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java856
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/DockState.java351
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java20
-rw-r--r--packages/SystemUI/tests/Android.mk1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java15
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationController.java19
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java49
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java8
-rw-r--r--services/core/java/com/android/server/BatteryService.java124
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java8
-rw-r--r--services/core/java/com/android/server/am/UserController.java31
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java3
-rw-r--r--services/core/java/com/android/server/job/controllers/TimeController.java32
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java51
-rw-r--r--services/core/java/com/android/server/pm/Settings.java6
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java9
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java3
-rw-r--r--services/tests/servicestests/Android.mk5
-rw-r--r--services/tests/servicestests/src/com/android/server/BatteryServiceTest.java121
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java13
-rw-r--r--telephony/java/android/telephony/NetworkScanRequest.java105
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java18
-rw-r--r--telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java8
-rw-r--r--tests/FeatureSplit/base/Android.mk1
-rw-r--r--tests/FeatureSplit/feature1/Android.mk2
-rw-r--r--tests/FeatureSplit/feature1/AndroidManifest.xml4
-rw-r--r--tests/FeatureSplit/feature1/res/values/values.xml2
-rw-r--r--tests/FeatureSplit/feature2/Android.mk2
-rw-r--r--tests/FeatureSplit/feature2/AndroidManifest.xml2
-rw-r--r--tests/FeatureSplit/feature2/res/values/values.xml2
-rw-r--r--tools/bit/command.cpp2
-rw-r--r--tools/bit/main.cpp7
-rw-r--r--tools/bit/make.cpp29
-rw-r--r--tools/bit/make.h2
-rwxr-xr-xtools/fonts/fontchain_lint.py2
231 files changed, 5393 insertions, 2926 deletions
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
new file mode 100644
index 000000000000..7c5316d233a7
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabaseIoPerfTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.database;
+
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.util.Preconditions;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Performance tests for measuring amount of data written during typical DB operations
+ *
+ * <p>To run: bit CorePerfTests:android.database.SQLiteDatabaseIoPerfTest
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class SQLiteDatabaseIoPerfTest {
+ private static final String TAG = "SQLiteDatabaseIoPerfTest";
+ private static final String DB_NAME = "db_io_perftest";
+ private static final int DEFAULT_DATASET_SIZE = 500;
+
+ private Long mWriteBytes;
+
+ private SQLiteDatabase mDatabase;
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mContext.deleteDatabase(DB_NAME);
+ mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
+ mDatabase.execSQL("CREATE TABLE T1 "
+ + "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
+ }
+
+ @After
+ public void tearDown() {
+ mDatabase.close();
+ mContext.deleteDatabase(DB_NAME);
+ }
+
+ @Test
+ public void testDatabaseModifications() {
+ startMeasuringWrites();
+ ContentValues cv = new ContentValues();
+ String[] whereArg = new String[1];
+ for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+ cv.put("_ID", i);
+ cv.put("COL_A", i);
+ cv.put("COL_B", "NewValue");
+ cv.put("COL_C", 1.0);
+ assertEquals(i, mDatabase.insert("T1", null, cv));
+ }
+ cv = new ContentValues();
+ for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+ cv.put("COL_B", "UpdatedValue");
+ cv.put("COL_C", 1.1);
+ whereArg[0] = String.valueOf(i);
+ assertEquals(1, mDatabase.update("T1", cv, "_ID=?", whereArg));
+ }
+ for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
+ whereArg[0] = String.valueOf(i);
+ assertEquals(1, mDatabase.delete("T1", "_ID=?", whereArg));
+ }
+ // Make sure all changes are written to disk
+ mDatabase.close();
+ long bytes = endMeasuringWrites();
+ sendResults("testDatabaseModifications" , bytes);
+ }
+
+ @Test
+ public void testInsertsWithTransactions() {
+ startMeasuringWrites();
+ final int txSize = 10;
+ ContentValues cv = new ContentValues();
+ for (int i = 0; i < DEFAULT_DATASET_SIZE * 5; i++) {
+ if (i % txSize == 0) {
+ mDatabase.beginTransaction();
+ }
+ if (i % txSize == txSize-1) {
+ mDatabase.setTransactionSuccessful();
+ mDatabase.endTransaction();
+
+ }
+ cv.put("_ID", i);
+ cv.put("COL_A", i);
+ cv.put("COL_B", "NewValue");
+ cv.put("COL_C", 1.0);
+ assertEquals(i, mDatabase.insert("T1", null, cv));
+ }
+ // Make sure all changes are written to disk
+ mDatabase.close();
+ long bytes = endMeasuringWrites();
+ sendResults("testInsertsWithTransactions" , bytes);
+ }
+
+ private void startMeasuringWrites() {
+ Preconditions.checkState(mWriteBytes == null, "Measurement already started");
+ mWriteBytes = getIoStats().get("write_bytes");
+ }
+
+ private long endMeasuringWrites() {
+ Preconditions.checkState(mWriteBytes != null, "Measurement wasn't started");
+ Long newWriteBytes = getIoStats().get("write_bytes");
+ return newWriteBytes - mWriteBytes;
+ }
+
+ private void sendResults(String testName, long writeBytes) {
+ Log.i(TAG, testName + " write_bytes: " + writeBytes);
+ Bundle status = new Bundle();
+ status.putLong("write_bytes", writeBytes);
+ InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+ }
+
+ private static Map<String, Long> getIoStats() {
+ String ioStat = "/proc/self/io";
+ Map<String, Long> results = new ArrayMap<>();
+ try {
+ List<String> lines = Files.readAllLines(new File(ioStat).toPath());
+ for (String line : lines) {
+ line = line.trim();
+ String[] split = line.split(":");
+ if (split.length == 2) {
+ try {
+ String key = split[0].trim();
+ Long value = Long.valueOf(split[1].trim());
+ results.put(key, value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Cannot parse number from " + line);
+ }
+ } else if (line.isEmpty()) {
+ Log.e(TAG, "Cannot parse line " + line);
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Can't read: " + ioStat, e);
+ }
+ return results;
+ }
+
+}
diff --git a/api/current.txt b/api/current.txt
index 79816ac17b67..3e1440286444 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35,6 +35,7 @@ package android {
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+ field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -4006,8 +4007,10 @@ package android.app {
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int);
ctor public ActivityManager.TaskDescription(java.lang.String);
ctor public ActivityManager.TaskDescription();
ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
@@ -6941,6 +6944,88 @@ package android.app.job {
}
+package android.app.slice {
+
+ public final class Slice implements android.os.Parcelable {
+ ctor protected Slice(android.os.Parcel);
+ method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public int describeContents();
+ method public java.util.List<java.lang.String> getHints();
+ method public java.util.List<android.app.slice.SliceItem> getItems();
+ method public android.net.Uri getUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+ field public static final java.lang.String HINT_ACTIONS = "actions";
+ field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+ field public static final java.lang.String HINT_LARGE = "large";
+ field public static final java.lang.String HINT_LIST = "list";
+ field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+ field public static final java.lang.String HINT_MESSAGE = "message";
+ field public static final java.lang.String HINT_NO_TINT = "no_tint";
+ field public static final java.lang.String HINT_PARTIAL = "partial";
+ field public static final java.lang.String HINT_SELECTED = "selected";
+ field public static final java.lang.String HINT_SOURCE = "source";
+ field public static final java.lang.String HINT_TITLE = "title";
+ }
+
+ public static class Slice.Builder {
+ ctor public Slice.Builder(android.net.Uri);
+ ctor public Slice.Builder(android.app.slice.Slice.Builder);
+ method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+ method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+ method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+ method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice build();
+ }
+
+ public final class SliceItem implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.app.PendingIntent getAction();
+ method public int getColor();
+ method public java.util.List<java.lang.String> getHints();
+ method public android.graphics.drawable.Icon getIcon();
+ method public android.app.RemoteInput getRemoteInput();
+ method public android.app.slice.Slice getSlice();
+ method public java.lang.CharSequence getText();
+ method public long getTimestamp();
+ method public int getType();
+ method public boolean hasHint(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+ field public static final int TYPE_ACTION = 4; // 0x4
+ field public static final int TYPE_COLOR = 6; // 0x6
+ field public static final int TYPE_IMAGE = 3; // 0x3
+ field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+ field public static final int TYPE_SLICE = 1; // 0x1
+ field public static final int TYPE_TEXT = 2; // 0x2
+ field public static final int TYPE_TIMESTAMP = 8; // 0x8
+ }
+
+ public abstract class SliceProvider extends android.content.ContentProvider {
+ ctor public SliceProvider();
+ method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public final java.lang.String getType(android.net.Uri);
+ method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+ method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+ }
+
+}
+
package android.app.usage {
public final class ConfigurationStats implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 40683d359eaa..5138f6ed33be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -58,6 +58,7 @@ package android {
field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
field public static final java.lang.String BIND_SETTINGS_SUGGESTIONS_SERVICE = "android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE";
+ field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
@@ -4168,8 +4169,10 @@ package android.app {
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int);
ctor public ActivityManager.TaskDescription(java.lang.String);
ctor public ActivityManager.TaskDescription();
ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
@@ -7384,6 +7387,88 @@ package android.app.job {
}
+package android.app.slice {
+
+ public final class Slice implements android.os.Parcelable {
+ ctor protected Slice(android.os.Parcel);
+ method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public int describeContents();
+ method public java.util.List<java.lang.String> getHints();
+ method public java.util.List<android.app.slice.SliceItem> getItems();
+ method public android.net.Uri getUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+ field public static final java.lang.String HINT_ACTIONS = "actions";
+ field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+ field public static final java.lang.String HINT_LARGE = "large";
+ field public static final java.lang.String HINT_LIST = "list";
+ field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+ field public static final java.lang.String HINT_MESSAGE = "message";
+ field public static final java.lang.String HINT_NO_TINT = "no_tint";
+ field public static final java.lang.String HINT_PARTIAL = "partial";
+ field public static final java.lang.String HINT_SELECTED = "selected";
+ field public static final java.lang.String HINT_SOURCE = "source";
+ field public static final java.lang.String HINT_TITLE = "title";
+ }
+
+ public static class Slice.Builder {
+ ctor public Slice.Builder(android.net.Uri);
+ ctor public Slice.Builder(android.app.slice.Slice.Builder);
+ method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+ method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+ method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+ method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice build();
+ }
+
+ public final class SliceItem implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.app.PendingIntent getAction();
+ method public int getColor();
+ method public java.util.List<java.lang.String> getHints();
+ method public android.graphics.drawable.Icon getIcon();
+ method public android.app.RemoteInput getRemoteInput();
+ method public android.app.slice.Slice getSlice();
+ method public java.lang.CharSequence getText();
+ method public long getTimestamp();
+ method public int getType();
+ method public boolean hasHint(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+ field public static final int TYPE_ACTION = 4; // 0x4
+ field public static final int TYPE_COLOR = 6; // 0x6
+ field public static final int TYPE_IMAGE = 3; // 0x3
+ field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+ field public static final int TYPE_SLICE = 1; // 0x1
+ field public static final int TYPE_TEXT = 2; // 0x2
+ field public static final int TYPE_TIMESTAMP = 8; // 0x8
+ }
+
+ public abstract class SliceProvider extends android.content.ContentProvider {
+ ctor public SliceProvider();
+ method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public final java.lang.String getType(android.net.Uri);
+ method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+ method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+ }
+
+}
+
package android.app.usage {
public final class CacheQuotaHint implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index cb4a6f2f9414..bd09f68870c1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -35,6 +35,7 @@ package android {
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
+ field public static final java.lang.String BIND_SLICE = "android.permission.BIND_SLICE";
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -4026,13 +4027,17 @@ package android.app {
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
- ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int, int);
+ ctor public deprecated ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+ ctor public ActivityManager.TaskDescription(java.lang.String, int);
ctor public ActivityManager.TaskDescription(java.lang.String);
ctor public ActivityManager.TaskDescription();
ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
method public int describeContents();
method public android.graphics.Bitmap getIcon();
+ method public java.lang.String getIconFilename();
+ method public int getIconResource();
method public java.lang.String getLabel();
method public int getPrimaryColor();
method public void readFromParcel(android.os.Parcel);
@@ -7010,6 +7015,88 @@ package android.app.job {
}
+package android.app.slice {
+
+ public final class Slice implements android.os.Parcelable {
+ ctor protected Slice(android.os.Parcel);
+ method public static android.app.slice.Slice bindSlice(android.content.ContentResolver, android.net.Uri);
+ method public int describeContents();
+ method public java.util.List<java.lang.String> getHints();
+ method public java.util.List<android.app.slice.SliceItem> getItems();
+ method public android.net.Uri getUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.Slice> CREATOR;
+ field public static final java.lang.String HINT_ACTIONS = "actions";
+ field public static final java.lang.String HINT_HORIZONTAL = "horizontal";
+ field public static final java.lang.String HINT_LARGE = "large";
+ field public static final java.lang.String HINT_LIST = "list";
+ field public static final java.lang.String HINT_LIST_ITEM = "list_item";
+ field public static final java.lang.String HINT_MESSAGE = "message";
+ field public static final java.lang.String HINT_NO_TINT = "no_tint";
+ field public static final java.lang.String HINT_PARTIAL = "partial";
+ field public static final java.lang.String HINT_SELECTED = "selected";
+ field public static final java.lang.String HINT_SOURCE = "source";
+ field public static final java.lang.String HINT_TITLE = "title";
+ }
+
+ public static class Slice.Builder {
+ ctor public Slice.Builder(android.net.Uri);
+ ctor public Slice.Builder(android.app.slice.Slice.Builder);
+ method public android.app.slice.Slice.Builder addAction(android.app.PendingIntent, android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addColor(int, java.lang.String...);
+ method public android.app.slice.Slice.Builder addColor(int, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addHints(java.lang.String...);
+ method public android.app.slice.Slice.Builder addHints(java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.lang.String...);
+ method public android.app.slice.Slice.Builder addIcon(android.graphics.drawable.Icon, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addRemoteInput(android.app.RemoteInput, java.lang.String...);
+ method public android.app.slice.Slice.Builder addSubSlice(android.app.slice.Slice);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.lang.String...);
+ method public android.app.slice.Slice.Builder addText(java.lang.CharSequence, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.lang.String...);
+ method public android.app.slice.Slice.Builder addTimestamp(long, java.util.List<java.lang.String>);
+ method public android.app.slice.Slice build();
+ }
+
+ public final class SliceItem implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.app.PendingIntent getAction();
+ method public int getColor();
+ method public java.util.List<java.lang.String> getHints();
+ method public android.graphics.drawable.Icon getIcon();
+ method public android.app.RemoteInput getRemoteInput();
+ method public android.app.slice.Slice getSlice();
+ method public java.lang.CharSequence getText();
+ method public long getTimestamp();
+ method public int getType();
+ method public boolean hasHint(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.slice.SliceItem> CREATOR;
+ field public static final int TYPE_ACTION = 4; // 0x4
+ field public static final int TYPE_COLOR = 6; // 0x6
+ field public static final int TYPE_IMAGE = 3; // 0x3
+ field public static final int TYPE_REMOTE_INPUT = 9; // 0x9
+ field public static final int TYPE_SLICE = 1; // 0x1
+ field public static final int TYPE_TEXT = 2; // 0x2
+ field public static final int TYPE_TIMESTAMP = 8; // 0x8
+ }
+
+ public abstract class SliceProvider extends android.content.ContentProvider {
+ ctor public SliceProvider();
+ method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+ method public final java.lang.String getType(android.net.Uri);
+ method public final android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+ method public abstract android.app.slice.Slice onBindSlice(android.net.Uri);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], android.os.Bundle, android.os.CancellationSignal);
+ method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+ field public static final java.lang.String SLICE_TYPE = "vnd.android.slice";
+ }
+
+}
+
package android.app.usage {
public final class ConfigurationStats implements android.os.Parcelable {
@@ -35400,6 +35487,7 @@ package android.provider {
method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
method public static final deprecated void setLocationProviderEnabled(android.content.ContentResolver, java.lang.String, boolean);
field public static final java.lang.String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
+ field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
field public static final java.lang.String ACCESSIBILITY_ENABLED = "accessibility_enabled";
field public static final deprecated java.lang.String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
field public static final deprecated java.lang.String ADB_ENABLED = "adb_enabled";
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index c5c38f530912..60ec8a96f325 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1570,11 +1570,19 @@ public final class Pm {
private static int showUsage() {
System.err.println("usage: pm path [--user USER_ID] PACKAGE");
System.err.println(" pm dump PACKAGE");
- System.err.println(" pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]");
- System.err.println(" pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
- System.err.println(" [--install-location 0/1/2]");
- System.err.println(" [--force-uuid internal|UUID]");
- System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
+ System.err.println(" pm install [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
+ System.err.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+ System.err.println(" [--originating-uri URI] [---referrer URI]");
+ System.err.println(" [--abi ABI_NAME] [--force-sdk]");
+ System.err.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
+ System.err.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]");
+ System.err.println(" pm install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID]");
+ System.err.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]");
+ System.err.println(" [--originating-uri URI] [---referrer URI]");
+ System.err.println(" [--abi ABI_NAME] [--force-sdk]");
+ System.err.println(" [--preload] [--instantapp] [--full] [--dont-kill]");
+ System.err.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]");
+ System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]");
System.err.println(" pm install-commit SESSION_ID");
System.err.println(" pm install-abandon SESSION_ID");
System.err.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE");
@@ -1613,15 +1621,27 @@ public final class Pm {
System.err.println("pm install: install a single legacy package");
System.err.println("pm install-create: create an install session");
System.err.println(" -l: forward lock application");
- System.err.println(" -r: replace existing application");
+ System.err.println(" -r: allow replacement of existing application");
System.err.println(" -t: allow test packages");
- System.err.println(" -i: specify the installer package name");
+ System.err.println(" -i: specify package name of installer owning the app");
System.err.println(" -s: install application on sdcard");
System.err.println(" -f: install application on internal flash");
System.err.println(" -d: allow version code downgrade (debuggable packages only)");
- System.err.println(" -p: partial application install");
+ System.err.println(" -p: partial application install (new split on top of existing pkg)");
System.err.println(" -g: grant all runtime permissions");
System.err.println(" -S: size in bytes of entire session");
+ System.err.println(" --dont-kill: installing a new feature split, don't kill running app");
+ System.err.println(" --originating-uri: set URI where app was downloaded from");
+ System.err.println(" --referrer: set URI that instigated the install of the app");
+ System.err.println(" --pkg: specify expected package name of app being installed");
+ System.err.println(" --abi: override the default ABI of the platform");
+ System.err.println(" --instantapp: cause the app to be installed as an ephemeral install app");
+ System.err.println(" --full: cause the app to be installed as a non-ephemeral full app");
+ System.err.println(" --install-location: force the install location:");
+ System.err.println(" 0=auto, 1=internal only, 2=prefer external");
+ System.err.println(" --force-uuid: force install on to disk volume with given UUID");
+ System.err.println(" --force-sdk: allow install even when existing app targets platform");
+ System.err.println(" codename but new one targets a final API level");
System.err.println("");
System.err.println("pm install-write: write a package into existing session; path may");
System.err.println(" be '-' to read from stdin");
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 5586057a2e70..4ebca8430cf4 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -21,8 +21,6 @@ cc_library_host_shared {
name: "libstats_proto_host",
srcs: [
"src/stats_events.proto",
- "src/stats_log.proto",
- "src/statsd_config.proto",
],
shared_libs: [
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index d9c37ef0c9b8..a8d3e1268b38 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -14,16 +14,23 @@
LOCAL_PATH:= $(call my-dir)
-
statsd_common_src := \
../../core/java/android/os/IStatsCompanionService.aidl \
../../core/java/android/os/IStatsManager.aidl \
src/stats_log.proto \
src/statsd_config.proto \
- src/stats_events.proto \
+ src/stats_events_copy.proto \
+ src/anomaly/AnomalyMonitor.cpp \
src/condition/CombinationConditionTracker.cpp \
src/condition/condition_util.cpp \
src/condition/SimpleConditionTracker.cpp \
+ src/config/ConfigKey.cpp \
+ src/config/ConfigListener.cpp \
+ src/config/ConfigManager.cpp \
+ src/external/KernelWakelockPuller.cpp \
+ src/external/StatsPullerManager.cpp \
+ src/logd/LogListener.cpp \
+ src/logd/LogReader.cpp \
src/matchers/CombinationLogMatchingTracker.cpp \
src/matchers/matcher_util.cpp \
src/matchers/SimpleLogMatchingTracker.cpp \
@@ -31,17 +38,12 @@ statsd_common_src := \
src/metrics/CountMetricProducer.cpp \
src/metrics/MetricsManager.cpp \
src/metrics/metrics_manager_util.cpp \
- src/AnomalyMonitor.cpp \
- src/DropboxReader.cpp \
- src/DropboxWriter.cpp \
- src/KernelWakelockPuller.cpp \
- src/LogEntryPrinter.cpp \
- src/LogReader.cpp \
+ src/packages/UidMap.cpp \
+ src/storage/DropboxReader.cpp \
+ src/storage/DropboxWriter.cpp \
src/StatsLogProcessor.cpp \
- src/StatsPullerManager.cpp \
src/StatsService.cpp \
- src/stats_util.cpp \
- src/UidMap.cpp
+ src/stats_util.cpp
statsd_common_c_includes := \
$(LOCAL_PATH)/src
@@ -125,13 +127,15 @@ LOCAL_CFLAGS += \
LOCAL_SRC_FILES := \
$(statsd_common_src) \
+ tests/AnomalyMonitor_test.cpp \
+ tests/ConditionTracker_test.cpp \
+ tests/ConfigManager_test.cpp \
tests/indexed_priority_queue_test.cpp \
+ tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
tests/MetricsManager_test.cpp \
- tests/UidMap_test.cpp \
- tests/LogEntryMatcher_test.cpp \
- tests/AnomalyMonitor_test.cpp \
- tests/ConditionTracker_test.cpp
+ tests/UidMap_test.cpp
+
LOCAL_STATIC_LIBRARIES := \
libgmock
diff --git a/cmds/statsd/src/Log.h b/cmds/statsd/src/Log.h
new file mode 100644
index 000000000000..785270973fd0
--- /dev/null
+++ b/cmds/statsd/src/Log.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
+
+#pragma once
+
+#define LOG_TAG "statsd"
+
+#include <log/log.h>
+
+#define VLOG(...) \
+ if (DEBUG) ALOGD(__VA_ARGS__);
diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp
deleted file mode 100644
index 3b6f6791d7f4..000000000000
--- a/cmds/statsd/src/LogEntryPrinter.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <LogEntryPrinter.h>
-
-#include <log/event_tag_map.h>
-#include <log/logprint.h>
-#include <utils/Errors.h>
-
-#include "matchers/matcher_util.h"
-
-#define PRINT_WITH_LIBLOG 0
-#define PRINT_WITH_LOG_EVENT_WRAPPER 1
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-LogEntryPrinter::LogEntryPrinter(int out) : m_out(out) {
- // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
- // If this fails, we can't print well, but something will print.
- m_tags = android_openEventTagMap(NULL);
-
- // Printing format
- m_format = android_log_format_new();
- android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
-}
-
-LogEntryPrinter::~LogEntryPrinter() {
- if (m_tags != NULL) {
- android_closeEventTagMap(m_tags);
- }
- android_log_format_free(m_format);
-}
-
-void LogEntryPrinter::OnLogEvent(const log_msg& msg) {
- if (PRINT_WITH_LIBLOG) {
- status_t err;
- AndroidLogEntry entry;
- char buf[1024];
-
- err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), &entry,
- m_tags, buf, sizeof(buf));
- if (err == NO_ERROR) {
- android_log_printLogLine(m_format, m_out, &entry);
- } else {
- printf("log entry: %s\n", buf);
- fflush(stdout);
- }
- }
-
- if (PRINT_WITH_LOG_EVENT_WRAPPER) {
- LogEventWrapper event = parseLogEvent(msg);
- printf("event: %s\n", event.toString().c_str());
- fflush(stdout);
- }
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f877ef30432c..1308ca1fb4eb 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#include <StatsLogProcessor.h>
+#include "Log.h"
+
+#include "StatsLogProcessor.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "metrics/CountMetricProducer.h"
+#include "stats_util.h"
-#include <cutils/log.h>
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
#include <log/log_event_list.h>
-#include <metrics/CountMetricProducer.h>
#include <utils/Errors.h>
using namespace android;
@@ -31,12 +33,8 @@ namespace android {
namespace os {
namespace statsd {
-StatsLogProcessor::StatsLogProcessor(const sp<UidMap> &uidMap)
- : m_dropbox_writer("all-logs"), m_UidMap(uidMap)
-{
- // hardcoded config
- // this should be called from StatsService when it receives a statsd_config
- UpdateConfig(0, buildFakeConfig());
+StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap)
+ : m_dropbox_writer("all-logs"), mUidMap(uidMap) {
}
StatsLogProcessor::~StatsLogProcessor() {
@@ -54,17 +52,18 @@ void StatsLogProcessor::OnLogEvent(const log_msg& msg) {
}
}
-void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig& config) {
- auto it = mMetricsManagers.find(config_source);
+void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+ auto it = mMetricsManagers.find(key);
if (it != mMetricsManagers.end()) {
it->second->finish();
}
- ALOGD("Updated configuration for source %i", config_source);
+ ALOGD("Updated configuration for key %s", key.ToString().c_str());
unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
if (newMetricsManager->isConfigValid()) {
- mMetricsManagers.insert({config_source, std::move(newMetricsManager)});
+ mMetricsManagers[key] = std::move(newMetricsManager);
+ // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
ALOGD("StatsdConfig valid");
} else {
// If there is any error in the config, don't use it.
@@ -72,6 +71,14 @@ void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig
}
}
+void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
+ auto it = mMetricsManagers.find(key);
+ if (it != mMetricsManagers.end()) {
+ it->second->finish();
+ mMetricsManagers.erase(it);
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 05e441caa496..6f5dd04876e1 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,12 +16,13 @@
#ifndef STATS_LOG_PROCESSOR_H
#define STATS_LOG_PROCESSOR_H
-#include "DropboxWriter.h"
-#include "LogReader.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "config/ConfigListener.h"
+#include "logd/LogReader.h"
#include "metrics/MetricsManager.h"
-#include "stats_util.h"
-#include "UidMap.h"
+#include "packages/UidMap.h"
+#include "storage/DropboxWriter.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <log/logprint.h>
#include <stdio.h>
@@ -31,22 +32,23 @@ namespace android {
namespace os {
namespace statsd {
-class StatsLogProcessor : public LogListener {
+class StatsLogProcessor : public ConfigListener {
public:
StatsLogProcessor(const sp<UidMap> &uidMap);
virtual ~StatsLogProcessor();
virtual void OnLogEvent(const log_msg& msg);
- void UpdateConfig(const int config_source, const StatsdConfig& config);
+ void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
+ void OnConfigRemoved(const ConfigKey& key);
private:
// TODO: use EventMetrics to log the events.
DropboxWriter m_dropbox_writer;
- std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
+ std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
- sp<UidMap> m_UidMap; // Reference to the UidMap to lookup app name and version for each uid.
+ sp<UidMap> mUidMap; // Reference to the UidMap to lookup app name and version for each uid.
};
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b496404962d5..eff2c1cfbcec 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-#define LOG_TAG "statsd"
#define DEBUG true
+#include "Log.h"
#include "StatsService.h"
-#include "DropboxReader.h"
+#include "storage/DropboxReader.h"
#include <android-base/file.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <cutils/log.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <private/android_filesystem_config.h>
#include <utils/Looper.h>
@@ -31,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <sys/system_properties.h>
#include <unistd.h>
using namespace android;
@@ -39,24 +39,65 @@ namespace android {
namespace os {
namespace statsd {
+// ======================================================================
+/**
+ * Watches for the death of the stats companion (system process).
+ */
+class CompanionDeathRecipient : public IBinder::DeathRecipient {
+public:
+ CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor);
+ virtual void binderDied(const wp<IBinder>& who);
+
+private:
+ const sp<AnomalyMonitor> mAnomalyMonitor;
+};
+
+CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor)
+ : mAnomalyMonitor(anomalyMonitor) {
+}
+
+void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
+ ALOGW("statscompanion service died");
+ mAnomalyMonitor->setStatsCompanionService(nullptr);
+}
+
+// ======================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
- : mAnomalyMonitor(new AnomalyMonitor(2)),m_UidMap(new UidMap()), mStatsPullerManager()
- // TODO: Change AnomalyMonitor initialization based on the config
+ : mStatsPullerManager(),
+
+ mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
{
- ALOGD("stats service constructed");
+ mUidMap = new UidMap();
+ mConfigManager = new ConfigManager();
+ mProcessor = new StatsLogProcessor(mUidMap);
+
+ mConfigManager->AddListener(mProcessor);
+
+ init_system_properties();
}
StatsService::~StatsService() {
}
-status_t StatsService::setProcessor(const sp<StatsLogProcessor>& main_processor) {
- m_processor = main_processor;
- ALOGD("stats service set to processor %p", m_processor.get());
- return NO_ERROR;
+void StatsService::init_system_properties() {
+ mEngBuild = false;
+ const prop_info* buildType = __system_property_find("ro.build.type");
+ if (buildType != NULL) {
+ __system_property_read_callback(buildType, init_build_type_callback, this);
+ }
}
-// Implement our own because the default binder implementation isn't
-// properly handling SHELL_COMMAND_TRANSACTION
+void StatsService::init_build_type_callback(void* cookie, const char* /*name*/, const char* value,
+ uint32_t serial) {
+ if (0 == strcmp("eng", value)) {
+ reinterpret_cast<StatsService*>(cookie)->mEngBuild = true;
+ }
+}
+
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
status_t err;
@@ -105,56 +146,159 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
}
}
+/**
+ * Write debugging data about statsd.
+ */
status_t StatsService::dump(int fd, const Vector<String16>& args) {
FILE* out = fdopen(fd, "w");
if (out == NULL) {
return NO_MEMORY; // the fd is already open
}
- fprintf(out, "StatsService::dump:");
- ALOGD("StatsService::dump:");
- const int N = args.size();
- for (int i = 0; i < N; i++) {
- fprintf(out, " %s", String8(args[i]).string());
- ALOGD(" %s", String8(args[i]).string());
- }
- fprintf(out, "\n");
+ // TODO: Proto format for incident reports
+ dump_impl(out);
fclose(out);
return NO_ERROR;
}
+/**
+ * Write debugging data about statsd in text format.
+ */
+void StatsService::dump_impl(FILE* out) {
+ mConfigManager->Dump(out);
+}
+
+/**
+ * Implementation of the adb shell cmd stats command.
+ */
status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
- if (args.size() > 0) {
- if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
- return doPrintStatsLog(out, args);
- }
+ // TODO: Permission check
+
+ const int argCount = args.size();
+ if (argCount >= 1) {
+ // adb shell cmd stats config ...
if (!args[0].compare(String8("config"))) {
- return doLoadConfig(in);
+ return cmd_config(in, out, err, args);
+ }
+
+ // adb shell cmd stats print-stats-log
+ if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
+ return cmd_print_stats_log(out, args);
}
+
+ // adb shell cmd stats print-stats-log
if (!args[0].compare(String8("print-uid-map"))) {
- return doPrintUidMap(out);
+ return cmd_print_uid_map(out);
}
}
- printCmdHelp(out);
+ print_cmd_help(out);
return NO_ERROR;
}
-status_t StatsService::doLoadConfig(FILE* in) {
- string content;
- if (!android::base::ReadFdToString(fileno(in), &content)) {
- return UNKNOWN_ERROR;
+void StatsService::print_cmd_help(FILE* out) {
+ fprintf(out,
+ "usage: adb shell cmd stats print-stats-log [tag_required] "
+ "[timestamp_nsec_optional]\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats print-uid-map \n");
+ fprintf(out, "\n");
+ fprintf(out, " Prints the UID, app name, version mapping.\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
+ fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
+ fprintf(out, "\n");
+ fprintf(out, " Adds, updates or removes a configuration. The proto should be in\n");
+ fprintf(out, " wire-encoded protobuf format and passed via stdin.\n");
+ fprintf(out, "\n");
+ fprintf(out, " UID The uid to use. It is only possible to pass the UID\n");
+ fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
+ fprintf(out, " uid is used.\n");
+ fprintf(out, " NAME The per-uid name to use\n");
+}
+
+status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+ const int argCount = args.size();
+ if (argCount >= 2) {
+ if (args[1] == "update" || args[1] == "remove") {
+ bool good = false;
+ int uid = -1;
+ string name;
+
+ if (argCount == 3) {
+ // Automatically pick the UID
+ uid = IPCThreadState::self()->getCallingUid();
+ // TODO: What if this isn't a binder call? Should we fail?
+ name.assign(args[2].c_str(), args[2].size());
+ good = true;
+ } else if (argCount == 4) {
+ // If it's a userdebug or eng build, then the shell user can
+ // impersonate other uids.
+ if (mEngBuild) {
+ const char* s = args[2].c_str();
+ if (*s != '\0') {
+ char* end = NULL;
+ uid = strtol(s, &end, 0);
+ if (*end == '\0') {
+ name.assign(args[3].c_str(), args[3].size());
+ good = true;
+ }
+ }
+ } else {
+ fprintf(err, "The config can only be set for other UIDs on eng builds.\n");
+ }
+ }
+
+ if (!good) {
+ // If arg parsing failed, print the help text and return an error.
+ print_cmd_help(out);
+ return UNKNOWN_ERROR;
+ }
+
+ if (args[1] == "update") {
+ // Read stream into buffer.
+ string buffer;
+ if (!android::base::ReadFdToString(fileno(in), &buffer)) {
+ fprintf(err, "Error reading stream for StatsConfig.\n");
+ return UNKNOWN_ERROR;
+ }
+
+ // Parse buffer.
+ StatsdConfig config;
+ if (!config.ParseFromString(buffer)) {
+ fprintf(err, "Error parsing proto stream for StatsConfig.\n");
+ return UNKNOWN_ERROR;
+ }
+
+ // Add / update the config.
+ mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
+ } else {
+ // Remove the config.
+ mConfigManager->RemoveConfig(ConfigKey(uid, name));
+ }
+
+ return NO_ERROR;
+ }
}
- StatsdConfig config;
- if (config.ParseFromString(content)) {
- ALOGD("Config parsed from command line: %s", config.SerializeAsString().c_str());
- m_processor->UpdateConfig(0, config);
- return NO_ERROR;
- } else {
- ALOGD("Config failed to be parsed");
- return UNKNOWN_ERROR;
+ print_cmd_help(out);
+ return UNKNOWN_ERROR;
+}
+
+status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
+ long msec = 0;
+
+ if (args.size() > 2) {
+ msec = strtol(args[2].string(), NULL, 10);
}
+ return DropboxReader::readStatsLogs(out, args[1].string(), msec);
+}
+
+status_t StatsService::cmd_print_uid_map(FILE* out) {
+ mUidMap->printUidMap(out);
+ return NO_ERROR;
}
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
@@ -166,7 +310,7 @@ Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<i
"Only system uid can call informAllUidData");
}
- m_UidMap->updateMap(uid, version, app);
+ mUidMap->updateMap(uid, version, app);
if (DEBUG) ALOGD("StatsService::informAllUidData succeeded");
return Status::ok();
@@ -179,7 +323,7 @@ Status StatsService::informOnePackage(const String16& app, int32_t uid, int32_t
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informOnePackage");
}
- m_UidMap->updateApp(app, uid, version);
+ mUidMap->updateApp(app, uid, version);
return Status::ok();
}
@@ -190,7 +334,7 @@ Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
return Status::fromExceptionCode(Status::EX_SECURITY,
"Only system uid can call informOnePackageRemoved");
}
- m_UidMap->removeApp(app, uid);
+ mUidMap->removeApp(app, uid);
return Status::ok();
}
@@ -282,38 +426,18 @@ Status StatsService::statsCompanionReady() {
"statscompanion unavailable despite it contacting statsd!");
}
if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
- IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor));
+ IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(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;
-
- if (args.size() > 2) {
- msec = strtol(args[2].string(), NULL, 10);
- }
- return DropboxReader::readStatsLogs(out, args[1].string(), msec);
-}
-
-status_t StatsService::doPrintUidMap(FILE* out) {
- m_UidMap->printUidMap(out);
- return NO_ERROR;
+void StatsService::Startup() {
+ mConfigManager->Startup();
}
-void StatsService::printCmdHelp(FILE* out) {
- fprintf(out, "Usage:\n");
- fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
- fprintf(out, "\t print-uid-map Prints the UID, app name, version mapping.\n");
- fprintf(out,
- "\t config\t Loads a new config from command-line (must be proto in wire-encoded "
- "format).\n");
+void StatsService::OnLogEvent(const log_msg& msg) {
+ mProcessor->OnLogEvent(msg);
}
} // namespace statsd
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 541f7e8be7fa..dcc73a1d4788 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -17,11 +17,11 @@
#ifndef STATS_SERVICE_H
#define STATS_SERVICE_H
-#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"
-#include "StatsPullerManager.h"
-#include "StatsPuller.h"
-#include "UidMap.h"
+#include "anomaly/AnomalyMonitor.h"
+#include "config/ConfigManager.h"
+#include "external/StatsPullerManager.h"
+#include "packages/UidMap.h"
#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
@@ -42,75 +42,114 @@ namespace android {
namespace os {
namespace statsd {
-class StatsService : public BnStatsManager {
+class StatsService : public BnStatsManager, public LogListener {
public:
StatsService(const sp<Looper>& handlerLooper);
virtual ~StatsService();
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
virtual status_t dump(int fd, const Vector<String16>& args);
-
virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
virtual Status systemRunning();
-
- // Inform statsd that statsCompanion is ready.
virtual Status statsCompanionReady();
-
virtual Status informAnomalyAlarmFired();
-
virtual Status informPollAlarmFired();
-
virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
const vector<String16>& app);
virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
- virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
+ /**
+ * Called right before we start processing events.
+ */
+ void Startup();
+
+ /**
+ * Called by LogReader when there's a log event to process.
+ */
+ virtual void OnLogEvent(const log_msg& msg);
// 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();
- // TODO: Move this to a more logical file/class
- // TODO: Should be private. Temporarily public for testing purposes only.
- const sp<AnomalyMonitor> mAnomalyMonitor;
-
- sp<UidMap> getUidMap() {
- return m_UidMap;
- }
-
/** Fetches and returns the StatsCompanionService. */
static sp<IStatsCompanionService> getStatsCompanionService();
private:
- sp<UidMap> m_UidMap; // Reference to the UID map needed for translating UID to app name/version.
-
- sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.
-
- status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
-
- void printCmdHelp(FILE* out);
-
- status_t doLoadConfig(FILE* in);
-
+ /**
+ * Load system properties at init.
+ */
+ void init_system_properties();
+
+ /**
+ * Helper for loading system properties.
+ */
+ static void init_build_type_callback(void* cookie, const char* name, const char* value,
+ uint32_t serial);
+
+ /**
+ * Text output of dumpsys.
+ */
+ void dump_impl(FILE* out);
+
+ /**
+ * Print usage information for the commands
+ */
+ void print_cmd_help(FILE* out);
+
+ /**
+ * Handle the config sub-command.
+ */
+ status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+
+ /**
+ * Print the event log.
+ */
+ status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
+
+ /**
+ * Print the mapping of uids to package names.
+ */
+ status_t cmd_print_uid_map(FILE* out);
+
+ /**
+ * Update a configuration.
+ */
+ void set_config(int uid, const string& name, const StatsdConfig& config);
+
+ /**
+ * Tracks the uid <--> package name mapping.
+ */
+ sp<UidMap> mUidMap;
+
+ /**
+ * Fetches external metrics.
+ * TODO: This should be an sp<>
+ */
StatsPullerManager mStatsPullerManager;
- status_t doPrintUidMap(FILE* out);
-};
+ /**
+ * Tracks the configurations that have been passed to statsd.
+ */
+ sp<ConfigManager> mConfigManager;
-// --- StatsdDeathRecipient ---
-class StatsdDeathRecipient : public IBinder::DeathRecipient {
-public:
- StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor) : mAnmlyMntr(anomalyMonitor) {
- }
+ /**
+ * The metrics recorder.
+ */
+ sp<StatsLogProcessor> mProcessor;
- virtual void binderDied(const wp<IBinder>& who);
+ /**
+ * The anomaly detector.
+ */
+ const sp<AnomalyMonitor> mAnomalyMonitor;
-private:
- const sp<AnomalyMonitor> mAnmlyMntr;
+ /**
+ * Whether this is an eng build.
+ */
+ bool mEngBuild;
};
} // namespace statsd
diff --git a/cmds/statsd/src/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 4fbbc7a2267f..7a464104fb09 100644
--- a/cmds/statsd/src/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -14,12 +14,10 @@
* limitations under the License.
*/
-#define LOG_TAG "AnomalyMonitor"
#define DEBUG true
+#include "Log.h"
-#include "AnomalyMonitor.h"
-
-#include <cutils/log.h>
+#include "anomaly/AnomalyMonitor.h"
namespace android {
namespace os {
@@ -92,17 +90,16 @@ void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
// More efficient than repeatedly calling remove(mPq.top()) since it batches the
// updates to the registered alarm.
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
- AnomalyMonitor::popSoonerThan(uint32_t timestampSec) {
-
+unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
+ uint32_t timestampSec) {
if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
std::lock_guard<std::mutex> lock(mLock);
- for (sp<const AnomalyAlarm> t = mPq.top();
- t != nullptr && t->timestampSec <= timestampSec; t = mPq.top()) {
+ for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
+ t = mPq.top()) {
oldAlarms.insert(t);
- mPq.pop(); // remove t
+ mPq.pop(); // remove t
}
// Always update registered alarm time (if anything has changed).
if (!oldAlarms.empty()) {
diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
index 7c6e5e8945a7..e2ac623c4670 100644
--- a/cmds/statsd/src/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -17,12 +17,13 @@
#ifndef ANOMALY_MONITOR_H
#define ANOMALY_MONITOR_H
+#include "anomaly/indexed_priority_queue.h"
+
#include <android/os/IStatsCompanionService.h>
-#include <indexed_priority_queue.h>
#include <utils/RefBase.h>
-#include <unordered_set>
#include <queue>
+#include <unordered_set>
#include <vector>
using namespace android;
@@ -91,8 +92,8 @@ public:
* Returns and removes all alarms whose timestamp <= the given timestampSec.
* Always updates the registered alarm if return is non-empty.
*/
- unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
- popSoonerThan(uint32_t timestampSec);
+ unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
+ uint32_t timestampSec);
/**
* Returns the projected alarm timestamp that is registered with
@@ -144,4 +145,4 @@ private:
} // namespace os
} // namespace android
-#endif // ANOMALY_MONITOR_H \ No newline at end of file
+#endif // ANOMALY_MONITOR_H
diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
index 81e8b3d023ea..1a2e9c2a41ed 100644
--- a/cmds/statsd/src/indexed_priority_queue.h
+++ b/cmds/statsd/src/anomaly/indexed_priority_queue.h
@@ -14,15 +14,10 @@
* limitations under the License.
*/
-#ifndef STATSD_INDEXED_PRIORITY_QUEUE_H
-#define STATSD_INDEXED_PRIORITY_QUEUE_H
+#pragma once
-// 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 "Log.h"
-#include <cutils/log.h>
#include <utils/RefBase.h>
#include <unordered_map>
#include <vector>
@@ -132,23 +127,23 @@ void indexed_priority_queue<AA, Comparator>::remove(sp<const AA> a) {
// The same as, but slightly more efficient than, remove(top()).
template <class AA, class Comparator>
void indexed_priority_queue<AA, Comparator>::pop() {
- sp<const AA> a = top();
- if (a == nullptr) return;
- const size_t idx = 1;
- if (idx == size()) { // if a is the last element
+ sp<const AA> a = top();
+ if (a == nullptr) return;
+ const size_t idx = 1;
+ if (idx == size()) { // if a is the last element
+ 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);
- 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_down(idx);
+
+ // get the heap back in order (since the element at idx is not in order)
+ sift_down(idx);
}
template <class AA, class Comparator>
@@ -227,5 +222,3 @@ void indexed_priority_queue<AA, Comparator>::swap_indices(size_t i, size_t j) {
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATSD_INDEXED_PRIORITY_QUEUE_H
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 6188383d4e8d..c3a06bcbf971 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -13,23 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "CombinationConditionTracker"
+
#define DEBUG true // STOPSHIP if true
-#define VLOG(...) \
- if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
#include "CombinationConditionTracker.h"
-#include <cutils/log.h>
+
#include <log/logprint.h>
-using std::string;
-using std::unique_ptr;
-using std::unordered_map;
-using std::vector;
namespace android {
namespace os {
namespace statsd {
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
: ConditionTracker(name, index) {
VLOG("creating CombinationConditionTracker %s", mName.c_str());
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 2da8fa0e8655..9554e0a894ef 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-#ifndef CONDITION_TRACKER_H
-#define CONDITION_TRACKER_H
+#pragma once
+
+#include "Log.h"
+
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
-#include <cutils/log.h>
#include <log/logprint.h>
#include <utils/RefBase.h>
+
#include <unordered_map>
-#include "../matchers/LogMatchingTracker.h"
-#include "../matchers/matcher_util.h"
-#include "condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
namespace os {
@@ -102,4 +104,3 @@ protected:
} // namespace os
} // namespace android
-#endif // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index e78c0de7bdf5..694908dbb6cb 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -14,24 +14,22 @@
* limitations under the License.
*/
-#define LOG_TAG "Stats_SimpleConditionTracker"
#define DEBUG true // STOPSHIP if true
-#define VLOG(...) \
- if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
#include "SimpleConditionTracker.h"
-#include <cutils/log.h>
+
#include <log/logprint.h>
+namespace android {
+namespace os {
+namespace statsd {
+
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
-namespace android {
-namespace os {
-namespace statsd {
-
SimpleConditionTracker::SimpleConditionTracker(
const string& name, const int index, const SimpleCondition& simpleCondition,
const unordered_map<string, int>& trackerNameIndexMap)
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index cb07d1530dab..c7c8fcc9b361 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -14,9 +14,10 @@
* limitations under the License.
*/
+#include "Log.h"
+
#include "condition_util.h"
-#include <cutils/log.h>
#include <log/event_tag_map.h>
#include <log/log_event_list.h>
#include <log/logprint.h>
@@ -27,14 +28,15 @@
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
+namespace android {
+namespace os {
+namespace statsd {
+
using std::set;
using std::string;
using std::unordered_map;
using std::vector;
-namespace android {
-namespace os {
-namespace statsd {
ConditionState evaluateCombinationCondition(const std::vector<int>& children,
const LogicalOperation& operation,
diff --git a/cmds/statsd/src/config/ConfigKey.cpp b/cmds/statsd/src/config/ConfigKey.cpp
new file mode 100644
index 000000000000..a365dc0b9189
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigKey.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "config/ConfigKey.h"
+
+#include <sstream>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::ostringstream;
+
+ConfigKey::ConfigKey() {
+}
+
+ConfigKey::ConfigKey(const ConfigKey& that) : mName(that.mName), mUid(that.mUid) {
+}
+
+ConfigKey::ConfigKey(int uid, const string& name) : mName(name), mUid(uid) {
+}
+
+ConfigKey::~ConfigKey() {
+}
+
+string ConfigKey::ToString() const {
+ ostringstream out;
+ out << '(' << mUid << ',' << mName << ')';
+ return out.str();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
new file mode 100644
index 000000000000..bbf20fd1acf7
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <functional>
+#include <iostream>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::hash;
+using std::ostream;
+using std::string;
+
+/**
+ * Uniquely identifies a configuration.
+ */
+class ConfigKey {
+public:
+ ConfigKey();
+ explicit ConfigKey(const ConfigKey& that);
+ ConfigKey(int uid, const string& name);
+ ~ConfigKey();
+
+ inline int GetUid() const {
+ return mUid;
+ }
+ inline const string& GetName() const {
+ return mName;
+ }
+
+ inline bool operator<(const ConfigKey& that) const {
+ if (mUid < that.mUid) {
+ return true;
+ }
+ if (mUid > that.mUid) {
+ return false;
+ }
+ return mName < that.mName;
+ };
+
+ inline bool operator==(const ConfigKey& that) const {
+ return mUid == that.mUid && mName == that.mName;
+ };
+
+ string ToString() const;
+
+private:
+ string mName;
+ int mUid;
+};
+
+inline ostream& operator<<(ostream& os, const ConfigKey& config) {
+ return os << config.ToString();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+/**
+ * A hash function for ConfigKey so it can be used for unordered_map/set.
+ * Unfortunately this hast to go in std namespace because C++ is fun!
+ */
+namespace std {
+
+using android::os::statsd::ConfigKey;
+
+template <>
+struct hash<ConfigKey> {
+ std::size_t operator()(const ConfigKey& key) const {
+ return (7 * key.GetUid()) ^ ((hash<string>()(key.GetName())));
+ }
+};
+
+} // namespace std
diff --git a/cmds/statsd/src/config/ConfigListener.cpp b/cmds/statsd/src/config/ConfigListener.cpp
new file mode 100644
index 000000000000..21a3f1673fd7
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigListener.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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 "config/ConfigListener.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+ConfigListener::ConfigListener() {
+}
+
+ConfigListener::~ConfigListener() {
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
new file mode 100644
index 000000000000..a58766d2a382
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include "config/ConfigKey.h"
+
+#include <utils/RefBase.h>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+
+/**
+ * Callback for different subsystems inside statsd to implement to find out
+ * when a configuration has been added, updated or removed.
+ */
+class ConfigListener : public virtual RefBase {
+public:
+ ConfigListener();
+ virtual ~ConfigListener();
+
+ /**
+ * A configuration was added or updated.
+ */
+ virtual void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) = 0;
+
+ /**
+ * A configuration was removed.
+ */
+ virtual void OnConfigRemoved(const ConfigKey& key) = 0;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
new file mode 100644
index 000000000000..2a4d6e22a2ed
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -0,0 +1,251 @@
+/*
+ * 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 "config/ConfigManager.h"
+
+#include "stats_util.h"
+
+#include <vector>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static StatsdConfig build_fake_config();
+
+ConfigManager::ConfigManager() {
+}
+
+ConfigManager::~ConfigManager() {
+}
+
+void ConfigManager::Startup() {
+ // TODO: Implement me -- read from storage and call onto all of the listeners.
+ // Instead, we'll just make a fake one.
+
+ // this should be called from StatsService when it receives a statsd_config
+ UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
+}
+
+void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+ mListeners.push_back(listener);
+}
+
+void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
+ // Add to map
+ mConfigs[key] = config;
+ // Why doesn't this work? mConfigs.insert({key, config});
+
+ // Save to disk
+ update_saved_configs();
+
+ // Tell everyone
+ for (auto& listener : mListeners) {
+ listener->OnConfigUpdated(key, config);
+ }
+}
+
+void ConfigManager::RemoveConfig(const ConfigKey& key) {
+ unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
+ if (it != mConfigs.end()) {
+ // Remove from map
+ mConfigs.erase(it);
+
+ // Save to disk
+ update_saved_configs();
+
+ // Tell everyone
+ for (auto& listener : mListeners) {
+ listener->OnConfigRemoved(key);
+ }
+ }
+ // If we didn't find it, just quietly ignore it.
+}
+
+void ConfigManager::RemoveConfigs(int uid) {
+ vector<ConfigKey> removed;
+
+ for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+ // Remove from map
+ if (it->first.GetUid() == uid) {
+ removed.push_back(it->first);
+ it = mConfigs.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ // Remove separately so if they do anything in the callback they can't mess up our iteration.
+ for (auto& key : removed) {
+ // Tell everyone
+ for (auto& listener : mListeners) {
+ listener->OnConfigRemoved(key);
+ }
+ }
+}
+
+void ConfigManager::Dump(FILE* out) {
+ fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
+ fprintf(out, " uid name\n");
+ for (unordered_map<ConfigKey, StatsdConfig>::const_iterator it = mConfigs.begin();
+ it != mConfigs.end(); it++) {
+ fprintf(out, " %6d %s\n", it->first.GetUid(), it->first.GetName().c_str());
+ // TODO: Print the contents of the config too.
+ }
+}
+
+void ConfigManager::update_saved_configs() {
+ // TODO: Implement me -- write to disk.
+}
+
+static StatsdConfig build_fake_config() {
+ // HACK: Hard code a test metric for counting screen on events...
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ // One count metric to count screen on
+ CountMetric* metric = config.add_count_metric();
+ metric->set_metric_id(20150717L);
+ metric->set_what("SCREEN_IS_ON");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+ // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
+ metric = config.add_count_metric();
+ metric->set_metric_id(20150718L);
+ metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
+ metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+ metric->set_condition("SCREEN_IS_ON");
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_ON");
+
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("SCREEN_IS_OFF");
+
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+ simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+ 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+ LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_CRASH");
+
+ SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+ keyValueMatcher->set_eq_int(2);
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_START");
+
+ simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1 /*STATE*/);
+ keyValueMatcher->set_eq_int(1);
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
+ LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
+ combinationMatcher->set_operation(LogicalOperation::OR);
+ combinationMatcher->add_matcher("PHOTO_START");
+ combinationMatcher->add_matcher("PHOTO_CRASH");
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("CHROME_CRASH");
+
+ simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+ keyValueMatcher->set_eq_string(
+ "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+ keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+ keyValueMatcher->mutable_key_matcher()->set_key(1 /*STATE*/);
+ keyValueMatcher->set_eq_int(2);
+
+ procEventMatcher = config.add_log_entry_matcher();
+ procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
+ combinationMatcher = procEventMatcher->mutable_combination();
+ combinationMatcher->set_operation(LogicalOperation::OR);
+ combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
+ combinationMatcher->add_matcher("CHROME_CRASH");
+
+ Condition* condition = config.add_condition();
+ condition->set_name("SCREEN_IS_ON");
+ SimpleCondition* simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("SCREEN_IS_ON");
+ simpleCondition->set_stop("SCREEN_IS_OFF");
+
+ condition = config.add_condition();
+ condition->set_name("PHOTO_STARTED");
+
+ simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("PHOTO_START");
+ simpleCondition->set_stop("PHOTO_CRASH");
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_OFF");
+
+ simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("SCREEN_IS_OFF");
+ simpleCondition->set_stop("SCREEN_IS_ON");
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+
+ Condition_Combination* combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_condition("SCREEN_IS_ON");
+ combination->add_condition("SCREEN_IS_OFF");
+
+ condition = config.add_condition();
+ condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
+
+ combination = condition->mutable_combination();
+ combination->set_operation(LogicalOperation::NOR);
+ combination->add_condition("SCREEN_IS_ON");
+ combination->add_condition("SCREEN_IS_OFF");
+
+ return config;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
new file mode 100644
index 000000000000..5d73eaf3c7b6
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "config/ConfigListener.h"
+
+#include <string>
+#include <unordered_map>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+/**
+ * Keeps track of which configurations have been set from various sources.
+ *
+ * TODO: Store the configs persistently too.
+ * TODO: Dump method for debugging.
+ */
+class ConfigManager : public virtual RefBase {
+public:
+ ConfigManager();
+ virtual ~ConfigManager();
+
+ /**
+ * Call to load the saved configs from disk.
+ *
+ * TODO: Implement me
+ */
+ void Startup();
+
+ /**
+ * Someone else wants to know about the configs.
+ */
+ void AddListener(const sp<ConfigListener>& listener);
+
+ /**
+ * A configuration was added or updated.
+ *
+ * Reports this to listeners.
+ */
+ void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
+
+ /**
+ * A configuration was removed.
+ *
+ * Reports this to listeners.
+ */
+ void RemoveConfig(const ConfigKey& key);
+
+ /**
+ * Remove all of the configs for the given uid.
+ */
+ void RemoveConfigs(int uid);
+
+ /**
+ * Text dump of our state for debugging.
+ */
+ void Dump(FILE* out);
+
+private:
+ /**
+ * Save the configs to disk.
+ */
+ void update_saved_configs();
+
+ /**
+ * The Configs that have been set
+ */
+ unordered_map<ConfigKey, StatsdConfig> mConfigs;
+
+ /**
+ * The ConfigListeners that will be told about changes.
+ */
+ vector<sp<ConfigListener>> mListeners;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
index 1798f9dec5ef..b9abee0d5df1 100644
--- a/cmds/statsd/src/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include "KernelWakelockPuller.h"
+#include "Log.h"
+
#include <android/os/IStatsCompanionService.h>
#include <binder/IPCThreadState.h>
-#include <cutils/log.h>
#include <private/android_filesystem_config.h>
-#include "StatsPuller.h"
#include "StatsService.h"
+#include "external/KernelWakelockPuller.h"
+#include "external/StatsPuller.h"
using namespace android;
using namespace android::base;
@@ -40,15 +41,15 @@ String16 KernelWakelockPuller::pull() {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
String16 returned_value("");
if (statsCompanion != NULL) {
- Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
- &returned_value);
- if (!status.isOk()) {
- ALOGW("error pulling kernel wakelock");
- }
- ALOGD("KernelWakelockPuller::pull succeeded!");
- // TODO: remove this when we integrate into aggregation chain.
- ALOGD("%s", String8(returned_value).string());
- return returned_value;
+ Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
+ &returned_value);
+ if (!status.isOk()) {
+ ALOGW("error pulling kernel wakelock");
+ }
+ ALOGD("KernelWakelockPuller::pull succeeded!");
+ // TODO: remove this when we integrate into aggregation chain.
+ ALOGD("%s", String8(returned_value).string());
+ return returned_value;
} else {
ALOGW("statsCompanion not found!");
return String16();
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
index 1c16f8703082..1ec33762bd49 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -18,7 +18,7 @@
#define STATSD_KERNELWAKELOCKPULLER_H
#include <utils/String16.h>
-#include "StatsPuller.h"
+#include "external/StatsPuller.h"
namespace android {
namespace os {
diff --git a/cmds/statsd/src/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 5e556b89b521..5e556b89b521 100644
--- a/cmds/statsd/src/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
diff --git a/cmds/statsd/src/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index f4cf1ceaf18a..6e8d58bc33ad 100644
--- a/cmds/statsd/src/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-#define LOG_TAG "StatsPullerManager"
#define DEBUG true
+#include "Log.h"
-#include "StatsPullerManager.h"
#include <android/os/IStatsCompanionService.h>
-#include <cutils/log.h>
-#include "StatsService.h"
#include "KernelWakelockPuller.h"
-
+#include "StatsService.h"
+#include "external/StatsPullerManager.h"
using namespace android;
diff --git a/cmds/statsd/src/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index ab36df535ae5..f143424e7b76 100644
--- a/cmds/statsd/src/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -19,7 +19,7 @@
#include <utils/String16.h>
#include <unordered_map>
-#include "StatsPuller.h"
+#include "external/StatsPuller.h"
namespace android {
namespace os {
@@ -41,7 +41,6 @@ private:
std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
};
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/logd/LogListener.cpp b/cmds/statsd/src/logd/LogListener.cpp
new file mode 100644
index 000000000000..6ac7978bbac9
--- /dev/null
+++ b/cmds/statsd/src/logd/LogListener.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "logd/LogReader.h"
+
+#include <log/log_read.h>
+
+#include <utils/Errors.h>
+
+#include <time.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+LogListener::LogListener() {
+}
+
+LogListener::~LogListener() {
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/logd/LogListener.h
index 4f79028889c9..786a79305296 100644
--- a/cmds/statsd/src/LogEntryPrinter.h
+++ b/cmds/statsd/src/logd/LogListener.h
@@ -14,48 +14,29 @@
* limitations under the License.
*/
-#ifndef LOG_ENTRY_PRINTER_H
-#define LOG_ENTRY_PRINTER_H
+#pragma once
-#include "LogReader.h"
-
-#include <log/logprint.h>
-
-#include <stdio.h>
+#include <log/log_read.h>
+#include <utils/RefBase.h>
+#include <vector>
namespace android {
namespace os {
namespace statsd {
/**
- * Decodes the log entry and prints it to the supplied file descriptor.
+ * Callback for LogReader
*/
-class LogEntryPrinter : public LogListener {
+class LogListener : public virtual android::RefBase {
public:
- LogEntryPrinter(int out);
- virtual ~LogEntryPrinter();
-
- virtual void OnLogEvent(const log_msg& msg);
+ LogListener();
+ virtual ~LogListener();
-private:
- /**
- * Where to write to.
- */
- int m_out;
-
- /**
- * Numeric to string tag name mapping.
- */
- EventTagMap* m_tags;
-
- /**
- * Pretty printing format.
- */
- AndroidLogFormat* m_format;
+ // TODO: Rather than using log_msg, which doesn't have any real internal structure
+ // here, we should pull this out into our own LogEntry class.
+ virtual void OnLogEvent(const log_msg& msg) = 0;
};
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // LOG_ENTRY_PRINTER_H
diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp
index c4ac33724bc7..23d3698aff0c 100644
--- a/cmds/statsd/src/LogReader.cpp
+++ b/cmds/statsd/src/logd/LogReader.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "LogReader.h"
+#include "logd/LogReader.h"
#include <log/log_read.h>
@@ -33,24 +33,12 @@ namespace statsd {
#define SNOOZE_INITIAL_MS 100
#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes
-// ================================================================================
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-// ================================================================================
-LogReader::LogReader() {
+LogReader::LogReader(const sp<LogListener>& listener) : mListener(listener) {
}
LogReader::~LogReader() {
}
-void LogReader::AddListener(const sp<LogListener>& listener) {
- m_listeners.push_back(listener);
-}
-
void LogReader::Run() {
int nextSnoozeMs = SNOOZE_INITIAL_MS;
@@ -119,11 +107,8 @@ int LogReader::connect_and_read() {
// Record that we read one (used above to know how to snooze).
lineCount++;
- // Call the listeners
- for (vector<sp<LogListener> >::iterator it = m_listeners.begin();
- it != m_listeners.end(); it++) {
- (*it)->OnLogEvent(msg);
- }
+ // Call the listener
+ mListener->OnLogEvent(msg);
}
}
diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/logd/LogReader.h
index fc19585ac6f0..6ca0646eae6b 100644
--- a/cmds/statsd/src/LogReader.h
+++ b/cmds/statsd/src/logd/LogReader.h
@@ -17,6 +17,8 @@
#ifndef LOGREADER_H
#define LOGREADER_H
+#include "logd/LogListener.h"
+
#include <log/log_read.h>
#include <utils/RefBase.h>
@@ -27,27 +29,14 @@ namespace os {
namespace statsd {
/**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
- LogListener();
- virtual ~LogListener();
-
- // TODO: Rather than using log_msg, which doesn't have any real internal structure
- // here, we should pull this out into our own LogEntry class.
- virtual void OnLogEvent(const log_msg& msg) = 0;
-};
-
-/**
* Class to read logs from logd.
*/
class LogReader : public virtual android::RefBase {
public:
/**
- * Construct the LogReader with a pointer back to the StatsService
+ * Construct the LogReader with the event listener. (Which is StatsService)
*/
- LogReader();
+ LogReader(const sp<LogListener>& listener);
/**
* Destructor.
@@ -55,20 +44,15 @@ public:
virtual ~LogReader();
/**
- * Add a LogListener class.
- */
- void AddListener(const android::sp<LogListener>& listener);
-
- /**
* Run the main LogReader loop
*/
void Run();
private:
/**
- * List of listeners to call back on when we do get an event.
+ * Who is going to get the events when they're read.
*/
- std::vector<android::sp<LogListener> > m_listeners;
+ sp<LogListener> mListener;
/**
* Connect to a single instance of logd, and read until there's a read error.
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 37477dc50e4e..a7402800630e 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -14,20 +14,16 @@
* limitations under the License.
*/
-#define LOG_TAG "statsd"
+#include "Log.h"
-#include "LogEntryPrinter.h"
-#include "LogReader.h"
-#include "StatsLogProcessor.h"
#include "StatsService.h"
-#include "UidMap.h"
+#include "logd/LogReader.h"
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
-#include <cutils/log.h>
#include <utils/Looper.h>
#include <utils/StrongPointer.h>
@@ -53,16 +49,12 @@ struct log_reader_thread_data {
static void* log_reader_thread_func(void* cookie) {
log_reader_thread_data* data = static_cast<log_reader_thread_data*>(cookie);
- sp<LogReader> reader = new LogReader();
+ sp<LogReader> reader = new LogReader(data->service);
- // Put the printer one first, so it will print before the real ones.
- reader->AddListener(new LogEntryPrinter(STDOUT_FILENO));
- sp<StatsLogProcessor> main_processor = new StatsLogProcessor(data->service->getUidMap());
- data->service->setProcessor(main_processor);
- reader->AddListener(main_processor);
-
- // TODO: Construct and add real LogListners here.
+ // Tell StatsService that we're ready to go.
+ data->service->Startup();
+ // Run the read loop. Never returns.
reader->Run();
ALOGW("statsd LogReader.Run() is not supposed to return.");
@@ -127,6 +119,8 @@ int main(int /*argc*/, char** /*argv*/) {
// 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).
+ // TODO: Are you sure? Don't we need to reconnect to the system process if we get restarted?
+ // --joeo
service->sayHiToStatsCompanion();
// Start the log reader thread
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index 9f9b648ae1a5..f1e0d5aed4c5 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -14,20 +14,21 @@
* limitations under the License.
*/
+#include "Log.h"
+
#include "CombinationLogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
-#include <cutils/log.h>
-#include "matcher_util.h"
using std::set;
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
-namespace android {
-namespace os {
-namespace statsd {
-
CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
: LogMatchingTracker(name, index) {
}
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 1c83039072da..815baf77e5a5 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-#define LOG_TAG "SimpleLogMatchingTracker"
#define DEBUG true // STOPSHIP if true
-#define VLOG(...) \
- if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
#include "SimpleLogMatchingTracker.h"
-#include <cutils/log.h>
+
#include <log/logprint.h>
+namespace android {
+namespace os {
+namespace statsd {
+
using std::string;
using std::unique_ptr;
using std::unordered_map;
using std::vector;
-namespace android {
-namespace os {
-namespace statsd {
SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
const SimpleLogEntryMatcher& matcher)
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 3308f3aeb318..ce0576cc082b 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-#include "matcher_util.h"
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
+
#include <log/event_tag_map.h>
#include <log/log_event_list.h>
#include <log/logprint.h>
#include <utils/Errors.h>
-#include <unordered_map>
-#include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
#include <sstream>
+#include <unordered_map>
using std::set;
using std::string;
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
index ebd53e056249..e1c2b8b3a90e 100644
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
+++ b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#define LOG_TAG "CountAnomaly"
#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
#define VLOG(...) \
if (DEBUG) ALOGD(__VA_ARGS__);
#include "CountAnomalyTracker.h"
-#include <cutils/log.h>
-
namespace android {
namespace os {
namespace statsd {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e98999e73223..68d0a30403b0 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -14,10 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "CountMetric"
#define DEBUG true // STOPSHIP if true
-#define VLOG(...) \
- if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
#include "CountMetricProducer.h"
#include "CountAnomalyTracker.h"
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 6c39d98281ca..7bc7f978d782 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -17,10 +17,11 @@
#ifndef METRIC_PRODUCER_H
#define METRIC_PRODUCER_H
+#include "matchers/matcher_util.h"
+#include "packages/PackageInfoListener.h"
+
#include <log/logprint.h>
#include <utils/RefBase.h>
-#include "../matchers/matcher_util.h"
-#include "PackageInfoListener.h"
namespace android {
namespace os {
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1e65f5888233..b77daf107503 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "MetricManager"
#define DEBUG true // STOPSHIP if true
+#include "Log.h"
#define VLOG(...) \
if (DEBUG) ALOGD(__VA_ARGS__);
#include "MetricsManager.h"
-#include <cutils/log.h>
#include <log/logprint.h>
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 70c34db6b80a..2f3fad930bd6 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -14,16 +14,15 @@
* limitations under the License.
*/
-#ifndef METRICS_MANAGER_H
-#define METRICS_MANAGER_H
+#pragma once
+
+#include "condition/ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "metrics/MetricProducer.h"
-#include <cutils/log.h>
#include <log/logprint.h>
#include <unordered_map>
-#include "../condition/ConditionTracker.h"
-#include "../matchers/LogMatchingTracker.h"
-#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
namespace android {
namespace os {
@@ -94,4 +93,3 @@ private:
} // namespace os
} // namespace android
-#endif // METRICS_MANAGER_H
diff --git a/cmds/statsd/src/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 476c1d953cbc..8b948dee887e 100644
--- a/cmds/statsd/src/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -35,4 +35,4 @@ public:
} // namespace os
} // namespace android
-#endif //STATSD_PACKAGE_INFO_LISTENER_H
+#endif // STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 76a7f3f28dee..f4621ee15dbe 100644
--- a/cmds/statsd/src/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#include "UidMap.h"
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "packages/UidMap.h"
+
#include <utils/Errors.h>
using namespace android;
@@ -48,18 +50,18 @@ int UidMap::getAppVersion(int uid, const string& packageName) const {
return 0;
}
-void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &versionCode,
- const vector <String16> &packageName) {
- lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
+void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+ const vector<String16>& packageName) {
+ lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
mMap.clear();
- for (unsigned long j=0; j<uid.size(); j++) {
- mMap.insert(make_pair(uid[j], AppData(string(String8(packageName[j]).string()),
- versionCode[j])));
+ for (unsigned long j = 0; j < uid.size(); j++) {
+ mMap.insert(make_pair(uid[j],
+ AppData(string(String8(packageName[j]).string()), versionCode[j])));
}
- if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
- for (unsigned long j=0; j<uid.size(); j++) {
+ if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
+ for (unsigned long j = 0; j < uid.size(); j++) {
auto t = mOutput.add_initial();
t->set_app(string(String8(packageName[j]).string()));
t->set_version(int(versionCode[j]));
@@ -68,7 +70,7 @@ void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &vers
}
}
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode){
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
@@ -80,7 +82,7 @@ void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t
auto log = mOutput.add_changes();
log->set_deletion(false);
- //log.timestamp = TODO: choose how timestamps are computed
+ // log.timestamp = TODO: choose how timestamps are computed
log->set_app(app);
log->set_uid(uid);
log->set_version(versionCode);
@@ -99,15 +101,14 @@ void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t
mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
}
-
-void UidMap::removeApp(const String16& app_16, const int32_t& uid){
+void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
auto log = mOutput.add_changes();
log->set_deletion(true);
- //log.timestamp = TODO: choose how timestamps are computed
+ // log.timestamp = TODO: choose how timestamps are computed
log->set_app(app);
log->set_uid(uid);
@@ -123,19 +124,19 @@ void UidMap::removeApp(const String16& app_16, const int32_t& uid){
}
void UidMap::addListener(sp<PackageInfoListener> producer) {
- lock_guard<mutex> lock(mMutex); // Lock for updates
+ lock_guard<mutex> lock(mMutex); // Lock for updates
mSubscribers.insert(producer);
}
void UidMap::removeListener(sp<PackageInfoListener> producer) {
- lock_guard<mutex> lock(mMutex); // Lock for updates
+ lock_guard<mutex> lock(mMutex); // Lock for updates
mSubscribers.erase(producer);
}
UidMapping UidMap::getAndClearOutput() {
- lock_guard<mutex> lock(mMutex); // Lock for updates
+ lock_guard<mutex> lock(mMutex); // Lock for updates
- auto ret = UidMapping(mOutput); // Copy that will be returned.
+ auto ret = UidMapping(mOutput); // Copy that will be returned.
mOutput.Clear();
// Re-initialize the initial state for the outputs. This results in extra data being uploaded
@@ -154,11 +155,11 @@ void UidMap::printUidMap(FILE* out) {
lock_guard<mutex> lock(mMutex);
for (auto it : mMap) {
- fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode, it.first);
+ fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode,
+ it.first);
}
}
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 1481010a60b8..d550372f2e9f 100644
--- a/cmds/statsd/src/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -18,17 +18,17 @@
#define STATSD_UIDMAP_H
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "PackageInfoListener.h"
+#include "packages/PackageInfoListener.h"
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <log/logprint.h>
-#include <mutex>
-#include <string>
#include <stdio.h>
+#include <utils/RefBase.h>
+#include <mutex>
#include <set>
+#include <string>
#include <unordered_map>
-#include <utils/RefBase.h>
using namespace std;
@@ -40,12 +40,12 @@ struct AppData {
const string packageName;
int versionCode;
- AppData(const string& a, const int v) : packageName(a), versionCode(v) {};
+ AppData(const string& a, const int v) : packageName(a), versionCode(v){};
};
// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
// at any given moment. This map must be updated by StatsCompanionService.
-class UidMap : public virtual android::RefBase {
+class UidMap : public virtual android::RefBase {
public:
/*
* All three inputs must be the same size, and the jth element in each array refers to the same
@@ -93,5 +93,4 @@ private:
} // namespace os
} // namespace android
-#endif //STATSD_UIDMAP_H
-
+#endif // STATSD_UIDMAP_H
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
new file mode 100644
index 000000000000..5e8ef245119a
--- /dev/null
+++ b/cmds/statsd/src/stats_events_copy.proto
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+// STOPSHIP: this is a duplicate of stats_event.proto with LITE_RUNTIME added
+// to produce device side lite proto. We should move statsd to soong so that
+// we can generate full and lite library from the same proto file.
+syntax = "proto2";
+option optimize_for = LITE_RUNTIME;
+
+// TODO: Not the right package and class name
+package android.os.statsd;
+option java_package = "com.android.os";
+option java_outer_classname = "StatsEventProto";
+
+/**
+ * The master event class. This message defines all of the available
+ * raw stats log events from the Android system, also known as "atoms."
+ *
+ * This field contains a single oneof with all of the available messages.
+ * The stats-log-api-gen tool runs as part of the Android build and
+ * generates the android.util.StatsLog class, which contains the constants
+ * and methods that Android uses to log.
+ *
+ * This StatsEvent class is not actually built into the Android system.
+ * Instead, statsd on Android constructs these messages synthetically,
+ * in the format defined here and in stats_log.proto.
+ */
+message StatsEvent {
+ oneof event {
+ ScreenStateChanged screen_state_changed = 1;
+ ProcessStateChanged process_state_changed = 2;
+ WakeLockChanged wakelock_changed = 3;
+ }
+}
+
+/**
+ * A WorkSource represents the chained attribution of applications that
+ * resulted in a particular bit of work being done.
+ */
+message WorkSource {
+ // TODO
+}
+
+/*
+ * *****************************************************************************
+ * Below are all of the individual atoms that are logged by Android via statsd
+ * and Westworld.
+ *
+ * RULES:
+ * - The field ids for each atom must start at 1, and count upwards by 1.
+ * Skipping field ids is not allowed.
+ * - These form an API, so renaming, renumbering or removing fields is
+ * not allowed between android releases. (This is not currently enforced,
+ * but there will be a tool to enforce this restriction).
+ * - The types must be built-in protocol buffer types, namely, no sub-messages
+ * are allowed (yet). The bytes type is also not allowed.
+ * - The CamelCase name of the message type should match the
+ * underscore_separated name as defined in StatsEvent.
+ * - If an atom represents work that can be attributed to an app, there can
+ * be exactly one WorkSource field. It must be field number 1.
+ * - A field that is a uid should be a string field, tagged with the [xxx]
+ * annotation. The generated code on android will be represented by UIDs,
+ * and those UIDs will be translated in xxx to those strings.
+ *
+ * CONVENTIONS:
+ * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange
+ * - If there is a UID, it goes first. Think in an object-oriented fashion.
+ * *****************************************************************************
+ */
+
+/**
+ * Logs when the screen state changes.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenStateChanged {
+ // TODO: Use the real screen state.
+ enum State {
+ STATE_UNKNOWN = 0;
+ STATE_OFF = 1;
+ STATE_ON = 2;
+ STATE_DOZE = 3;
+ STATE_DOZE_SUSPEND = 4;
+ STATE_VR = 5;
+ }
+ // New screen state.
+ optional State display_state = 1;
+}
+
+/**
+ * Logs that the state of a process state, as per the activity manager has changed.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ProcessStateChanged {
+ // TODO: Use the real (mapped) process states.
+ optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+
+ // The state.
+ optional int32 state = 2;
+}
+
+/**
+ * Logs that the state of a wakelock has changed.
+ *
+ * Logged from:
+ * TODO
+ */
+message WakeLockChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
+ optional string tag = 2;
+
+ // TODO: Use a constant instead of boolean?
+ optional bool state = 3;
+}
+
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 6421b70f1f86..4ca06fa7a2fe 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -22,7 +22,7 @@ package android.os.statsd;
option java_package = "com.android.os";
option java_outer_classname = "StatsLog";
-import "frameworks/base/cmds/statsd/src/stats_events.proto";
+import "frameworks/base/cmds/statsd/src/stats_events_copy.proto";
message KeyValuePair {
optional int32 key = 1;
diff --git a/cmds/statsd/src/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
index 978b228891b5..5157adf74607 100644
--- a/cmds/statsd/src/stats_util.cpp
+++ b/cmds/statsd/src/stats_util.cpp
@@ -128,162 +128,6 @@ EventMetricData parse(log_msg msg) {
return eventMetricData;
}
-StatsdConfig buildFakeConfig() {
- // HACK: Hard code a test metric for counting screen on events...
- StatsdConfig config;
- config.set_config_id(12345L);
-
- // One count metric to count screen on
- CountMetric* metric = config.add_count_metric();
- metric->set_metric_id(20150717L);
- metric->set_what("SCREEN_IS_ON");
- metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
-
- // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
- metric = config.add_count_metric();
- metric->set_metric_id(20150718L);
- metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
- metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
- metric->set_condition("SCREEN_IS_ON");
-
-
- LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
- eventMatcher->set_name("SCREEN_IS_ON");
-
- SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
- 2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-
-
- eventMatcher = config.add_log_entry_matcher();
- eventMatcher->set_name("SCREEN_IS_OFF");
-
- simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
- simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
- simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-
-
- LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
- procEventMatcher->set_name("PHOTO_CRASH");
-
- SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
- simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
- KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1002 /*pkg*/);
- keyValueMatcher->set_eq_string(
- "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
- keyValueMatcher->set_eq_int(2);
-
-
- procEventMatcher = config.add_log_entry_matcher();
- procEventMatcher->set_name("PHOTO_START");
-
- simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
- simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
- keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1002 /*pkg*/);
- keyValueMatcher->set_eq_string(
- "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1 /*STATE*/);
- keyValueMatcher->set_eq_int(1);
-
-
- procEventMatcher = config.add_log_entry_matcher();
- procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
- LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
- combinationMatcher->set_operation(LogicalOperation::OR);
- combinationMatcher->add_matcher("PHOTO_START");
- combinationMatcher->add_matcher("PHOTO_CRASH");
-
-
- procEventMatcher = config.add_log_entry_matcher();
- procEventMatcher->set_name("CHROME_CRASH");
-
- simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
- simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
- keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1002 /*pkg*/);
- keyValueMatcher->set_eq_string(
- "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
- keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
- keyValueMatcher->mutable_key_matcher()->set_key(
- 1 /*STATE*/);
- keyValueMatcher->set_eq_int(2);
-
-
-
- procEventMatcher = config.add_log_entry_matcher();
- procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
- combinationMatcher = procEventMatcher->mutable_combination();
- combinationMatcher->set_operation(LogicalOperation::OR);
- combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
- combinationMatcher->add_matcher("CHROME_CRASH");
-
-
-
- Condition* condition = config.add_condition();
- condition->set_name("SCREEN_IS_ON");
- SimpleCondition* simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_IS_ON");
- simpleCondition->set_stop("SCREEN_IS_OFF");
-
-
- condition = config.add_condition();
- condition->set_name("PHOTO_STARTED");
-
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("PHOTO_START");
- simpleCondition->set_stop("PHOTO_CRASH");
-
-
- condition = config.add_condition();
- condition->set_name("SCREEN_IS_OFF");
-
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_IS_OFF");
- simpleCondition->set_stop("SCREEN_IS_ON");
-
-
- condition = config.add_condition();
- condition->set_name("SCREEN_IS_EITHER_ON_OFF");
-
- Condition_Combination* combination = condition->mutable_combination();
- combination->set_operation(LogicalOperation::OR);
- combination->add_condition("SCREEN_IS_ON");
- combination->add_condition("SCREEN_IS_OFF");
-
-
- condition = config.add_condition();
- condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
-
- combination = condition->mutable_combination();
- combination->set_operation(LogicalOperation::NOR);
- combination->add_condition("SCREEN_IS_ON");
- combination->add_condition("SCREEN_IS_OFF");
-
- return config;
-}
-
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 25b9bba56280..38174bfae080 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -16,8 +16,8 @@
#ifndef PARSE_UTIL_H
#define PARSE_UTIL_H
-#include "DropboxWriter.h"
-#include "LogReader.h"
+#include "logd/LogReader.h"
+#include "storage/DropboxWriter.h"
#include <log/logprint.h>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -30,8 +30,6 @@ EventMetricData parse(log_msg msg);
int getTagId(log_msg msg);
-StatsdConfig buildFakeConfig();
-
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/storage/DropboxReader.cpp
index 430e7afc7b9b..c561959f8edd 100644
--- a/cmds/statsd/src/DropboxReader.cpp
+++ b/cmds/statsd/src/storage/DropboxReader.cpp
@@ -17,14 +17,14 @@
#include <android/os/DropBoxManager.h>
#include <androidfw/ZipUtils.h>
-#include "DropboxReader.h"
+#include "storage/DropboxReader.h"
-using android::String16;
-using android::ZipUtils;
using android::base::unique_fd;
using android::binder::Status;
using android::os::DropBoxManager;
using android::sp;
+using android::String16;
+using android::ZipUtils;
using std::vector;
namespace android {
diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/storage/DropboxReader.h
index a5a28d9113da..a5a28d9113da 100644
--- a/cmds/statsd/src/DropboxReader.h
+++ b/cmds/statsd/src/storage/DropboxReader.h
diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/storage/DropboxWriter.cpp
index b72e530e413a..e59bdbd1eb21 100644
--- a/cmds/statsd/src/DropboxWriter.cpp
+++ b/cmds/statsd/src/storage/DropboxWriter.cpp
@@ -16,12 +16,12 @@
#include <android/os/DropBoxManager.h>
-#include "DropboxWriter.h"
+#include "storage/DropboxWriter.h"
-using android::String16;
using android::binder::Status;
using android::os::DropBoxManager;
using android::sp;
+using android::String16;
using std::vector;
namespace android {
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/storage/DropboxWriter.h
index d72f1032744a..d72f1032744a 100644
--- a/cmds/statsd/src/DropboxWriter.h
+++ b/cmds/statsd/src/storage/DropboxWriter.h
diff --git a/cmds/statsd/tests/AnomalyMonitor_test.cpp b/cmds/statsd/tests/AnomalyMonitor_test.cpp
index d5b68118d119..59fa16007eef 100644
--- a/cmds/statsd/tests/AnomalyMonitor_test.cpp
+++ b/cmds/statsd/tests/AnomalyMonitor_test.cpp
@@ -12,9 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
-
-#include "../src/AnomalyMonitor.h"
+#include "anomaly/AnomalyMonitor.h"
#include <gtest/gtest.h>
diff --git a/cmds/statsd/tests/ConditionTracker_test.cpp b/cmds/statsd/tests/ConditionTracker_test.cpp
index f8b0fd0796e7..2935ac7136ba 100644
--- a/cmds/statsd/tests/ConditionTracker_test.cpp
+++ b/cmds/statsd/tests/ConditionTracker_test.cpp
@@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <gtest/gtest.h>
-#include "../src/condition/condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <stdio.h>
#include <vector>
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
new file mode 100644
index 000000000000..aa896cafffaf
--- /dev/null
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -0,0 +1,156 @@
+// 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/config/ConfigManager.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <iostream>
+
+using namespace android;
+using namespace android::os::statsd;
+using namespace testing;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static ostream& operator<<(ostream& os, const StatsdConfig& config) {
+ return os << "StatsdConfig{id=" << config.config_id() << "}";
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+/**
+ * Mock ConfigListener
+ */
+class MockListener : public ConfigListener {
+public:
+ MOCK_METHOD2(OnConfigUpdated, void(const ConfigKey& key, const StatsdConfig& config));
+ MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
+};
+
+/**
+ * Validate that the ConfigKey is the one we wanted.
+ */
+MATCHER_P2(ConfigKeyEq, uid, name, "") {
+ return arg.GetUid() == uid && arg.GetName() == name;
+}
+
+/**
+ * Validate that the StatsdConfig is the one we wanted.
+ */
+MATCHER_P(StatsdConfigEq, configId, "") {
+ return arg.config_id() == configId;
+}
+
+/**
+ * Test the addOrUpdate and remove methods
+ */
+TEST(ConfigManagerTest, TestAddUpdateRemove) {
+ sp<MockListener> listener = new StrictMock<MockListener>();
+
+ sp<ConfigManager> manager = new ConfigManager();
+ manager->AddListener(listener);
+
+ StatsdConfig config91;
+ config91.set_config_id(91);
+ StatsdConfig config92;
+ config92.set_config_id(92);
+ StatsdConfig config93;
+ config93.set_config_id(93);
+ StatsdConfig config94;
+ config94.set_config_id(94);
+
+ {
+ InSequence s;
+
+ // The built-in fake one.
+ // TODO: Remove this when we get rid of the fake one, and make this
+ // test loading one from disk somewhere.
+ EXPECT_CALL(*(listener.get()),
+ OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq(12345)))
+ .RetiresOnSaturation();
+ manager->Startup();
+
+ // Add another one
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(91)))
+ .RetiresOnSaturation();
+ manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
+
+ // Update It
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(92)))
+ .RetiresOnSaturation();
+ manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
+
+ // Add one with the same uid but a different name
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq(93)))
+ .RetiresOnSaturation();
+ manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
+
+ // Add one with the same name but a different uid
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq(94)))
+ .RetiresOnSaturation();
+ manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
+
+ // Remove (1,yyy)
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "yyy")))
+ .RetiresOnSaturation();
+ manager->RemoveConfig(ConfigKey(1, "yyy"));
+
+ // Remove (2,zzz)
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")))
+ .RetiresOnSaturation();
+ manager->RemoveConfig(ConfigKey(2, "zzz"));
+
+ // Remove (1,zzz)
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "zzz")))
+ .RetiresOnSaturation();
+ manager->RemoveConfig(ConfigKey(1, "zzz"));
+
+ // Remove (2,zzz) again and we shouldn't get the callback
+ manager->RemoveConfig(ConfigKey(2, "zzz"));
+ }
+}
+
+/**
+ * Test removing all of the configs for a uid.
+ */
+TEST(ConfigManagerTest, TestRemoveUid) {
+ sp<MockListener> listener = new StrictMock<MockListener>();
+
+ sp<ConfigManager> manager = new ConfigManager();
+ manager->AddListener(listener);
+
+ StatsdConfig config;
+
+ EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(6);
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "xxx")));
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "yyy")));
+ EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")));
+
+ manager->Startup();
+ manager->UpdateConfig(ConfigKey(1, "aaa"), config);
+ manager->UpdateConfig(ConfigKey(2, "xxx"), config);
+ manager->UpdateConfig(ConfigKey(2, "yyy"), config);
+ manager->UpdateConfig(ConfigKey(2, "zzz"), config);
+ manager->UpdateConfig(ConfigKey(3, "bbb"), config);
+
+ manager->RemoveConfigs(2);
+}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 606980178e2a..3bc98624ff75 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -12,15 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
#include <gtest/gtest.h>
#include <log/log_event_list.h>
#include <log/log_read.h>
#include <log/logprint.h>
-#include "../src/matchers/matcher_util.h"
-#include "../src/stats_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <stdio.h>
diff --git a/cmds/statsd/tests/LogReader_test.cpp b/cmds/statsd/tests/LogReader_test.cpp
index 2002143edfc1..7ce1d6a71c85 100644
--- a/cmds/statsd/tests/LogReader_test.cpp
+++ b/cmds/statsd/tests/LogReader_test.cpp
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
-
#include <gtest/gtest.h>
#include <stdio.h>
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 673c15686f71..32661dcc4752 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
-
#include <gtest/gtest.h>
-#include "../src/condition/ConditionTracker.h"
-#include "../src/matchers/LogMatchingTracker.h"
-#include "../src/metrics/CountMetricProducer.h"
-#include "../src/metrics/MetricProducer.h"
-#include "../src/metrics/metrics_manager_util.h"
+
+#include "src/condition/ConditionTracker.h"
+#include "src/matchers/LogMatchingTracker.h"
+#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/metrics/metrics_manager_util.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index b6f14493cb36..f9a90e4ee29b 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#define LOG_TAG "statsd_test"
+#include "packages/UidMap.h"
#include <gtest/gtest.h>
-#include "../src/UidMap.h"
+
#include <stdio.h>
using namespace android;
@@ -66,4 +66,4 @@ TEST(UidMapTest, TestAddAndRemove) {
}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif \ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
index 74a482eace58..600b95356083 100644
--- a/cmds/statsd/tests/indexed_priority_queue_test.cpp
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "../src/indexed_priority_queue.h"
+#include "src/anomaly/indexed_priority_queue.h"
#include <gtest/gtest.h>
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 92567d758856..56f4ae2b5832 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -428,6 +428,18 @@ public final class GestureDescription {
}
@Override
+ public String toString() {
+ return "TouchPoint{"
+ + "mStrokeId=" + mStrokeId
+ + ", mContinuedStrokeId=" + mContinuedStrokeId
+ + ", mIsStartOfPath=" + mIsStartOfPath
+ + ", mIsEndOfPath=" + mIsEndOfPath
+ + ", mX=" + mX
+ + ", mY=" + mY
+ + '}';
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 252959a04d4f..85f73bb7c0ef 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6259,6 +6259,8 @@ public class Activity extends ContextThemeWrapper
final AutofillManager afm = getAutofillManager();
if (afm != null) {
afm.dump(prefix, writer);
+ } else {
+ writer.print(prefix); writer.println("No AutofillManager");
}
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 027e811a3273..fc4c8d7f0666 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.Manifest;
+import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -941,11 +942,14 @@ public class ActivityManager {
ATTR_TASKDESCRIPTION_PREFIX + "color";
private static final String ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND =
ATTR_TASKDESCRIPTION_PREFIX + "colorBackground";
- private static final String ATTR_TASKDESCRIPTIONICONFILENAME =
+ private static final String ATTR_TASKDESCRIPTIONICON_FILENAME =
ATTR_TASKDESCRIPTION_PREFIX + "icon_filename";
+ private static final String ATTR_TASKDESCRIPTIONICON_RESOURCE =
+ ATTR_TASKDESCRIPTION_PREFIX + "icon_resource";
private String mLabel;
private Bitmap mIcon;
+ private int mIconRes;
private String mIconFilename;
private int mColorPrimary;
private int mColorBackground;
@@ -959,9 +963,27 @@ public class ActivityManager {
* @param icon An icon that represents the current state of this task.
* @param colorPrimary A color to override the theme's primary color. This color must be
* opaque.
+ * @deprecated use TaskDescription constructor with icon resource instead
*/
+ @Deprecated
public TaskDescription(String label, Bitmap icon, int colorPrimary) {
- this(label, icon, null, colorPrimary, 0, 0, 0);
+ this(label, icon, 0, null, colorPrimary, 0, 0, 0);
+ if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
+ throw new RuntimeException("A TaskDescription's primary color should be opaque");
+ }
+ }
+
+ /**
+ * Creates the TaskDescription to the specified values.
+ *
+ * @param label A label and description of the current state of this task.
+ * @param iconRes A drawable resource of an icon that represents the current state of this
+ * activity.
+ * @param colorPrimary A color to override the theme's primary color. This color must be
+ * opaque.
+ */
+ public TaskDescription(String label, @DrawableRes int iconRes, int colorPrimary) {
+ this(label, null, iconRes, null, colorPrimary, 0, 0, 0);
if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
throw new RuntimeException("A TaskDescription's primary color should be opaque");
}
@@ -972,9 +994,22 @@ public class ActivityManager {
*
* @param label A label and description of the current state of this activity.
* @param icon An icon that represents the current state of this activity.
+ * @deprecated use TaskDescription constructor with icon resource instead
*/
+ @Deprecated
public TaskDescription(String label, Bitmap icon) {
- this(label, icon, null, 0, 0, 0, 0);
+ this(label, icon, 0, null, 0, 0, 0, 0);
+ }
+
+ /**
+ * Creates the TaskDescription to the specified values.
+ *
+ * @param label A label and description of the current state of this activity.
+ * @param iconRes A drawable resource of an icon that represents the current state of this
+ * activity.
+ */
+ public TaskDescription(String label, @DrawableRes int iconRes) {
+ this(label, null, iconRes, null, 0, 0, 0, 0);
}
/**
@@ -983,21 +1018,22 @@ public class ActivityManager {
* @param label A label and description of the current state of this activity.
*/
public TaskDescription(String label) {
- this(label, null, null, 0, 0, 0, 0);
+ this(label, null, 0, null, 0, 0, 0, 0);
}
/**
* Creates an empty TaskDescription.
*/
public TaskDescription() {
- this(null, null, null, 0, 0, 0, 0);
+ this(null, null, 0, null, 0, 0, 0, 0);
}
/** @hide */
- public TaskDescription(String label, Bitmap icon, String iconFilename, int colorPrimary,
- int colorBackground, int statusBarColor, int navigationBarColor) {
+ public TaskDescription(String label, Bitmap bitmap, int iconRes, String iconFilename,
+ int colorPrimary, int colorBackground, int statusBarColor, int navigationBarColor) {
mLabel = label;
- mIcon = icon;
+ mIcon = bitmap;
+ mIconRes = iconRes;
mIconFilename = iconFilename;
mColorPrimary = colorPrimary;
mColorBackground = colorBackground;
@@ -1019,6 +1055,7 @@ public class ActivityManager {
public void copyFrom(TaskDescription other) {
mLabel = other.mLabel;
mIcon = other.mIcon;
+ mIconRes = other.mIconRes;
mIconFilename = other.mIconFilename;
mColorPrimary = other.mColorPrimary;
mColorBackground = other.mColorBackground;
@@ -1034,6 +1071,7 @@ public class ActivityManager {
public void copyFromPreserveHiddenFields(TaskDescription other) {
mLabel = other.mLabel;
mIcon = other.mIcon;
+ mIconRes = other.mIconRes;
mIconFilename = other.mIconFilename;
mColorPrimary = other.mColorPrimary;
if (other.mColorBackground != 0) {
@@ -1106,6 +1144,14 @@ public class ActivityManager {
}
/**
+ * Sets the icon resource for this task description.
+ * @hide
+ */
+ public void setIcon(int iconRes) {
+ mIconRes = iconRes;
+ }
+
+ /**
* Moves the icon bitmap reference from an actual Bitmap to a file containing the
* bitmap.
* @hide
@@ -1133,6 +1179,13 @@ public class ActivityManager {
}
/** @hide */
+ @TestApi
+ public int getIconResource() {
+ return mIconRes;
+ }
+
+ /** @hide */
+ @TestApi
public String getIconFilename() {
return mIconFilename;
}
@@ -1198,7 +1251,10 @@ public class ActivityManager {
Integer.toHexString(mColorBackground));
}
if (mIconFilename != null) {
- out.attribute(null, ATTR_TASKDESCRIPTIONICONFILENAME, mIconFilename);
+ out.attribute(null, ATTR_TASKDESCRIPTIONICON_FILENAME, mIconFilename);
+ }
+ if (mIconRes != 0) {
+ out.attribute(null, ATTR_TASKDESCRIPTIONICON_RESOURCE, Integer.toString(mIconRes));
}
}
@@ -1210,8 +1266,10 @@ public class ActivityManager {
setPrimaryColor((int) Long.parseLong(attrValue, 16));
} else if (ATTR_TASKDESCRIPTIONCOLOR_BACKGROUND.equals(attrName)) {
setBackgroundColor((int) Long.parseLong(attrValue, 16));
- } else if (ATTR_TASKDESCRIPTIONICONFILENAME.equals(attrName)) {
+ } else if (ATTR_TASKDESCRIPTIONICON_FILENAME.equals(attrName)) {
setIconFilename(attrValue);
+ } else if (ATTR_TASKDESCRIPTIONICON_RESOURCE.equals(attrName)) {
+ setIcon(Integer.parseInt(attrValue, 10));
}
}
@@ -1234,6 +1292,7 @@ public class ActivityManager {
dest.writeInt(1);
mIcon.writeToParcel(dest, 0);
}
+ dest.writeInt(mIconRes);
dest.writeInt(mColorPrimary);
dest.writeInt(mColorBackground);
dest.writeInt(mStatusBarColor);
@@ -1249,6 +1308,7 @@ public class ActivityManager {
public void readFromParcel(Parcel source) {
mLabel = source.readInt() > 0 ? source.readString() : null;
mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+ mIconRes = source.readInt();
mColorPrimary = source.readInt();
mColorBackground = source.readInt();
mStatusBarColor = source.readInt();
@@ -1269,8 +1329,8 @@ public class ActivityManager {
@Override
public String toString() {
return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
- " IconFilename: " + mIconFilename + " colorPrimary: " + mColorPrimary +
- " colorBackground: " + mColorBackground +
+ " IconRes: " + mIconRes + " IconFilename: " + mIconFilename +
+ " colorPrimary: " + mColorPrimary + " colorBackground: " + mColorBackground +
" statusBarColor: " + mColorBackground +
" navigationBarColor: " + mNavigationBarColor;
}
diff --git a/core/java/android/slice/Slice.java b/core/java/android/app/slice/Slice.java
index 576865480e04..7f9f74b4819a 100644
--- a/core/java/android/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -14,38 +14,35 @@
* limitations under the License.
*/
-package android.slice;
-
-import static android.slice.SliceItem.TYPE_ACTION;
-import static android.slice.SliceItem.TYPE_COLOR;
-import static android.slice.SliceItem.TYPE_IMAGE;
-import static android.slice.SliceItem.TYPE_REMOTE_INPUT;
-import static android.slice.SliceItem.TYPE_REMOTE_VIEW;
-import static android.slice.SliceItem.TYPE_SLICE;
-import static android.slice.SliceItem.TYPE_TEXT;
-import static android.slice.SliceItem.TYPE_TIMESTAMP;
+package android.app.slice;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StringDef;
import android.app.PendingIntent;
import android.app.RemoteInput;
+import android.content.ContentResolver;
+import android.content.IContentProvider;
import android.graphics.drawable.Icon;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
import android.widget.RemoteViews;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* A slice is a piece of app content and actions that can be surfaced outside of the app.
*
* <p>They are constructed using {@link Builder} in a tree structure
* that provides the OS some information about how the content should be displayed.
- * @hide
*/
public final class Slice implements Parcelable {
@@ -53,7 +50,7 @@ public final class Slice implements Parcelable {
* @hide
*/
@StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
- HINT_SOURCE, HINT_MESSAGE, HINT_HORIZONTAL, HINT_NO_TINT})
+ HINT_SOURCE, HINT_MESSAGE, HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL})
public @interface SliceHint{ }
/**
@@ -102,6 +99,12 @@ public final class Slice implements Parcelable {
* Hint to indicate that this content should not be tinted.
*/
public static final String HINT_NO_TINT = "no_tint";
+ /**
+ * Hint to indicate that this slice is incomplete and an update will be sent once
+ * loading is complete. Slices which contain HINT_PARTIAL will not be cached by the
+ * OS and should not be cached by apps.
+ */
+ public static final String HINT_PARTIAL = "partial";
// These two are coming over from prototyping, but we probably don't want in
// public API, at least not right now.
@@ -109,19 +112,12 @@ public final class Slice implements Parcelable {
* @hide
*/
public static final String HINT_ALT = "alt";
- /**
- * @hide
- */
- public static final String HINT_PARTIAL = "partial";
private final SliceItem[] mItems;
private final @SliceHint String[] mHints;
private Uri mUri;
- /**
- * @hide
- */
- public Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
+ Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri) {
mHints = hints;
mItems = items.toArray(new SliceItem[items.size()]);
mUri = uri;
@@ -147,15 +143,15 @@ public final class Slice implements Parcelable {
/**
* @return All child {@link SliceItem}s that this Slice contains.
*/
- public SliceItem[] getItems() {
- return mItems;
+ public List<SliceItem> getItems() {
+ return Arrays.asList(mItems);
}
/**
* @return All hints associated with this Slice.
*/
- public @SliceHint String[] getHints() {
- return mHints;
+ public @SliceHint List<String> getHints() {
+ return Arrays.asList(mHints);
}
/**
@@ -163,14 +159,14 @@ public final class Slice implements Parcelable {
*/
public SliceItem getPrimaryIcon() {
for (SliceItem item : getItems()) {
- if (item.getType() == TYPE_IMAGE) {
+ if (item.getType() == SliceItem.TYPE_IMAGE) {
return item;
}
- if (!(item.getType() == TYPE_SLICE && item.hasHint(Slice.HINT_LIST))
+ if (!(item.getType() == SliceItem.TYPE_SLICE && item.hasHint(Slice.HINT_LIST))
&& !item.hasHint(Slice.HINT_ACTIONS)
&& !item.hasHint(Slice.HINT_LIST_ITEM)
- && (item.getType() != TYPE_ACTION)) {
- SliceItem icon = SliceQuery.find(item, TYPE_IMAGE);
+ && (item.getType() != SliceItem.TYPE_ACTION)) {
+ SliceItem icon = SliceQuery.find(item, SliceItem.TYPE_IMAGE);
if (icon != null) return icon;
}
}
@@ -235,10 +231,18 @@ public final class Slice implements Parcelable {
}
/**
+ * Add hints to the Slice being constructed
+ */
+ public Builder addHints(@SliceHint List<String> hints) {
+ return addHints(hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Add a sub-slice to the slice being constructed
*/
public Builder addSubSlice(@NonNull Slice slice) {
- mItems.add(new SliceItem(slice, TYPE_SLICE, slice.getHints()));
+ mItems.add(new SliceItem(slice, SliceItem.TYPE_SLICE, slice.getHints().toArray(
+ new String[slice.getHints().size()])));
return this;
}
@@ -246,7 +250,7 @@ public final class Slice implements Parcelable {
* Add an action to the slice being constructed
*/
public Slice.Builder addAction(@NonNull PendingIntent action, @NonNull Slice s) {
- mItems.add(new SliceItem(action, s, TYPE_ACTION, new String[0]));
+ mItems.add(new SliceItem(action, s, SliceItem.TYPE_ACTION, new String[0]));
return this;
}
@@ -254,31 +258,53 @@ public final class Slice implements Parcelable {
* Add text to the slice being constructed
*/
public Builder addText(CharSequence text, @SliceHint String... hints) {
- mItems.add(new SliceItem(text, TYPE_TEXT, hints));
+ mItems.add(new SliceItem(text, SliceItem.TYPE_TEXT, hints));
return this;
}
/**
+ * Add text to the slice being constructed
+ */
+ public Builder addText(CharSequence text, @SliceHint List<String> hints) {
+ return addText(text, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Add an image to the slice being constructed
*/
public Builder addIcon(Icon icon, @SliceHint String... hints) {
- mItems.add(new SliceItem(icon, TYPE_IMAGE, hints));
+ mItems.add(new SliceItem(icon, SliceItem.TYPE_IMAGE, hints));
return this;
}
/**
+ * Add an image to the slice being constructed
+ */
+ public Builder addIcon(Icon icon, @SliceHint List<String> hints) {
+ return addIcon(icon, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* @hide This isn't final
*/
public Builder addRemoteView(RemoteViews remoteView, @SliceHint String... hints) {
- mItems.add(new SliceItem(remoteView, TYPE_REMOTE_VIEW, hints));
+ mItems.add(new SliceItem(remoteView, SliceItem.TYPE_REMOTE_VIEW, hints));
return this;
}
/**
* Add remote input to the slice being constructed
*/
+ public Slice.Builder addRemoteInput(RemoteInput remoteInput,
+ @SliceHint List<String> hints) {
+ return addRemoteInput(remoteInput, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
+ * Add remote input to the slice being constructed
+ */
public Slice.Builder addRemoteInput(RemoteInput remoteInput, @SliceHint String... hints) {
- mItems.add(new SliceItem(remoteInput, TYPE_REMOTE_INPUT, hints));
+ mItems.add(new SliceItem(remoteInput, SliceItem.TYPE_REMOTE_INPUT, hints));
return this;
}
@@ -286,19 +312,33 @@ public final class Slice implements Parcelable {
* Add a color to the slice being constructed
*/
public Builder addColor(int color, @SliceHint String... hints) {
- mItems.add(new SliceItem(color, TYPE_COLOR, hints));
+ mItems.add(new SliceItem(color, SliceItem.TYPE_COLOR, hints));
return this;
}
/**
+ * Add a color to the slice being constructed
+ */
+ public Builder addColor(int color, @SliceHint List<String> hints) {
+ return addColor(color, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Add a timestamp to the slice being constructed
*/
public Slice.Builder addTimestamp(long time, @SliceHint String... hints) {
- mItems.add(new SliceItem(time, TYPE_TIMESTAMP, hints));
+ mItems.add(new SliceItem(time, SliceItem.TYPE_TIMESTAMP, hints));
return this;
}
/**
+ * Add a timestamp to the slice being constructed
+ */
+ public Slice.Builder addTimestamp(long time, @SliceHint List<String> hints) {
+ return addTimestamp(time, hints.toArray(new String[hints.size()]));
+ }
+
+ /**
* Construct the slice.
*/
public Slice build() {
@@ -322,18 +362,18 @@ public final class Slice implements Parcelable {
* @hide
* @return A string representation of this slice.
*/
- public String getString() {
- return getString("");
+ public String toString() {
+ return toString("");
}
- private String getString(String indent) {
+ private String toString(String indent) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mItems.length; i++) {
sb.append(indent);
- if (mItems[i].getType() == TYPE_SLICE) {
+ if (mItems[i].getType() == SliceItem.TYPE_SLICE) {
sb.append("slice:\n");
- sb.append(mItems[i].getSlice().getString(indent + " "));
- } else if (mItems[i].getType() == TYPE_TEXT) {
+ sb.append(mItems[i].getSlice().toString(indent + " "));
+ } else if (mItems[i].getType() == SliceItem.TYPE_TEXT) {
sb.append("text: ");
sb.append(mItems[i].getText());
sb.append("\n");
@@ -344,4 +384,34 @@ public final class Slice implements Parcelable {
}
return sb.toString();
}
+
+ /**
+ * Turns a slice Uri into slice content.
+ *
+ * @param resolver ContentResolver to be used.
+ * @param uri The URI to a slice provider
+ * @return The Slice provided by the app or null if none is given.
+ * @see Slice
+ */
+ public static @Nullable Slice bindSlice(ContentResolver resolver, @NonNull Uri uri) {
+ Preconditions.checkNotNull(uri, "uri");
+ IContentProvider provider = resolver.acquireProvider(uri);
+ if (provider == null) {
+ throw new IllegalArgumentException("Unknown URI " + uri);
+ }
+ try {
+ Bundle extras = new Bundle();
+ extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
+ final Bundle res = provider.call(resolver.getPackageName(), SliceProvider.METHOD_SLICE,
+ null, extras);
+ Bundle.setDefusable(res, true);
+ return res.getParcelable(SliceProvider.EXTRA_SLICE);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return null;
+ } finally {
+ resolver.releaseProvider(provider);
+ }
+ }
}
diff --git a/core/java/android/slice/SliceItem.java b/core/java/android/app/slice/SliceItem.java
index 2827ab9d994c..6e69b0511207 100644
--- a/core/java/android/slice/SliceItem.java
+++ b/core/java/android/app/slice/SliceItem.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.slice;
+package android.app.slice;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -23,13 +23,15 @@ import android.app.RemoteInput;
import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
-import android.slice.Slice.SliceHint;
import android.text.TextUtils;
import android.util.Pair;
import android.widget.RemoteViews;
import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
+import java.util.List;
+
/**
* A SliceItem is a single unit in the tree structure of a {@link Slice}.
@@ -47,7 +49,6 @@ import com.android.internal.util.ArrayUtils;
* The hints that a {@link SliceItem} are a set of strings which annotate
* the content. The hints that are guaranteed to be understood by the system
* are defined on {@link Slice}.
- * @hide
*/
public final class SliceItem implements Parcelable {
@@ -97,14 +98,15 @@ public final class SliceItem implements Parcelable {
/**
* @hide
*/
- protected @SliceHint String[] mHints;
+ protected @Slice.SliceHint
+ String[] mHints;
private final int mType;
private final Object mObj;
/**
* @hide
*/
- public SliceItem(Object obj, @SliceType int type, @SliceHint String[] hints) {
+ public SliceItem(Object obj, @SliceType int type, @Slice.SliceHint String[] hints) {
mHints = hints;
mType = type;
mObj = obj;
@@ -113,7 +115,7 @@ public final class SliceItem implements Parcelable {
/**
* @hide
*/
- public SliceItem(PendingIntent intent, Slice slice, int type, @SliceHint String[] hints) {
+ public SliceItem(PendingIntent intent, Slice slice, int type, @Slice.SliceHint String[] hints) {
this(new Pair<>(intent, slice), type, hints);
}
@@ -121,14 +123,14 @@ public final class SliceItem implements Parcelable {
* Gets all hints associated with this SliceItem.
* @return Array of hints.
*/
- public @NonNull @SliceHint String[] getHints() {
- return mHints;
+ public @NonNull @Slice.SliceHint List<String> getHints() {
+ return Arrays.asList(mHints);
}
/**
* @hide
*/
- public void addHint(@SliceHint String hint) {
+ public void addHint(@Slice.SliceHint String hint) {
mHints = ArrayUtils.appendElement(String.class, mHints, hint);
}
@@ -206,7 +208,7 @@ public final class SliceItem implements Parcelable {
* @param hint The hint to check for
* @return true if this item contains the given hint
*/
- public boolean hasHint(@SliceHint String hint) {
+ public boolean hasHint(@Slice.SliceHint String hint) {
return ArrayUtils.contains(mHints, hint);
}
@@ -234,7 +236,7 @@ public final class SliceItem implements Parcelable {
/**
* @hide
*/
- public boolean hasHints(@SliceHint String[] hints) {
+ public boolean hasHints(@Slice.SliceHint String[] hints) {
if (hints == null) return true;
for (String hint : hints) {
if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
@@ -247,7 +249,7 @@ public final class SliceItem implements Parcelable {
/**
* @hide
*/
- public boolean hasAnyHints(@SliceHint String[] hints) {
+ public boolean hasAnyHints(@Slice.SliceHint String[] hints) {
if (hints == null) return false;
for (String hint : hints) {
if (ArrayUtils.contains(mHints, hint)) {
diff --git a/core/java/android/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 4e21371b26b5..df87b4556ee5 100644
--- a/core/java/android/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.slice;
+package android.app.slice;
import android.Manifest.permission;
import android.content.ContentProvider;
@@ -26,6 +26,8 @@ import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
@@ -51,10 +53,15 @@ import java.util.concurrent.CountDownLatch;
* </pre>
*
* @see Slice
- * @hide
*/
public abstract class SliceProvider extends ContentProvider {
+ /**
+ * This is the Android platform's MIME type for a slice: URI
+ * containing a slice implemented through {@link SliceProvider}.
+ */
+ public static final String SLICE_TYPE = "vnd.android.slice";
+
private static final String TAG = "SliceProvider";
/**
* @hide
@@ -73,8 +80,18 @@ public abstract class SliceProvider extends ContentProvider {
/**
* Implemented to create a slice. Will be called on the main thread.
+ * <p>
+ * onBindSlice should return as quickly as possible so that the UI tied
+ * to this slice can be responsive. No network or other IO will be allowed
+ * during onBindSlice. Any loading that needs to be done should happen
+ * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+ * when the app is ready to provide the complete data in onBindSlice.
+ * <p>
+ *
* @see {@link Slice}.
+ * @see {@link Slice#HINT_PARTIAL}
*/
+ // TODO: Provide alternate notifyChange that takes in the slice (i.e. notifyChange(Uri, Slice)).
public abstract Slice onBindSlice(Uri sliceUri);
@Override
@@ -120,11 +137,11 @@ public abstract class SliceProvider extends ContentProvider {
@Override
public final String getType(Uri uri) {
if (DEBUG) Log.d(TAG, "getType " + uri);
- return null;
+ return SLICE_TYPE;
}
@Override
- public final Bundle call(String method, String arg, Bundle extras) {
+ public Bundle call(String method, String arg, Bundle extras) {
if (method.equals(METHOD_SLICE)) {
getContext().enforceCallingPermission(permission.BIND_SLICE,
"Slice binding requires the permission BIND_SLICE");
@@ -143,8 +160,17 @@ public abstract class SliceProvider extends ContentProvider {
CountDownLatch latch = new CountDownLatch(1);
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(() -> {
- output[0] = onBindSlice(sliceUri);
- latch.countDown();
+ ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+ try {
+ StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+ .detectAll()
+ .penaltyDeath()
+ .build());
+ output[0] = onBindSlice(sliceUri);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ latch.countDown();
+ }
});
try {
latch.await();
diff --git a/core/java/android/slice/SliceQuery.java b/core/java/android/app/slice/SliceQuery.java
index d99b26a507e4..d1fe2c90f7a4 100644
--- a/core/java/android/slice/SliceQuery.java
+++ b/core/java/android/app/slice/SliceQuery.java
@@ -14,12 +14,8 @@
* limitations under the License.
*/
-package android.slice;
+package android.app.slice;
-import static android.slice.SliceItem.TYPE_ACTION;
-import static android.slice.SliceItem.TYPE_SLICE;
-
-import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -114,7 +110,9 @@ public class SliceQuery {
* @hide
*/
public static SliceItem find(Slice s, int type, String[] hints, String[] nonHints) {
- return find(new SliceItem(s, TYPE_SLICE, s.getHints()), type, hints, nonHints);
+ List<String> h = s.getHints();
+ return find(new SliceItem(s, SliceItem.TYPE_SLICE, h.toArray(new String[h.size()])), type,
+ hints, nonHints);
}
/**
@@ -140,8 +138,9 @@ public class SliceQuery {
@Override
public SliceItem next() {
SliceItem item = items.poll();
- if (item.getType() == TYPE_SLICE || item.getType() == TYPE_ACTION) {
- items.addAll(Arrays.asList(item.getSlice().getItems()));
+ if (item.getType() == SliceItem.TYPE_SLICE
+ || item.getType() == SliceItem.TYPE_ACTION) {
+ items.addAll(item.getSlice().getItems());
}
return item;
}
diff --git a/core/java/android/slice/views/ActionRow.java b/core/java/android/app/slice/views/ActionRow.java
index 93e9c0352580..c7d99f7fd443 100644
--- a/core/java/android/slice/views/ActionRow.java
+++ b/core/java/android/app/slice/views/ActionRow.java
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteInput;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.drawable.Icon;
import android.os.AsyncTask;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewParent;
diff --git a/core/java/android/slice/views/GridView.java b/core/java/android/app/slice/views/GridView.java
index 18a90f7d1405..6f30c507b052 100644
--- a/core/java/android/slice/views/GridView.java
+++ b/core/java/android/app/slice/views/GridView.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
import android.content.Context;
import android.graphics.Color;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.views.LargeSliceAdapter.SliceListView;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
@@ -38,7 +38,7 @@ import android.widget.TextView;
import com.android.internal.R;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.List;
/**
* @hide
@@ -76,10 +76,10 @@ public class GridView extends LinearLayout implements SliceListView {
removeAllViews();
int total = 1;
if (slice.getType() == SliceItem.TYPE_SLICE) {
- SliceItem[] items = slice.getSlice().getItems();
- total = items.length;
+ List<SliceItem> items = slice.getSlice().getItems();
+ total = items.size();
for (int i = 0; i < total; i++) {
- SliceItem item = items[i];
+ SliceItem item = items.get(i);
if (isFull()) {
continue;
}
@@ -142,7 +142,7 @@ public class GridView extends LinearLayout implements SliceListView {
// TODO: Unify sporadic inflates that happen throughout the code.
ArrayList<SliceItem> items = new ArrayList<>();
if (item.getType() == SliceItem.TYPE_SLICE) {
- items.addAll(Arrays.asList(item.getSlice().getItems()));
+ items.addAll(item.getSlice().getItems());
}
items.forEach(i -> {
Context context = getContext();
diff --git a/core/java/android/slice/views/LargeSliceAdapter.java b/core/java/android/app/slice/views/LargeSliceAdapter.java
index e77a1b2af745..6794ff984152 100644
--- a/core/java/android/slice/views/LargeSliceAdapter.java
+++ b/core/java/android/app/slice/views/LargeSliceAdapter.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceViewHolder;
import android.content.Context;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceViewHolder;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
diff --git a/core/java/android/slice/views/LargeTemplateView.java b/core/java/android/app/slice/views/LargeTemplateView.java
index d53e8fcb39e7..9e225162e205 100644
--- a/core/java/android/slice/views/LargeTemplateView.java
+++ b/core/java/android/app/slice/views/LargeTemplateView.java
@@ -14,22 +14,21 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.SliceView.SliceModeView;
import android.content.Context;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.SliceView.SliceModeView;
import android.util.TypedValue;
import com.android.internal.widget.LinearLayoutManager;
import com.android.internal.widget.RecyclerView;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -86,7 +85,7 @@ public class LargeTemplateView extends SliceModeView {
if (slice.hasHint(Slice.HINT_LIST)) {
addList(slice, items);
} else {
- Arrays.asList(slice.getItems()).forEach(item -> {
+ slice.getItems().forEach(item -> {
if (item.hasHint(Slice.HINT_ACTIONS)) {
return;
} else if (item.getType() == SliceItem.TYPE_COLOR) {
@@ -109,7 +108,7 @@ public class LargeTemplateView extends SliceModeView {
}
private void addList(Slice slice, List<SliceItem> items) {
- List<SliceItem> sliceItems = Arrays.asList(slice.getItems());
+ List<SliceItem> sliceItems = slice.getItems();
sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
items.addAll(sliceItems);
}
diff --git a/core/java/android/slice/views/MessageView.java b/core/java/android/app/slice/views/MessageView.java
index 7b03e0bd92c7..77252bf2bb4b 100644
--- a/core/java/android/slice/views/MessageView.java
+++ b/core/java/android/app/slice/views/MessageView.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceListView;
import android.text.SpannableStringBuilder;
import android.util.AttributeSet;
import android.util.TypedValue;
diff --git a/core/java/android/slice/views/RemoteInputView.java b/core/java/android/app/slice/views/RemoteInputView.java
index a29bb5c0e608..e53cb1ea1764 100644
--- a/core/java/android/slice/views/RemoteInputView.java
+++ b/core/java/android/app/slice/views/RemoteInputView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.animation.Animator;
import android.app.Notification;
diff --git a/core/java/android/slice/views/ShortcutView.java b/core/java/android/app/slice/views/ShortcutView.java
index 8fe2f1ac9e6f..b6790c7df82d 100644
--- a/core/java/android/slice/views/ShortcutView.java
+++ b/core/java/android/app/slice/views/ShortcutView.java
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.SliceView.SliceModeView;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.net.Uri;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.SliceView.SliceModeView;
import android.view.ViewGroup;
import com.android.internal.R;
diff --git a/core/java/android/slice/views/SliceView.java b/core/java/android/app/slice/views/SliceView.java
index f37924816bf2..32484fcabe77 100644
--- a/core/java/android/slice/views/SliceView.java
+++ b/core/java/android/app/slice/views/SliceView.java
@@ -14,23 +14,25 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.annotation.StringDef;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import java.util.List;
+
/**
* A view that can display a {@link Slice} in different {@link SliceMode}'s.
*
@@ -120,7 +122,7 @@ public class SliceView extends LinearLayout {
*/
public void bindSlice(Uri sliceUri) {
validate(sliceUri);
- Slice s = mContext.getContentResolver().bindSlice(sliceUri);
+ Slice s = Slice.bindSlice(mContext.getContentResolver(), sliceUri);
bindSlice(s);
}
@@ -201,7 +203,7 @@ public class SliceView extends LinearLayout {
}
// TODO: Smarter mapping here from one state to the next.
SliceItem color = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_COLOR);
- SliceItem[] items = mCurrentSlice.getItems();
+ List<SliceItem> items = mCurrentSlice.getItems();
SliceItem actionRow = SliceQuery.find(mCurrentSlice, SliceItem.TYPE_SLICE,
Slice.HINT_ACTIONS,
Slice.HINT_ALT);
@@ -212,7 +214,7 @@ public class SliceView extends LinearLayout {
addView(mCurrentView);
addView(mActions);
}
- if (items.length > 1 || (items.length != 0 && items[0] != actionRow)) {
+ if (items.size() > 1 || (items.size() != 0 && items.get(0) != actionRow)) {
mCurrentView.setVisibility(View.VISIBLE);
mCurrentView.setSlice(mCurrentSlice);
} else {
@@ -239,7 +241,7 @@ public class SliceView extends LinearLayout {
}
private static void validate(Uri sliceUri) {
- if (!ContentResolver.SCHEME_SLICE.equals(sliceUri.getScheme())) {
+ if (!ContentResolver.SCHEME_CONTENT.equals(sliceUri.getScheme())) {
throw new RuntimeException("Invalid uri " + sliceUri);
}
if (sliceUri.getPathSegments().size() == 0) {
diff --git a/core/java/android/slice/views/SliceViewUtil.java b/core/java/android/app/slice/views/SliceViewUtil.java
index 1b5a6d1e088b..19e8e7c9be4e 100644
--- a/core/java/android/slice/views/SliceViewUtil.java
+++ b/core/java/android/app/slice/views/SliceViewUtil.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.annotation.ColorInt;
import android.content.Context;
diff --git a/core/java/android/slice/views/SmallTemplateView.java b/core/java/android/app/slice/views/SmallTemplateView.java
index b0b181ed0169..42b2d21399c9 100644
--- a/core/java/android/slice/views/SmallTemplateView.java
+++ b/core/java/android/app/slice/views/SmallTemplateView.java
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.slice.views;
+package android.app.slice.views;
import android.app.PendingIntent.CanceledException;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.app.slice.views.LargeSliceAdapter.SliceListView;
+import android.app.slice.views.SliceView.SliceModeView;
import android.content.Context;
import android.os.AsyncTask;
-import android.slice.Slice;
-import android.slice.SliceItem;
-import android.slice.SliceQuery;
-import android.slice.views.LargeSliceAdapter.SliceListView;
-import android.slice.views.SliceView.SliceModeView;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -34,7 +34,6 @@ import com.android.internal.R;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
import java.util.List;
@@ -117,7 +116,7 @@ public class SmallTemplateView extends SliceModeView implements SliceListView {
int itemCount = 0;
boolean hasSummary = false;
ArrayList<SliceItem> sliceItems = new ArrayList<SliceItem>(
- Arrays.asList(slice.getSlice().getItems()));
+ slice.getSlice().getItems());
for (int i = 0; i < sliceItems.size(); i++) {
SliceItem item = sliceItems.get(i);
if (!hasSummary && item.getType() == SliceItem.TYPE_TEXT
@@ -140,9 +139,9 @@ public class SmallTemplateView extends SliceModeView implements SliceListView {
mEndContainer.addView(tv);
itemCount++;
} else if (item.getType() == SliceItem.TYPE_SLICE) {
- SliceItem[] subItems = item.getSlice().getItems();
- for (int j = 0; j < subItems.length; j++) {
- sliceItems.add(subItems[j]);
+ List<SliceItem> subItems = item.getSlice().getItems();
+ for (int j = 0; j < subItems.size(); j++) {
+ sliceItems.add(subItems.get(j));
}
}
}
@@ -151,7 +150,8 @@ public class SmallTemplateView extends SliceModeView implements SliceListView {
@Override
public void setSlice(Slice slice) {
- setSliceItem(new SliceItem(slice, SliceItem.TYPE_SLICE, slice.getHints()));
+ setSliceItem(new SliceItem(slice, SliceItem.TYPE_SLICE,
+ slice.getHints().toArray(new String[slice.getHints().size()])));
}
/**
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 051dccbd86c0..fd579fce34d8 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -48,10 +48,10 @@ import java.util.Map;
* </pre>
* A request for data in the middle of a time interval will include that interval.
* <p/>
- * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS, which
- * is a system-level permission and will not be granted to third-party apps. However, declaring
- * the permission implies intention to use the API and the user of the device can grant permission
- * through the Settings application.
+ * <b>NOTE:</b> This API requires the permission android.permission.PACKAGE_USAGE_STATS.
+ * However, declaring the permission implies intention to use the API and the user of the device
+ * still needs to grant permission through the Settings application.
+ * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}
*/
@SystemService(Context.USAGE_STATS_SERVICE)
public final class UsageStatsManager {
@@ -122,7 +122,7 @@ public final class UsageStatsManager {
* @param intervalType The time interval by which the stats are aggregated.
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return A list of {@link UsageStats} or null if none are available.
+ * @return A list of {@link UsageStats}
*
* @see #INTERVAL_DAILY
* @see #INTERVAL_WEEKLY
@@ -139,7 +139,7 @@ public final class UsageStatsManager {
return slice.getList();
}
} catch (RemoteException e) {
- // fallthrough and return null.
+ // fallthrough and return the empty list.
}
return Collections.emptyList();
}
@@ -152,7 +152,7 @@ public final class UsageStatsManager {
* @param intervalType The time interval by which the stats are aggregated.
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return A list of {@link ConfigurationStats} or null if none are available.
+ * @return A list of {@link ConfigurationStats}
*/
public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime,
long endTime) {
@@ -185,7 +185,7 @@ public final class UsageStatsManager {
return iter;
}
} catch (RemoteException e) {
- // fallthrough and return null
+ // fallthrough and return empty result.
}
return sEmptyResults;
}
@@ -197,8 +197,7 @@ public final class UsageStatsManager {
*
* @param beginTime The inclusive beginning of the range of stats to include in the results.
* @param endTime The exclusive end of the range of stats to include in the results.
- * @return A {@link java.util.Map} keyed by package name, or null if no stats are
- * available.
+ * @return A {@link java.util.Map} keyed by package name
*/
public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5b2bf456b4e8..cdeaea3ebcae 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -2099,8 +2099,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public static Uri maybeAddUserId(Uri uri, int userId) {
if (uri == null) return null;
if (userId != UserHandle.USER_CURRENT
- && (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
- || ContentResolver.SCHEME_SLICE.equals(uri.getScheme()))) {
+ && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
if (!uriHasUserId(uri)) {
//We don't add the user Id if there's already one
Uri.Builder builder = uri.buildUpon();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 02e70f55f27e..9ccc552f77f5 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -47,8 +47,6 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
-import android.slice.Slice;
-import android.slice.SliceProvider;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -180,8 +178,6 @@ public abstract class ContentResolver {
public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
- /** @hide */
- public static final String SCHEME_SLICE = "slice";
public static final String SCHEME_CONTENT = "content";
public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
public static final String SCHEME_FILE = "file";
@@ -1722,36 +1718,6 @@ public abstract class ContentResolver {
}
/**
- * Turns a slice Uri into slice content.
- *
- * @param uri The URI to a slice provider
- * @return The Slice provided by the app or null if none is given.
- * @see Slice
- * @hide
- */
- public final @Nullable Slice bindSlice(@NonNull Uri uri) {
- Preconditions.checkNotNull(uri, "uri");
- IContentProvider provider = acquireProvider(uri);
- if (provider == null) {
- throw new IllegalArgumentException("Unknown URI " + uri);
- }
- try {
- Bundle extras = new Bundle();
- extras.putParcelable(SliceProvider.EXTRA_BIND_URI, uri);
- final Bundle res = provider.call(mPackageName, SliceProvider.METHOD_SLICE, null,
- extras);
- Bundle.setDefusable(res, true);
- return res.getParcelable(SliceProvider.EXTRA_SLICE);
- } catch (RemoteException e) {
- // Arbitrary and not worth documenting, as Activity
- // Manager will kill this process shortly anyway.
- return null;
- } finally {
- releaseProvider(provider);
- }
- }
-
- /**
* Returns the content provider for the given content URI.
*
* @param uri The URI to a content provider
@@ -1759,7 +1725,7 @@ public abstract class ContentResolver {
* @hide
*/
public final IContentProvider acquireProvider(Uri uri) {
- if (!SCHEME_CONTENT.equals(uri.getScheme()) && !SCHEME_SLICE.equals(uri.getScheme())) {
+ if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
diff --git a/core/java/android/content/pm/FeatureInfo.java b/core/java/android/content/pm/FeatureInfo.java
index 9ee6fa2431a3..ff9fd8ec31c5 100644
--- a/core/java/android/content/pm/FeatureInfo.java
+++ b/core/java/android/content/pm/FeatureInfo.java
@@ -18,6 +18,7 @@ package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.proto.ProtoOutputStream;
/**
* Definition of a single optional hardware or software feature of an Android
@@ -113,6 +114,18 @@ public class FeatureInfo implements Parcelable {
dest.writeInt(flags);
}
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ if (name != null) {
+ proto.write(FeatureInfoProto.NAME, name);
+ }
+ proto.write(FeatureInfoProto.VERSION, version);
+ proto.write(FeatureInfoProto.GLES_VERSION, getGlEsVersion());
+ proto.write(FeatureInfoProto.FLAGS, flags);
+ proto.end(token);
+ }
+
public static final Creator<FeatureInfo> CREATOR = new Creator<FeatureInfo>() {
@Override
public FeatureInfo createFromParcel(Parcel source) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 560b4b31cdc6..84111fbf7f93 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -84,9 +84,6 @@ public class SystemProperties {
/**
* Get the String value for the given {@code key}.
*
- * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
- * method will crash in native code.
- *
* @param key the key to lookup
* @return an empty string if the {@code key} isn't found
*/
@@ -99,9 +96,6 @@ public class SystemProperties {
/**
* Get the String value for the given {@code key}.
*
- * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
- * method will crash in native code.
- *
* @param key the key to lookup
* @param def the default value in case the property is not set or empty
* @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 53e888176162..b43507465384 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5708,6 +5708,7 @@ public final class Settings {
*
* @hide
*/
+ @TestApi
public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
"accessibility_display_magnification_enabled";
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 3426485e93ab..afa941316be7 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -528,84 +528,23 @@ public class ViewDebug {
/** @hide */
public static void profileViewAndChildren(final View view, BufferedWriter out)
throws IOException {
- profileViewAndChildren(view, out, true);
+ RenderNode node = RenderNode.create("ViewDebug", null);
+ profileViewAndChildren(view, node, out, true);
+ node.destroy();
}
- private static void profileViewAndChildren(final View view, BufferedWriter out, boolean root)
- throws IOException {
-
+ private static void profileViewAndChildren(View view, RenderNode node, BufferedWriter out,
+ boolean root) throws IOException {
long durationMeasure =
(root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0)
- ? profileViewOperation(view, new ViewOperation<Void>() {
- public Void[] pre() {
- forceLayout(view);
- return null;
- }
-
- private void forceLayout(View view) {
- view.forceLayout();
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
- final int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- forceLayout(group.getChildAt(i));
- }
- }
- }
-
- public void run(Void... data) {
- view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
- }
-
- public void post(Void... data) {
- }
- })
- : 0;
+ ? profileViewMeasure(view) : 0;
long durationLayout =
(root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0)
- ? profileViewOperation(view, new ViewOperation<Void>() {
- public Void[] pre() {
- return null;
- }
-
- public void run(Void... data) {
- view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom);
- }
-
- public void post(Void... data) {
- }
- }) : 0;
+ ? profileViewLayout(view) : 0;
long durationDraw =
(root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0)
- ? profileViewOperation(view, new ViewOperation<Object>() {
- public Object[] pre() {
- final DisplayMetrics metrics =
- (view != null && view.getResources() != null) ?
- view.getResources().getDisplayMetrics() : null;
- final Bitmap bitmap = metrics != null ?
- Bitmap.createBitmap(metrics, metrics.widthPixels,
- metrics.heightPixels, Bitmap.Config.RGB_565) : null;
- final Canvas canvas = bitmap != null ? new Canvas(bitmap) : null;
- return new Object[] {
- bitmap, canvas
- };
- }
+ ? profileViewDraw(view, node) : 0;
- public void run(Object... data) {
- if (data[1] != null) {
- view.draw((Canvas) data[1]);
- }
- }
-
- public void post(Object... data) {
- if (data[1] != null) {
- ((Canvas) data[1]).setBitmap(null);
- }
- if (data[0] != null) {
- ((Bitmap) data[0]).recycle();
- }
- }
- }) : 0;
out.write(String.valueOf(durationMeasure));
out.write(' ');
out.write(String.valueOf(durationLayout));
@@ -616,34 +555,86 @@ public class ViewDebug {
ViewGroup group = (ViewGroup) view;
final int count = group.getChildCount();
for (int i = 0; i < count; i++) {
- profileViewAndChildren(group.getChildAt(i), out, false);
+ profileViewAndChildren(group.getChildAt(i), node, out, false);
+ }
+ }
+ }
+
+ private static long profileViewMeasure(final View view) {
+ return profileViewOperation(view, new ViewOperation() {
+ @Override
+ public void pre() {
+ forceLayout(view);
+ }
+
+ private void forceLayout(View view) {
+ view.forceLayout();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+ final int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ forceLayout(group.getChildAt(i));
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ view.measure(view.mOldWidthMeasureSpec, view.mOldHeightMeasureSpec);
+ }
+ });
+ }
+
+ private static long profileViewLayout(View view) {
+ return profileViewOperation(view,
+ () -> view.layout(view.mLeft, view.mTop, view.mRight, view.mBottom));
+ }
+
+ private static long profileViewDraw(View view, RenderNode node) {
+ DisplayMetrics dm = view.getResources().getDisplayMetrics();
+ if (dm == null) {
+ return 0;
+ }
+
+ if (view.isHardwareAccelerated()) {
+ DisplayListCanvas canvas = node.start(dm.widthPixels, dm.heightPixels);
+ try {
+ return profileViewOperation(view, () -> view.draw(canvas));
+ } finally {
+ node.end(canvas);
+ }
+ } else {
+ Bitmap bitmap = Bitmap.createBitmap(
+ dm, dm.widthPixels, dm.heightPixels, Bitmap.Config.RGB_565);
+ Canvas canvas = new Canvas(bitmap);
+ try {
+ return profileViewOperation(view, () -> view.draw(canvas));
+ } finally {
+ canvas.setBitmap(null);
+ bitmap.recycle();
}
}
}
- interface ViewOperation<T> {
- T[] pre();
- void run(T... data);
- void post(T... data);
+ interface ViewOperation {
+ default void pre() {}
+
+ void run();
}
- private static <T> long profileViewOperation(View view, final ViewOperation<T> operation) {
+ private static long profileViewOperation(View view, final ViewOperation operation) {
final CountDownLatch latch = new CountDownLatch(1);
final long[] duration = new long[1];
- view.post(new Runnable() {
- public void run() {
- try {
- T[] data = operation.pre();
- long start = Debug.threadCpuTimeNanos();
- //noinspection unchecked
- operation.run(data);
- duration[0] = Debug.threadCpuTimeNanos() - start;
- //noinspection unchecked
- operation.post(data);
- } finally {
- latch.countDown();
- }
+ view.post(() -> {
+ try {
+ operation.pre();
+ long start = Debug.threadCpuTimeNanos();
+ //noinspection unchecked
+ operation.run();
+ duration[0] = Debug.threadCpuTimeNanos() - start;
+ } finally {
+ latch.countDown();
}
});
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 44f304dd8781..e564fa344ce5 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -997,7 +997,12 @@ public final class AutofillManager {
}
private AutofillClient getClientLocked() {
- return mContext.getAutofillClient();
+ final AutofillClient client = mContext.getAutofillClient();
+ if (client == null && sDebug) {
+ Log.d(TAG, "No AutofillClient for " + mContext.getPackageName() + " on context "
+ + mContext);
+ }
+ return client;
}
/** @hide */
@@ -1579,6 +1584,7 @@ public final class AutofillManager {
final String pfx = outerPrefix + " ";
pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
+ pw.print(pfx); pw.print("context: "); pw.println(mContext);
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);
diff --git a/core/java/android/view/textclassifier/SmartSelection.java b/core/java/android/view/textclassifier/SmartSelection.java
index f0e83d1fd85f..2c93a19bbe0e 100644
--- a/core/java/android/view/textclassifier/SmartSelection.java
+++ b/core/java/android/view/textclassifier/SmartSelection.java
@@ -16,6 +16,8 @@
package android.view.textclassifier;
+import android.content.res.AssetFileDescriptor;
+
/**
* Java wrapper for SmartSelection native library interface.
* This library is used for detecting entities in text.
@@ -42,6 +44,26 @@ final class SmartSelection {
}
/**
+ * Creates a new instance of SmartSelect predictor, using the provided model image, given as a
+ * file path.
+ */
+ SmartSelection(String path) {
+ mCtx = nativeNewFromPath(path);
+ }
+
+ /**
+ * Creates a new instance of SmartSelect predictor, using the provided model image, given as an
+ * AssetFileDescriptor.
+ */
+ SmartSelection(AssetFileDescriptor afd) {
+ mCtx = nativeNewFromAssetFileDescriptor(afd, afd.getStartOffset(), afd.getLength());
+ if (mCtx == 0L) {
+ throw new IllegalArgumentException(
+ "Couldn't initialize TC from given AssetFileDescriptor");
+ }
+ }
+
+ /**
* Given a string context and current selection, computes the SmartSelection suggestion.
*
* The begin and end are character indices into the context UTF8 string. selectionBegin is the
@@ -69,6 +91,15 @@ final class SmartSelection {
}
/**
+ * Annotates given input text. Every word of the input is a part of some annotation.
+ * The annotations are sorted by their position in the context string.
+ * The annotations do not overlap.
+ */
+ public AnnotatedSpan[] annotate(String text) {
+ return nativeAnnotate(mCtx, text);
+ }
+
+ /**
* Frees up the allocated memory.
*/
public void close() {
@@ -91,12 +122,19 @@ final class SmartSelection {
private static native long nativeNew(int fd);
+ private static native long nativeNewFromPath(String path);
+
+ private static native long nativeNewFromAssetFileDescriptor(AssetFileDescriptor afd,
+ long offset, long size);
+
private static native int[] nativeSuggest(
long context, String text, int selectionBegin, int selectionEnd);
private static native ClassificationResult[] nativeClassifyText(
long context, String text, int selectionBegin, int selectionEnd, int hintFlags);
+ private static native AnnotatedSpan[] nativeAnnotate(long context, String text);
+
private static native void nativeClose(long context);
private static native String nativeGetLanguage(int fd);
@@ -114,4 +152,29 @@ final class SmartSelection {
mScore = score;
}
}
+
+ /** Represents a result of Annotate call. */
+ public static final class AnnotatedSpan {
+ final int mStartIndex;
+ final int mEndIndex;
+ final ClassificationResult[] mClassification;
+
+ AnnotatedSpan(int startIndex, int endIndex, ClassificationResult[] classification) {
+ mStartIndex = startIndex;
+ mEndIndex = endIndex;
+ mClassification = classification;
+ }
+
+ public int getStartIndex() {
+ return mStartIndex;
+ }
+
+ public int getEndIndex() {
+ return mEndIndex;
+ }
+
+ public ClassificationResult[] getClassification() {
+ return mClassification;
+ }
+ }
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 91f6799e26ed..d4be7e5784e0 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -476,6 +476,17 @@ public class Editor {
stopTextActionModeWithPreservingSelection();
}
+ void invalidateMagnifier() {
+ final DisplayMetrics dm = mTextView.getResources().getDisplayMetrics();
+ invalidateMagnifier(0, 0, dm.widthPixels, dm.heightPixels);
+ }
+
+ void invalidateMagnifier(final float l, final float t, final float r, final float b) {
+ if (mMagnifier != null) {
+ mTextView.post(() -> mMagnifier.invalidate(new RectF(l, t, r, b)));
+ }
+ }
+
private void discardTextDisplayLists() {
if (mTextRenderNodes != null) {
for (int i = 0; i < mTextRenderNodes.length; i++) {
@@ -4545,10 +4556,8 @@ public class Editor {
+ mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f;
final int[] coordinatesOnScreen = new int[2];
mTextView.getLocationOnScreen(coordinatesOnScreen);
- final float centerXOnScreen = xPosInView + mTextView.getTotalPaddingLeft()
- - mTextView.getScrollX() + coordinatesOnScreen[0];
- final float centerYOnScreen = yPosInView + mTextView.getTotalPaddingTop()
- - mTextView.getScrollY() + coordinatesOnScreen[1];
+ final float centerXOnScreen = mTextView.convertViewToScreenCoord(xPosInView, true);
+ final float centerYOnScreen = mTextView.convertViewToScreenCoord(yPosInView, false);
suspendBlink();
mMagnifier.show(centerXOnScreen, centerYOnScreen, MAGNIFIER_ZOOM);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d9bc51fffd6a..ce805526e4ad 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9219,6 +9219,36 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ @Override
+ public void invalidate() {
+ super.invalidate();
+
+ if (mEditor != null) {
+ mEditor.invalidateMagnifier();
+ }
+ }
+
+ @Override
+ public void invalidate(int l, int t, int r, int b) {
+ super.invalidate(l, t, r, b);
+
+ if (mEditor != null) {
+ mEditor.invalidateMagnifier(
+ convertViewToScreenCoord(l, true /* isHorizontal */),
+ convertViewToScreenCoord(t, false /* isHorizontal */),
+ convertViewToScreenCoord(r, true /* isHorizontal */),
+ convertViewToScreenCoord(b, false /* isHorizontal */));
+ }
+ }
+
+ float convertViewToScreenCoord(float viewCoord, boolean isHorizontal) {
+ final int[] coordinatesOnScreen = new int[2];
+ getLocationOnScreen(coordinatesOnScreen);
+ return isHorizontal
+ ? viewCoord + getTotalPaddingLeft() - getScrollX() + coordinatesOnScreen[0]
+ : viewCoord + getTotalPaddingTop() - getScrollY() + coordinatesOnScreen[1];
+ }
+
/**
* @return whether or not the cursor is visible (assuming this TextView is editable)
*
diff --git a/core/java/com/android/internal/widget/Magnifier.java b/core/java/com/android/internal/widget/Magnifier.java
index 284f2b2b7e12..9bc0778d9be6 100644
--- a/core/java/com/android/internal/widget/Magnifier.java
+++ b/core/java/com/android/internal/widget/Magnifier.java
@@ -22,7 +22,9 @@ import android.annotation.UiThread;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
@@ -41,8 +43,8 @@ import com.android.internal.util.Preconditions;
*/
public final class Magnifier {
private static final String LOG_TAG = "magnifier";
- private static final int MINIMUM_MAGNIFIER_SCALE = 1;
- private static final int MAXIMUM_MAGNIFIER_SCALE = 4;
+ // Use this to specify that a previous configuration value does not exist.
+ private static final int INEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
// The view for which this magnifier is attached.
private final View mView;
// The window containing the magnifier.
@@ -61,6 +63,15 @@ public final class Magnifier {
// the copy is finished.
private final Handler mPixelCopyHandler = Handler.getMain();
+ private RectF mTmpRectF;
+
+ // Variables holding previous states, used for detecting redundant calls and invalidation.
+ private Point mPrevStartCoordsOnScreen = new Point(
+ INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
+ private PointF mPrevCenterCoordsOnScreen = new PointF(
+ INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
+ private float mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+
/**
* Initializes a magnifier.
*
@@ -90,19 +101,22 @@ public final class Magnifier {
/**
* Shows the magnifier on the screen.
*
- * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source
- * @param centerYOnScreen vertical coordinate of the center point of the magnifier source
- * @param scale the scale at which the magnifier zooms on the source content
+ * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source. The
+ * lower end is clamped to 0
+ * @param centerYOnScreen vertical coordinate of the center point of the magnifier source. The
+ * lower end is clamped to 0
+ * @param scale the scale at which the magnifier zooms on the source content. The
+ * lower end is clamped to 1 and the higher end to 4
*/
public void show(@FloatRange(from=0) float centerXOnScreen,
@FloatRange(from=0) float centerYOnScreen,
- @FloatRange(from=MINIMUM_MAGNIFIER_SCALE, to=MAXIMUM_MAGNIFIER_SCALE) float scale) {
- if (scale > MAXIMUM_MAGNIFIER_SCALE) {
- scale = MAXIMUM_MAGNIFIER_SCALE;
+ @FloatRange(from=1, to=4) float scale) {
+ if (scale > 4) {
+ scale = 4;
}
- if (scale < MINIMUM_MAGNIFIER_SCALE) {
- scale = MINIMUM_MAGNIFIER_SCALE;
+ if (scale < 1) {
+ scale = 1;
}
if (centerXOnScreen < 0) {
@@ -113,9 +127,19 @@ public final class Magnifier {
centerYOnScreen = 0;
}
- maybeResizeBitmap(scale);
+ showInternal(centerXOnScreen, centerYOnScreen, scale, false);
+ }
+
+ private void showInternal(@FloatRange(from=0) float centerXOnScreen,
+ @FloatRange(from=0) float centerYOnScreen,
+ @FloatRange(from=1, to=4) float scale,
+ boolean forceShow) {
+ if (mPrevScale != scale) {
+ resizeBitmap(scale);
+ mPrevScale = scale;
+ }
configureCoordinates(centerXOnScreen, centerYOnScreen);
- performPixelCopy();
+ maybePerformPixelCopy(scale, forceShow);
if (mWindow.isShowing()) {
mWindow.update(mWindowCoords.x, mWindowCoords.y, mWindow.getWidth(),
@@ -124,6 +148,9 @@ public final class Magnifier {
mWindow.showAtLocation(mView.getRootView(), Gravity.NO_GRAVITY,
mWindowCoords.x, mWindowCoords.y);
}
+
+ mPrevCenterCoordsOnScreen.x = centerXOnScreen;
+ mPrevCenterCoordsOnScreen.y = centerYOnScreen;
}
/**
@@ -131,6 +158,38 @@ public final class Magnifier {
*/
public void dismiss() {
mWindow.dismiss();
+
+ mPrevStartCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevStartCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevCenterCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevCenterCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+ mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
+ }
+
+ /**
+ * Forces the magnifier to update content by taking and showing a new snapshot using the
+ * previous coordinates. It does this only if the magnifier is showing and the dirty rectangle
+ * intersects the rectangle which holds the content to be magnified.
+ *
+ * @param dirtyRectOnScreen the rectangle representing the screen bounds of the dirty region
+ */
+ public void invalidate(RectF dirtyRectOnScreen) {
+ if (mWindow.isShowing() && mPrevCenterCoordsOnScreen.x != INEXISTENT_PREVIOUS_CONFIG_VALUE
+ && mPrevCenterCoordsOnScreen.y != INEXISTENT_PREVIOUS_CONFIG_VALUE
+ && mPrevScale != INEXISTENT_PREVIOUS_CONFIG_VALUE) {
+ // Update the current showing RectF.
+ mTmpRectF = new RectF(mPrevStartCoordsOnScreen.x,
+ mPrevStartCoordsOnScreen.y,
+ mPrevStartCoordsOnScreen.x + mBitmap.getWidth(),
+ mPrevStartCoordsOnScreen.y + mBitmap.getHeight());
+
+ // Update only if we are currently showing content that has been declared as invalid.
+ if (RectF.intersects(dirtyRectOnScreen, mTmpRectF)) {
+ // Update the contents shown in the magnifier.
+ showInternal(mPrevCenterCoordsOnScreen.x, mPrevCenterCoordsOnScreen.y, mPrevScale,
+ true /* forceShow */);
+ }
+ }
}
/**
@@ -147,13 +206,11 @@ public final class Magnifier {
return mWindowWidth;
}
- private void maybeResizeBitmap(float scale) {
+ private void resizeBitmap(float scale) {
final int bitmapWidth = (int) (mWindowWidth / scale);
final int bitmapHeight = (int) (mWindowHeight / scale);
- if (mBitmap.getWidth() != bitmapWidth || mBitmap.getHeight() != bitmapHeight) {
- mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
- getImageView().setImageBitmap(mBitmap);
- }
+ mBitmap.reconfigure(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
+ getImageView().setImageBitmap(mBitmap);
}
private void configureCoordinates(float posXOnScreen, float posYOnScreen) {
@@ -166,16 +223,25 @@ public final class Magnifier {
mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalMagnifierOffset;
}
- private void performPixelCopy() {
- int startX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
+ private void maybePerformPixelCopy(final float scale, final boolean forceShow) {
+ final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
+ int rawStartX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;
+
// Clamp startX value to avoid distorting the rendering of the magnifier content.
- if (startX < 0) {
- startX = 0;
- } else if (startX + mBitmap.getWidth() > mView.getWidth()) {
- startX = mView.getWidth() - mBitmap.getWidth();
+ if (rawStartX < 0) {
+ rawStartX = 0;
+ } else if (rawStartX + mBitmap.getWidth() > mView.getWidth()) {
+ rawStartX = mView.getWidth() - mBitmap.getWidth();
}
- final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
+ if (!forceShow && rawStartX == mPrevStartCoordsOnScreen.x
+ && startY == mPrevStartCoordsOnScreen.y
+ && scale == mPrevScale) {
+ // Skip, we are already showing the desired content.
+ return;
+ }
+
+ final int startX = rawStartX;
final ViewRootImpl viewRootImpl = mView.getViewRootImpl();
if (viewRootImpl != null && viewRootImpl.mSurface != null
@@ -185,7 +251,11 @@ public final class Magnifier {
new Rect(startX, startY, startX + mBitmap.getWidth(),
startY + mBitmap.getHeight()),
mBitmap,
- result -> getImageView().invalidate(),
+ result -> {
+ getImageView().invalidate();
+ mPrevStartCoordsOnScreen.x = startX;
+ mPrevStartCoordsOnScreen.y = startY;
+ },
mPixelCopyHandler);
} else {
Log.d(LOG_TAG, "Could not perform PixelCopy request");
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index b46f38959d6b..05bec28a5d39 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -83,6 +83,7 @@ static void init() {
constexpr int INDIC_MIN_SUFFIX = 2;
addHyphenator("as", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Assamese
+ addHyphenator("be", 2, 2); // Belarusian
addHyphenator("bg", 2, 2); // Bulgarian
addHyphenator("bn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Bengali
addHyphenator("cu", 1, 2); // Church Slavonic
@@ -106,6 +107,7 @@ static void init() {
// Going with a more conservative value of (2, 2) for now.
addHyphenator("hy", 2, 2); // Armenian
addHyphenator("kn", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Kannada
+ addHyphenator("la", 2, 2); // Latin
addHyphenator("ml", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Malayalam
addHyphenator("mn-Cyrl", 2, 2); // Mongolian in Cyrillic script
addHyphenator("mr", INDIC_MIN_PREFIX, INDIC_MIN_SUFFIX); // Marathi
diff --git a/core/proto/android/content/featureinfo.proto b/core/proto/android/content/featureinfo.proto
new file mode 100644
index 000000000000..a7501204b43f
--- /dev/null
+++ b/core/proto/android/content/featureinfo.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 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 = "proto2";
+
+option java_package = "android.content.pm";
+option java_multiple_files = true;
+
+package android.content.pm;
+
+message FeatureInfoProto {
+ optional string name = 1;
+ optional int32 version = 2;
+ optional string gles_version = 3;
+ optional int32 flags = 4;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index c9d7b4966cef..5a5454e2f6ae 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -100,7 +100,11 @@ message IncidentProto {
(section).args = "diskstats --proto"
];
- optional android.service.pm.PackageServiceDumpProto package = 3008;
+ optional android.service.pm.PackageServiceDumpProto package = 3008 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "package --proto"
+ ];
+
optional android.service.power.PowerServiceDumpProto power = 3009;
optional android.service.print.PrintServiceDumpProto print = 3010;
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index be82e2d549f9..aa1a575a5c93 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -17,6 +17,8 @@
syntax = "proto2";
package android.service.pm;
+import "frameworks/base/core/proto/android/content/featureinfo.proto";
+
option java_multiple_files = true;
option java_outer_classname = "PackageServiceProto";
@@ -36,10 +38,6 @@ message PackageServiceDumpProto {
// Should be filled if is_jar is false
optional string apk = 4;
}
- message FeatureProto {
- optional string name = 1;
- optional int32 version = 2;
- }
message SharedUserProto {
optional int32 user_id = 1;
optional string name = 2;
@@ -49,7 +47,7 @@ message PackageServiceDumpProto {
optional PackageShortProto required_verifier_package = 1;
optional PackageShortProto verifier_package = 2;
repeated SharedLibraryProto shared_libraries = 3;
- repeated FeatureProto features = 4;
+ repeated android.content.pm.FeatureInfoProto features = 4;
repeated PackageProto packages = 5;
repeated SharedUserProto shared_users = 6;
// Messages from the settings problem file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 37b5d5d6e206..105bb7ef9f3f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3112,7 +3112,7 @@
<!-- Allows an application to bind app's slices and get their
content. This content will be surfaced to the
user and not to leave the device.
- <p>Not for use by third-party applications. @hide -->
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_SLICE"
android:protectionLevel="signature|privileged|development" />
diff --git a/core/res/res/layout/slice_grid.xml b/core/res/res/layout/slice_grid.xml
index 70df76b0ec60..15ded7b3800e 100644
--- a/core/res/res/layout/slice_grid.xml
+++ b/core/res/res/layout/slice_grid.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<android.slice.views.GridView
+<android.app.slice.views.GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -21,4 +21,4 @@
android:gravity="center_vertical"
android:background="?android:attr/activatedBackgroundIndicator"
android:clipToPadding="false">
-</android.slice.views.GridView>
+</android.app.slice.views.GridView>
diff --git a/core/res/res/layout/slice_message.xml b/core/res/res/layout/slice_message.xml
index a3279b652c84..96f8078f224d 100644
--- a/core/res/res/layout/slice_message.xml
+++ b/core/res/res/layout/slice_message.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<android.slice.views.MessageView
+<android.app.slice.views.MessageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -48,4 +48,4 @@
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItem"
android:maxLines="10" />
-</android.slice.views.MessageView>
+</android.app.slice.views.MessageView>
diff --git a/core/res/res/layout/slice_message_local.xml b/core/res/res/layout/slice_message_local.xml
index d4180f35250b..5c767ba6b8ef 100644
--- a/core/res/res/layout/slice_message_local.xml
+++ b/core/res/res/layout/slice_message_local.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<android.slice.views.MessageView
+<android.app.slice.views.MessageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -35,4 +35,4 @@
android:background="#ffeeeeee"
android:maxLines="10" />
-</android.slice.views.MessageView>
+</android.app.slice.views.MessageView>
diff --git a/core/res/res/layout/slice_remote_input.xml b/core/res/res/layout/slice_remote_input.xml
index dc570c43ef99..90d0c82be5e7 100644
--- a/core/res/res/layout/slice_remote_input.xml
+++ b/core/res/res/layout/slice_remote_input.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<!-- LinearLayout -->
-<android.slice.views.RemoteInputView
+<android.app.slice.views.RemoteInputView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/remote_input"
android:background="@drawable/slice_remote_input_bg"
@@ -73,4 +73,4 @@
</FrameLayout>
-</android.slice.views.RemoteInputView> \ No newline at end of file
+</android.app.slice.views.RemoteInputView> \ No newline at end of file
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 91c107a3775f..93c02b0e05f6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2715,8 +2715,6 @@
<string name="yes">OK</string>
<!-- Preference framework strings. -->
<string name="no">Cancel</string>
- <!-- Preference framework strings. -->
- <string name="close">CLOSE</string>
<!-- This is the generic "attention" string to be used in attention dialogs. Typically
combined with setIconAttribute(android.R.attr.alertDialogIcon)
(or setIcon(android.R.drawable.ic_dialog_alert) on legacy versions of the platform) -->
@@ -2849,11 +2847,6 @@
<!-- [CHAR LIMIT=200] Compat mode dialog: hint to re-enable compat mode dialog. -->
<string name="screen_compat_mode_hint">Re-enable this in System settings &gt; Apps &gt; Downloaded.</string>
- <!-- Text of the alert that is displayed when a top application is killed by lmk. -->
- <string name="top_app_killed_title">App isn\'t responding</string>
- <!-- Top app killed by lmk dialog message. -->
- <string name="top_app_killed_message"><xliff:g id="app_name">%1$s</xliff:g> may be using too much memory.</string>
-
<!-- [CHAR LIMIT=200] Unsupported display size dialog: message. Refers to "Display size" setting. -->
<string name="unsupported_display_size_message"><xliff:g id="app_name">%1$s</xliff:g> does not support the current Display size setting and may behave unexpectedly.</string>
<!-- [CHAR LIMIT=50] Unsupported display size dialog: check box label. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1307ae2e2c9b..260a5198365b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1901,9 +1901,6 @@
<java-symbol type="string" name="anr_application_process" />
<java-symbol type="string" name="anr_process" />
<java-symbol type="string" name="anr_title" />
- <java-symbol type="string" name="top_app_killed_title" />
- <java-symbol type="string" name="top_app_killed_message" />
- <java-symbol type="string" name="close" />
<java-symbol type="string" name="car_mode_disable_notification_message" />
<java-symbol type="string" name="car_mode_disable_notification_title" />
<java-symbol type="string" name="chooser_wallpaper" />
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ad6ce2c4a9d6..40aecac5e27d 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -255,11 +255,13 @@ cc_library {
// Build libhwui with PGO by default.
// Location of PGO profile data is defined in build/soong/cc/pgo.go
// and is separate from hwui.
- // To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable.
+ // To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable
+ // or set enable_profile_use property to false.
pgo: {
instrumentation: true,
profile_file: "hwui/hwui.profdata",
benchmarks: ["hwui"],
+ enable_profile_use: false,
},
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 4ea4e3810e03..760cc49bc1e2 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -395,7 +395,7 @@ public class MediaMetadataRetriever
* @see #getFrameAtTime(long, int)
*/
/* Do not change these option values without updating their counterparts
- * in include/media/stagefright/MediaSource.h!
+ * in include/media/MediaSource.h!
*/
/**
* This option is used with {@link #getFrameAtTime(long, int)} to retrieve
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index d2fa8f5f4c2a..5c90d0020d61 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -37,7 +37,8 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSource.h>
+#include <media/DataSource.h>
+#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/NuMediaExtractor.h>
@@ -744,7 +745,7 @@ static void android_media_MediaExtractor_setDataSourceCallback(
}
sp<DataSource> bridge =
- DataSource::CreateFromIDataSource(new JMediaDataSource(env, callbackObj));
+ CreateDataSourceFromIDataSource(new JMediaDataSource(env, callbackObj));
status_t err = extractor->setDataSource(bridge);
if (err != OK) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 94d36f25ae1c..a4638ac43184 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -18,8 +18,8 @@
#define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/DataSource.h>
+#include <media/MediaSource.h>
+#include <media/DataSource.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 5f1cf1608942..ab0da072047c 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -26,7 +26,6 @@
#include <media/AudioTrack.h>
#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
-#include <media/stagefright/MediaExtractor.h>
#include "SoundPool.h"
#include "SoundPoolThread.h"
#include <media/AudioPolicyHelper.h>
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index fa6423ecb8c7..88b85e078f45 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -30,8 +30,11 @@ LOCAL_BUILT_MODULE_STEM := package.apk
# Make sure the build system doesn't try to resign the APK
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-LOCAL_SRC_FILES := CtsShimPriv.apk
+my_archs := arm x86
+my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
+LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShimPriv.apk
include $(BUILD_PREBUILT)
@@ -48,8 +51,11 @@ LOCAL_BUILT_MODULE_STEM := package.apk
# Make sure the build system doesn't try to resign the APK
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-LOCAL_SRC_FILES := CtsShim.apk
+my_archs := arm x86
+my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
+LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShim.apk
include $(BUILD_PREBUILT)
diff --git a/packages/CtsShim/CtsShim.apk b/packages/CtsShim/CtsShim.apk
deleted file mode 100644
index 27289037dd8b..000000000000
--- a/packages/CtsShim/CtsShim.apk
+++ /dev/null
Binary files differ
diff --git a/packages/CtsShim/CtsShimPriv.apk b/packages/CtsShim/CtsShimPriv.apk
deleted file mode 100644
index 9a8e75c28b05..000000000000
--- a/packages/CtsShim/CtsShimPriv.apk
+++ /dev/null
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShim.apk b/packages/CtsShim/apk/arm/CtsShim.apk
new file mode 100644
index 000000000000..a91160368cb8
--- /dev/null
+++ b/packages/CtsShim/apk/arm/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/arm/CtsShimPriv.apk b/packages/CtsShim/apk/arm/CtsShimPriv.apk
new file mode 100644
index 000000000000..845d781f38f3
--- /dev/null
+++ b/packages/CtsShim/apk/arm/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShim.apk b/packages/CtsShim/apk/x86/CtsShim.apk
new file mode 100644
index 000000000000..a91160368cb8
--- /dev/null
+++ b/packages/CtsShim/apk/x86/CtsShim.apk
Binary files differ
diff --git a/packages/CtsShim/apk/x86/CtsShimPriv.apk b/packages/CtsShim/apk/x86/CtsShimPriv.apk
new file mode 100644
index 000000000000..2fc9a94037fa
--- /dev/null
+++ b/packages/CtsShim/apk/x86/CtsShimPriv.apk
Binary files differ
diff --git a/packages/CtsShim/build/README b/packages/CtsShim/build/README
index 9869377738b8..59af068f0587 100644
--- a/packages/CtsShim/build/README
+++ b/packages/CtsShim/build/README
@@ -6,19 +6,34 @@ must specify the singular APK that can be used to upgrade it.
NOTE: The need to include a binary on the system image may be deprecated if a
solution involving a temporarily writable /system partition is implemented.
-build:
- $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA
+For local testing, build the apk and put them in the following folders.
+This is for arm:
+ $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA arm64
$ m
+ $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+ cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm
+ $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+ vendor/xts/gts-tests/hostsidetests/packagemanager/app/apk/arm/GtsShimPrivUpgrade.apk
+ $ cp $OUT/system/priv-app/CtsShimPrivUpgradeWrongSHA/CtsShimPrivUpgradeWrongSHA.apk \
+ cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/arm
+ $ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
+ frameworks/base/packages/CtsShim/apk/arm
+ $ cp $OUT/system/app/CtsShim/CtsShim.apk \
+ frameworks/base/packages/CtsShim/apk/arm
-local testing:
+This is for x86:
+ $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade CtsShimPrivUpgradeWrongSHA x86_64
+ $ m
+ $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+ cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86
$ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
- cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
+ vendor/xts/gts-tests/hostsidetests/packagemanager/app/apk/x86/GtsShimPrivUpgrade.apk
$ cp $OUT/system/priv-app/CtsShimPrivUpgradeWrongSHA/CtsShimPrivUpgradeWrongSHA.apk \
- cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
+ cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp/apk/x86
$ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
- frameworks/base/packages/CtsShim
+ frameworks/base/packages/CtsShim/apk/x86
$ cp $OUT/system/app/CtsShim/CtsShim.apk \
- frameworks/base/packages/CtsShim
+ frameworks/base/packages/CtsShim/apk/x86
For final submission, the APKs should be downloaded from the build server, then
submitted to the cts/ and frameworks/base/ repos.
diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
index 253ca11bc44e..90124f1f558f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java
@@ -20,6 +20,7 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.support.annotation.CallSuper;
import android.support.v14.preference.EditTextPreferenceDialogFragment;
import android.support.v7.preference.EditTextPreference;
import android.util.AttributeSet;
@@ -30,7 +31,8 @@ public class CustomEditTextPreference extends EditTextPreference {
private CustomPreferenceDialogFragment mFragment;
- public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@@ -69,7 +71,12 @@ public class CustomEditTextPreference extends EditTextPreference {
protected void onClick(DialogInterface dialog, int which) {
}
+ @CallSuper
protected void onBindDialogView(View view) {
+ final EditText editText = view.findViewById(android.R.id.edit);
+ if (editText != null) {
+ editText.requestFocus();
+ }
}
private void setFragment(CustomPreferenceDialogFragment fragment) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
index 67553adc528c..77b2d86c445f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java
@@ -68,7 +68,7 @@ public abstract class AbstractLogpersistPreferenceController extends
public AbstractLogpersistPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
- if (isAvailable()) {
+ if (isAvailable() && lifecycle != null) {
lifecycle.addObserver(this);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
new file mode 100644
index 000000000000..17c7d13fe67e
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.settingslib;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class CustomEditTextPreferenceTest {
+
+ @Mock
+ private View mView;
+
+ private TestPreference mPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mPreference = new TestPreference(RuntimeEnvironment.application);
+ }
+
+ @Test
+ public void bindDialogView_shouldRequestFocus() {
+ final String testText = "";
+ final EditText editText = spy(new EditText(RuntimeEnvironment.application));
+ editText.setText(testText);
+ when(mView.findViewById(android.R.id.edit)).thenReturn(editText);
+
+ mPreference.onBindDialogView(mView);
+
+ verify(editText).requestFocus();
+ }
+
+ private static class TestPreference extends CustomEditTextPreference {
+ public TestPreference(Context context) {
+ super(context);
+ }
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 06d00be8aee8..1557d911e6bf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2319,8 +2319,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
R.bool.def_screen_brightness_automatic_mode);
- loadDefaultAnimationSettings(stmt);
-
loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
R.bool.def_accelerometer_rotation);
@@ -2514,6 +2512,8 @@ class DatabaseHelper extends SQLiteOpenHelper {
loadSetting(stmt, Settings.Global.MODE_RINGER,
AudioManager.RINGER_MODE_NORMAL);
+ loadDefaultAnimationSettings(stmt);
+
// --- Previously in 'secure'
loadBooleanSetting(stmt, Settings.Global.PACKAGE_VERIFIER_ENABLE,
R.bool.def_package_verifier_enable);
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 2fd7e87a683e..2c5eb27abe3d 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-unde
LOCAL_STATIC_ANDROID_LIBRARIES := \
SystemUIPluginLib \
+ SystemUISharedLib \
android-support-v4 \
android-support-v7-recyclerview \
android-support-v7-preference \
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index b4b4e19028b0..c52c0aae3556 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -26,6 +26,7 @@ import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
import java.util.Objects;
+import java.util.function.Supplier;
@ProvidesInterface(version = QSTile.VERSION)
@DependsOn(target = QSIconView.class)
@@ -104,6 +105,7 @@ public interface QSTile {
public static class State {
public static final int VERSION = 1;
public Icon icon;
+ public Supplier<Icon> iconSupplier;
public int state = Tile.STATE_ACTIVE;
public CharSequence label;
public CharSequence contentDescription;
@@ -118,6 +120,7 @@ public interface QSTile {
if (other == null) throw new IllegalArgumentException();
if (!other.getClass().equals(getClass())) throw new IllegalArgumentException();
final boolean changed = !Objects.equals(other.icon, icon)
+ || !Objects.equals(other.iconSupplier, iconSupplier)
|| !Objects.equals(other.label, label)
|| !Objects.equals(other.contentDescription, contentDescription)
|| !Objects.equals(other.dualLabelContentDescription,
@@ -130,6 +133,7 @@ public interface QSTile {
|| !Objects.equals(other.dualTarget, dualTarget)
|| !Objects.equals(other.slash, slash);
other.icon = icon;
+ other.iconSupplier = iconSupplier;
other.label = label;
other.contentDescription = contentDescription;
other.dualLabelContentDescription = dualLabelContentDescription;
@@ -150,6 +154,7 @@ public interface QSTile {
protected StringBuilder toStringBuilder() {
final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
sb.append(",icon=").append(icon);
+ sb.append(",iconSupplier=").append(iconSupplier);
sb.append(",label=").append(label);
sb.append(",contentDescription=").append(contentDescription);
sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription);
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7ccb6b0db128..1536b64dc41f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -451,8 +451,6 @@
<string name="accessibility_recents_item_open_app_info">Open <xliff:g id="app" example="Calendar">%s</xliff:g> application info.</string>
<!-- Content description to tell the user an application has been launched from recents -->
<string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
- <!-- Content description of individual recents task. -->
- <string name="accessibility_recents_task_header"><xliff:g id="app" example="Chrome">%1$s</xliff:g> <xliff:g id="activity_label" example="www.google.com">%2$s</xliff:g></string>
<!-- Content description to tell the user a notification has been removed from the notification shade -->
<string name="accessibility_notification_dismissed">Notification dismissed.</string>
@@ -810,10 +808,6 @@
<!-- Recents: Accessibility split to the right -->
<string name="recents_accessibility_split_screen_right">Split screen to the right</string>
- <!-- Fully qualified activity class names to be blacklisted in Recents, add package names into overlay as needed -->
- <string-array name="recents_blacklist_array">
- </string-array>
-
<!-- Expanded Status Bar Header: Battery Charged [CHAR LIMIT=40] -->
<string name="expanded_header_battery_charged">Charged</string>
diff --git a/packages/SystemUI/shared/Android.mk b/packages/SystemUI/shared/Android.mk
new file mode 100644
index 000000000000..88a89bc8eba2
--- /dev/null
+++ b/packages/SystemUI/shared/Android.mk
@@ -0,0 +1,42 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := SystemUISharedLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_JAR_EXCLUDE_FILES := none
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := SharedDummyLib
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := SystemUISharedLib
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH)) \ No newline at end of file
diff --git a/packages/SystemUI/shared/AndroidManifest.xml b/packages/SystemUI/shared/AndroidManifest.xml
new file mode 100644
index 000000000000..43b9c7574141
--- /dev/null
+++ b/packages/SystemUI/shared/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.shared">
+
+ <uses-sdk
+ android:minSdkVersion="26" />
+
+</manifest>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
new file mode 100644
index 000000000000..ddd27b0b38ba
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/BackgroundTaskLoader.java
@@ -0,0 +1,186 @@
+/*
+ * 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.shared.recents.model;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+/**
+ * Background task resource loader
+ */
+class BackgroundTaskLoader implements Runnable {
+ static String TAG = "BackgroundTaskLoader";
+ static boolean DEBUG = false;
+
+ private Context mContext;
+ private final HandlerThread mLoadThread;
+ private final Handler mLoadThreadHandler;
+ private final Handler mMainThreadHandler;
+
+ private final TaskResourceLoadQueue mLoadQueue;
+ private final TaskKeyLruCache<Drawable> mIconCache;
+ private final BitmapDrawable mDefaultIcon;
+
+ private boolean mStarted;
+ private boolean mCancelled;
+ private boolean mWaitingOnLoadQueue;
+
+ private final OnIdleChangedListener mOnIdleChangedListener;
+
+ /** Constructor, creates a new loading thread that loads task resources in the background */
+ public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
+ TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon,
+ OnIdleChangedListener onIdleChangedListener) {
+ mLoadQueue = loadQueue;
+ mIconCache = iconCache;
+ mDefaultIcon = defaultIcon;
+ mMainThreadHandler = new Handler();
+ mOnIdleChangedListener = onIdleChangedListener;
+ mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
+ android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ mLoadThread.start();
+ mLoadThreadHandler = new Handler(mLoadThread.getLooper());
+ }
+
+ /** Restarts the loader thread */
+ void start(Context context) {
+ mContext = context;
+ mCancelled = false;
+ if (!mStarted) {
+ // Start loading on the load thread
+ mStarted = true;
+ mLoadThreadHandler.post(this);
+ } else {
+ // Notify the load thread to start loading again
+ synchronized (mLoadThread) {
+ mLoadThread.notifyAll();
+ }
+ }
+ }
+
+ /** Requests the loader thread to stop after the current iteration */
+ void stop() {
+ // Mark as cancelled for the thread to pick up
+ mCancelled = true;
+ // If we are waiting for the load queue for more tasks, then we can just reset the
+ // Context now, since nothing is using it
+ if (mWaitingOnLoadQueue) {
+ mContext = null;
+ }
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ if (mCancelled) {
+ // We have to unset the context here, since the background thread may be using it
+ // when we call stop()
+ mContext = null;
+ // If we are cancelled, then wait until we are started again
+ synchronized(mLoadThread) {
+ try {
+ mLoadThread.wait();
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+ } else {
+ // If we've stopped the loader, then fall through to the above logic to wait on
+ // the load thread
+ processLoadQueueItem();
+
+ // If there are no other items in the list, then just wait until something is added
+ if (!mCancelled && mLoadQueue.isEmpty()) {
+ synchronized(mLoadQueue) {
+ try {
+ mWaitingOnLoadQueue = true;
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(true));
+ mLoadQueue.wait();
+ mMainThreadHandler.post(
+ () -> mOnIdleChangedListener.onIdleChanged(false));
+ mWaitingOnLoadQueue = false;
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This needs to be in a separate method to work around an surprising interpreter behavior:
+ * The register will keep the local reference to cachedThumbnailData even if it falls out of
+ * scope. Putting it into a method fixes this issue.
+ */
+ private void processLoadQueueItem() {
+ // Load the next item from the queue
+ final Task t = mLoadQueue.nextTask();
+ if (t != null) {
+ Drawable cachedIcon = mIconCache.get(t.key);
+
+ // Load the icon if it is stale or we haven't cached one yet
+ if (cachedIcon == null) {
+ cachedIcon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(
+ mContext, t.taskDescription, t.key.userId, mContext.getResources());
+
+ if (cachedIcon == null) {
+ ActivityInfo info = PackageManagerWrapper.getInstance().getActivityInfo(
+ t.key.getComponent(), t.key.userId);
+ if (info != null) {
+ if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
+ cachedIcon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(
+ info, t.key.userId);
+ }
+ }
+
+ if (cachedIcon == null) {
+ cachedIcon = mDefaultIcon;
+ }
+
+ // At this point, even if we can't load the icon, we will set the
+ // default icon.
+ mIconCache.put(t.key, cachedIcon);
+ }
+
+ if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
+ final ThumbnailData thumbnailData =
+ ActivityManagerWrapper.getInstance().getTaskThumbnail(t.key.id,
+ true /* reducedResolution */);
+
+ if (!mCancelled) {
+ // Notify that the task data has changed
+ final Drawable finalIcon = cachedIcon;
+ mMainThreadHandler.post(
+ () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon));
+ }
+ }
+ }
+
+ interface OnIdleChangedListener {
+ void onIdleChanged(boolean idle);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
new file mode 100644
index 000000000000..898d64a1ea1a
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/FilteredTaskList.java
@@ -0,0 +1,124 @@
+/*
+ * 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.shared.recents.model;
+
+import android.util.ArrayMap;
+import android.util.SparseArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A list of filtered tasks.
+ */
+class FilteredTaskList {
+
+ private final ArrayList<Task> mTasks = new ArrayList<>();
+ private final ArrayList<Task> mFilteredTasks = new ArrayList<>();
+ private final ArrayMap<TaskKey, Integer> mFilteredTaskIndices = new ArrayMap<>();
+ private TaskFilter mFilter;
+
+ /** Sets the task filter, and returns whether the set of filtered tasks have changed. */
+ boolean setFilter(TaskFilter filter) {
+ ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
+ mFilter = filter;
+ updateFilteredTasks();
+ return !prevFilteredTasks.equals(mFilteredTasks);
+ }
+
+ /** Adds a new task to the task list */
+ void add(Task t) {
+ mTasks.add(t);
+ updateFilteredTasks();
+ }
+
+ /** Sets the list of tasks */
+ void set(List<Task> tasks) {
+ mTasks.clear();
+ mTasks.addAll(tasks);
+ updateFilteredTasks();
+ }
+
+ /** Removes a task from the base list only if it is in the filtered list */
+ boolean remove(Task t) {
+ if (mFilteredTasks.contains(t)) {
+ boolean removed = mTasks.remove(t);
+ updateFilteredTasks();
+ return removed;
+ }
+ return false;
+ }
+
+ /** Returns the index of this task in the list of filtered tasks */
+ int indexOf(Task t) {
+ if (t != null && mFilteredTaskIndices.containsKey(t.key)) {
+ return mFilteredTaskIndices.get(t.key);
+ }
+ return -1;
+ }
+
+ /** Returns the size of the list of filtered tasks */
+ int size() {
+ return mFilteredTasks.size();
+ }
+
+ /** Returns whether the filtered list contains this task */
+ boolean contains(Task t) {
+ return mFilteredTaskIndices.containsKey(t.key);
+ }
+
+ /** Updates the list of filtered tasks whenever the base task list changes */
+ private void updateFilteredTasks() {
+ mFilteredTasks.clear();
+ if (mFilter != null) {
+ // Create a sparse array from task id to Task
+ SparseArray<Task> taskIdMap = new SparseArray<>();
+ int taskCount = mTasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task t = mTasks.get(i);
+ taskIdMap.put(t.key.id, t);
+ }
+
+ for (int i = 0; i < taskCount; i++) {
+ Task t = mTasks.get(i);
+ if (mFilter.acceptTask(taskIdMap, t, i)) {
+ mFilteredTasks.add(t);
+ }
+ }
+ } else {
+ mFilteredTasks.addAll(mTasks);
+ }
+ updateFilteredTaskIndices();
+ }
+
+ /** Updates the mapping of tasks to indices. */
+ private void updateFilteredTaskIndices() {
+ int taskCount = mFilteredTasks.size();
+ mFilteredTaskIndices.clear();
+ for (int i = 0; i < taskCount; i++) {
+ Task t = mFilteredTasks.get(i);
+ mFilteredTaskIndices.put(t.key, i);
+ }
+ }
+
+ /** Returns the list of filtered tasks */
+ ArrayList<Task> getTasks() {
+ return mFilteredTasks;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
index 6414ea1e9783..24ba99840165 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/HighResThumbnailLoader.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import static android.os.Process.setThreadPriority;
@@ -25,10 +25,8 @@ import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task.TaskCallbacks;
+import com.android.systemui.shared.recents.model.Task.TaskCallbacks;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -38,6 +36,8 @@ import java.util.ArrayList;
*/
public class HighResThumbnailLoader implements TaskCallbacks {
+ private final ActivityManagerWrapper mActivityManager;
+
@GuardedBy("mLoadQueue")
private final ArrayDeque<Task> mLoadQueue = new ArrayDeque<>();
@GuardedBy("mLoadQueue")
@@ -46,20 +46,21 @@ public class HighResThumbnailLoader implements TaskCallbacks {
private boolean mLoaderIdling;
private final ArrayList<Task> mVisibleTasks = new ArrayList<>();
+
private final Thread mLoadThread;
private final Handler mMainThreadHandler;
- private final SystemServicesProxy mSystemServicesProxy;
private final boolean mIsLowRamDevice;
private boolean mLoading;
private boolean mVisible;
private boolean mFlingingFast;
private boolean mTaskLoadQueueIdle;
- public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper, boolean isLowRamDevice) {
+ public HighResThumbnailLoader(ActivityManagerWrapper activityManager, Looper looper,
+ boolean isLowRamDevice) {
+ mActivityManager = activityManager;
mMainThreadHandler = new Handler(looper);
mLoadThread = new Thread(mLoader, "Recents-HighResThumbnailLoader");
mLoadThread.start();
- mSystemServicesProxy = ssp;
mIsLowRamDevice = isLowRamDevice;
}
@@ -220,7 +221,7 @@ public class HighResThumbnailLoader implements TaskCallbacks {
}
private void loadTask(Task t) {
- ThumbnailData thumbnail = mSystemServicesProxy.getTaskThumbnail(t.key.id,
+ ThumbnailData thumbnail = mActivityManager.getTaskThumbnail(t.key.id,
false /* reducedResolution */);
mMainThreadHandler.post(() -> {
synchronized (mLoadQueue) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index 62ba30bfd5dd..c9368f3ea34c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -14,33 +14,21 @@
* limitations under the License.
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
-import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
-import android.util.ArraySet;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
-import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.ArrayList;
import java.util.Collections;
@@ -68,14 +56,17 @@ public class RecentsTaskLoadPlan {
public int numVisibleTaskThumbnails = 0;
}
- Context mContext;
+ private final Context mContext;
+ private final KeyguardManager mKeyguardManager;
- List<ActivityManager.RecentTaskInfo> mRawTasks;
- TaskStack mStack;
+ private List<ActivityManager.RecentTaskInfo> mRawTasks;
+ private TaskStack mStack;
- /** Package level ctor */
- RecentsTaskLoadPlan(Context context) {
+ private final SparseBooleanArray mTmpLockedUsers = new SparseBooleanArray();
+
+ public RecentsTaskLoadPlan(Context context) {
mContext = context;
+ mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
}
/**
@@ -85,9 +76,9 @@ public class RecentsTaskLoadPlan {
* Note: Do not lock, callers should synchronize on the loader before making this call.
*/
void preloadRawTasks() {
- SystemServicesProxy ssp = Recents.getSystemServices();
- int currentUserId = ssp.getCurrentUser();
- mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), currentUserId);
+ int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId();
+ mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
+ ActivityManager.getMaxRecentTasksStatic(), currentUserId);
// Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(mRawTasks);
@@ -111,18 +102,13 @@ public class RecentsTaskLoadPlan {
preloadRawTasks();
}
- SparseBooleanArray lockedUsers = new SparseBooleanArray();
- String dismissDescFormat = mContext.getString(
- R.string.accessibility_recents_item_will_be_dismissed);
- String appInfoDescFormat = mContext.getString(
- R.string.accessibility_recents_item_open_app_info);
int taskCount = mRawTasks.size();
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
// Compose the task key
final int windowingMode = t.configuration.windowConfiguration.getWindowingMode();
- Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, windowingMode, t.baseIntent,
+ TaskKey taskKey = new TaskKey(t.persistentId, windowingMode, t.baseIntent,
t.userId, t.lastActiveTime);
boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM;
@@ -133,9 +119,7 @@ public class RecentsTaskLoadPlan {
ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
String titleDescription = loader.getAndUpdateContentDescription(taskKey,
- t.taskDescription, res);
- String dismissDescription = String.format(dismissDescFormat, titleDescription);
- String appInfoDescription = String.format(appInfoDescFormat, titleDescription);
+ t.taskDescription);
Drawable icon = isStackTask
? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
@@ -145,17 +129,18 @@ public class RecentsTaskLoadPlan {
int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
boolean isSystemApp = (info != null) &&
((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
- if (lockedUsers.indexOfKey(t.userId) < 0) {
- lockedUsers.put(t.userId, Recents.getSystemServices().isDeviceLocked(t.userId));
+
+ // TODO: Refactor to not do this every preload
+ if (mTmpLockedUsers.indexOfKey(t.userId) < 0) {
+ mTmpLockedUsers.put(t.userId, mKeyguardManager.isDeviceLocked(t.userId));
}
- boolean isLocked = lockedUsers.get(t.userId);
+ boolean isLocked = mTmpLockedUsers.get(t.userId);
// Add the task to the stack
Task task = new Task(taskKey, icon,
- thumbnail, title, titleDescription, dismissDescription, appInfoDescription,
- activityColor, backgroundColor, isLaunchTarget, isStackTask, isSystemApp,
- t.supportsSplitScreenMultiWindow, t.taskDescription, t.resizeMode,
- t.topActivity, isLocked);
+ thumbnail, title, titleDescription, activityColor, backgroundColor,
+ isLaunchTarget, isStackTask, isSystemApp, t.supportsSplitScreenMultiWindow,
+ t.taskDescription, t.resizeMode, t.topActivity, isLocked);
allTasks.add(task);
}
@@ -179,7 +164,7 @@ public class RecentsTaskLoadPlan {
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
- Task.TaskKey taskKey = task.key;
+ TaskKey taskKey = task.key;
boolean isRunningTask = (task.key.id == opts.runningTaskId);
boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
@@ -210,13 +195,6 @@ public class RecentsTaskLoadPlan {
return mStack;
}
- /**
- * Returns the raw list of recent tasks.
- */
- public List<ActivityManager.RecentTaskInfo> getRawTasks() {
- return mRawTasks;
- }
-
/** Returns whether there are any tasks in any stacks. */
public boolean hasTasks() {
if (mStack != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index 3494a00b2e95..de4c72c2ee6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
@@ -25,234 +25,43 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.Looper;
import android.os.Trace;
import android.util.Log;
import android.util.LruCache;
import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan.Options;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.TaskKeyLruCache.EvictionCallback;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
import java.io.PrintWriter;
import java.util.Map;
-import java.util.concurrent.ConcurrentLinkedQueue;
/**
- * A Task load queue
- */
-class TaskResourceLoadQueue {
-
- ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
-
- /** Adds a new task to the load queue */
- void addTask(Task t) {
- if (!mQueue.contains(t)) {
- mQueue.add(t);
- }
- synchronized(this) {
- notifyAll();
- }
- }
-
- /**
- * Retrieves the next task from the load queue, as well as whether we want that task to be
- * force reloaded.
- */
- Task nextTask() {
- return mQueue.poll();
- }
-
- /** Removes a task from the load queue */
- void removeTask(Task t) {
- mQueue.remove(t);
- }
-
- /** Clears all the tasks from the load queue */
- void clearTasks() {
- mQueue.clear();
- }
-
- /** Returns whether the load queue is empty */
- boolean isEmpty() {
- return mQueue.isEmpty();
- }
-}
-
-/**
- * Task resource loader
- */
-class BackgroundTaskLoader implements Runnable {
- static String TAG = "TaskResourceLoader";
- static boolean DEBUG = false;
-
- Context mContext;
- HandlerThread mLoadThread;
- Handler mLoadThreadHandler;
- Handler mMainThreadHandler;
-
- TaskResourceLoadQueue mLoadQueue;
- TaskKeyLruCache<Drawable> mIconCache;
- BitmapDrawable mDefaultIcon;
-
- boolean mStarted;
- boolean mCancelled;
- boolean mWaitingOnLoadQueue;
-
- private final OnIdleChangedListener mOnIdleChangedListener;
-
- /** Constructor, creates a new loading thread that loads task resources in the background */
- public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
- TaskKeyLruCache<Drawable> iconCache, BitmapDrawable defaultIcon,
- OnIdleChangedListener onIdleChangedListener) {
- mLoadQueue = loadQueue;
- mIconCache = iconCache;
- mDefaultIcon = defaultIcon;
- mMainThreadHandler = new Handler();
- mOnIdleChangedListener = onIdleChangedListener;
- mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
- android.os.Process.THREAD_PRIORITY_BACKGROUND);
- mLoadThread.start();
- mLoadThreadHandler = new Handler(mLoadThread.getLooper());
- }
-
- /** Restarts the loader thread */
- void start(Context context) {
- mContext = context;
- mCancelled = false;
- if (!mStarted) {
- // Start loading on the load thread
- mStarted = true;
- mLoadThreadHandler.post(this);
- } else {
- // Notify the load thread to start loading again
- synchronized (mLoadThread) {
- mLoadThread.notifyAll();
- }
- }
- }
-
- /** Requests the loader thread to stop after the current iteration */
- void stop() {
- // Mark as cancelled for the thread to pick up
- mCancelled = true;
- // If we are waiting for the load queue for more tasks, then we can just reset the
- // Context now, since nothing is using it
- if (mWaitingOnLoadQueue) {
- mContext = null;
- }
- }
-
- @Override
- public void run() {
- while (true) {
- if (mCancelled) {
- // We have to unset the context here, since the background thread may be using it
- // when we call stop()
- mContext = null;
- // If we are cancelled, then wait until we are started again
- synchronized(mLoadThread) {
- try {
- mLoadThread.wait();
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- } else {
- SystemServicesProxy ssp = Recents.getSystemServices();
- // If we've stopped the loader, then fall through to the above logic to wait on
- // the load thread
- if (ssp != null) {
- processLoadQueueItem(ssp);
- }
-
- // If there are no other items in the list, then just wait until something is added
- if (!mCancelled && mLoadQueue.isEmpty()) {
- synchronized(mLoadQueue) {
- try {
- mWaitingOnLoadQueue = true;
- mMainThreadHandler.post(
- () -> mOnIdleChangedListener.onIdleChanged(true));
- mLoadQueue.wait();
- mMainThreadHandler.post(
- () -> mOnIdleChangedListener.onIdleChanged(false));
- mWaitingOnLoadQueue = false;
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- }
- }
- }
- }
-
- /**
- * This needs to be in a separate method to work around an surprising interpreter behavior:
- * The register will keep the local reference to cachedThumbnailData even if it falls out of
- * scope. Putting it into a method fixes this issue.
- */
- private void processLoadQueueItem(SystemServicesProxy ssp) {
- // Load the next item from the queue
- final Task t = mLoadQueue.nextTask();
- if (t != null) {
- Drawable cachedIcon = mIconCache.get(t.key);
-
- // Load the icon if it is stale or we haven't cached one yet
- if (cachedIcon == null) {
- cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
- t.key.userId, mContext.getResources());
-
- if (cachedIcon == null) {
- ActivityInfo info = ssp.getActivityInfo(
- t.key.getComponent(), t.key.userId);
- if (info != null) {
- if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
- cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
- }
- }
-
- if (cachedIcon == null) {
- cachedIcon = mDefaultIcon;
- }
-
- // At this point, even if we can't load the icon, we will set the
- // default icon.
- mIconCache.put(t.key, cachedIcon);
- }
-
- if (DEBUG) Log.d(TAG, "Loading thumbnail: " + t.key);
- final ThumbnailData thumbnailData = ssp.getTaskThumbnail(t.key.id,
- true /* reducedResolution */);
-
- if (!mCancelled) {
- // Notify that the task data has changed
- final Drawable finalIcon = cachedIcon;
- mMainThreadHandler.post(
- () -> t.notifyTaskDataLoaded(thumbnailData, finalIcon));
- }
- }
- }
-
- interface OnIdleChangedListener {
- void onIdleChanged(boolean idle);
- }
-}
-
-/**
* Recents task loader
*/
public class RecentsTaskLoader {
-
private static final String TAG = "RecentsTaskLoader";
private static final boolean DEBUG = false;
+ /** Levels of svelte in increasing severity/austerity. */
+ // No svelting.
+ public static final int SVELTE_NONE = 0;
+ // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable
+ // caching thumbnails as you scroll.
+ public static final int SVELTE_LIMIT_CACHE = 1;
+ // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and
+ // evict all thumbnails when hidden.
+ public static final int SVELTE_DISABLE_CACHE = 2;
+ // Disable all thumbnail loading.
+ public static final int SVELTE_DISABLE_LOADING = 3;
+
+ private final Context mContext;
+
// This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos
// for many tasks, which we use to get the activity labels and icons. Unlike the other caches
// below, this is per-package so we can't invalidate the items in the cache based on the last
@@ -272,29 +81,27 @@ public class RecentsTaskLoader {
private final int mMaxThumbnailCacheSize;
private final int mMaxIconCacheSize;
private int mNumVisibleTasksLoaded;
+ private int mSvelteLevel;
- int mDefaultTaskBarBackgroundColor;
- int mDefaultTaskViewBackgroundColor;
- BitmapDrawable mDefaultIcon;
+ private int mDefaultTaskBarBackgroundColor;
+ private int mDefaultTaskViewBackgroundColor;
+ private final BitmapDrawable mDefaultIcon;
- private TaskKeyLruCache.EvictionCallback mClearActivityInfoOnEviction =
- new TaskKeyLruCache.EvictionCallback() {
+ private EvictionCallback mClearActivityInfoOnEviction = new EvictionCallback() {
@Override
- public void onEntryEvicted(Task.TaskKey key) {
+ public void onEntryEvicted(TaskKey key) {
if (key != null) {
mActivityInfoCache.remove(key.getComponent());
}
}
};
- public RecentsTaskLoader(Context context) {
- Resources res = context.getResources();
- mDefaultTaskBarBackgroundColor =
- context.getColor(R.color.recents_task_bar_default_background_color);
- mDefaultTaskViewBackgroundColor =
- context.getColor(R.color.recents_task_view_default_background_color);
- mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
- mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
+ public RecentsTaskLoader(Context context, int maxThumbnailCacheSize, int maxIconCacheSize,
+ int svelteLevel) {
+ mContext = context;
+ mMaxThumbnailCacheSize = maxThumbnailCacheSize;
+ mMaxIconCacheSize = maxIconCacheSize;
+ mSvelteLevel = svelteLevel;
// Create the default assets
Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
@@ -303,18 +110,27 @@ public class RecentsTaskLoader {
// Initialize the proxy, cache and loaders
int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
- mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
- Looper.getMainLooper(), Recents.getConfiguration().isLowRamDevice);
+ mHighResThumbnailLoader = new HighResThumbnailLoader(ActivityManagerWrapper.getInstance(),
+ Looper.getMainLooper(), ActivityManager.isLowRamDeviceStatic());
mLoadQueue = new TaskResourceLoadQueue();
mIconCache = new TaskKeyLruCache<>(mMaxIconCacheSize, mClearActivityInfoOnEviction);
mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
mClearActivityInfoOnEviction);
- mActivityInfoCache = new LruCache(numRecentTasks);
+ mActivityInfoCache = new LruCache<>(numRecentTasks);
mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultIcon,
mHighResThumbnailLoader::setTaskLoadQueueIdle);
}
+ /**
+ * Sets the default task bar/view colors if none are provided by the app.
+ */
+ public void setDefaultColors(int defaultTaskBarBackgroundColor,
+ int defaultTaskViewBackgroundColor) {
+ mDefaultTaskBarBackgroundColor = defaultTaskBarBackgroundColor;
+ mDefaultTaskViewBackgroundColor = defaultTaskViewBackgroundColor;
+ }
+
/** Returns the size of the app icon cache. */
public int getIconCacheSize() {
return mMaxIconCacheSize;
@@ -329,12 +145,6 @@ public class RecentsTaskLoader {
return mHighResThumbnailLoader;
}
- /** Creates a new plan for loading the recent tasks. */
- public RecentsTaskLoadPlan createLoadPlan(Context context) {
- RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context);
- return plan;
- }
-
/** Preloads recents tasks using the specified plan to store the output. */
public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {
try {
@@ -346,13 +156,11 @@ public class RecentsTaskLoader {
}
/** Begins loading the heavy task data according to the specified options. */
- public synchronized void loadTasks(Context context, RecentsTaskLoadPlan plan,
- RecentsTaskLoadPlan.Options opts) {
+ public synchronized void loadTasks(RecentsTaskLoadPlan plan, Options opts) {
if (opts == null) {
throw new RuntimeException("Requires load options");
}
if (opts.onlyLoadForCache && opts.loadThumbnails) {
-
// If we are loading for the cache, we'd like to have the real cache only include the
// visible thumbnails. However, we also don't want to reload already cached thumbnails.
// Thus, we copy over the current entries into a second cache, and clear the real cache,
@@ -453,9 +261,7 @@ public class RecentsTaskLoader {
/**
* Returns the cached task label if the task key is not expired, updating the cache if it is.
*/
- String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
- SystemServicesProxy ssp = Recents.getSystemServices();
-
+ String getAndUpdateActivityTitle(TaskKey taskKey, ActivityManager.TaskDescription td) {
// Return the task description label if it exists
if (td != null && td.getLabel() != null) {
return td.getLabel();
@@ -468,7 +274,8 @@ public class RecentsTaskLoader {
// All short paths failed, load the label from the activity info and cache it
ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
- label = ssp.getBadgedActivityLabel(activityInfo, taskKey.userId);
+ label = ActivityManagerWrapper.getInstance().getBadgedActivityLabel(activityInfo,
+ taskKey.userId);
mActivityLabelCache.put(taskKey, label);
return label;
}
@@ -481,10 +288,7 @@ public class RecentsTaskLoader {
* Returns the cached task content description if the task key is not expired, updating the
* cache if it is.
*/
- String getAndUpdateContentDescription(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
- Resources res) {
- SystemServicesProxy ssp = Recents.getSystemServices();
-
+ String getAndUpdateContentDescription(TaskKey taskKey, ActivityManager.TaskDescription td) {
// Return the cached content description if it exists
String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
if (label != null) {
@@ -494,7 +298,8 @@ public class RecentsTaskLoader {
// All short paths failed, load the label from the activity info and cache it
ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
- label = ssp.getBadgedContentDescription(activityInfo, taskKey.userId, td, res);
+ label = ActivityManagerWrapper.getInstance().getBadgedContentDescription(
+ activityInfo, taskKey.userId, td);
if (td == null) {
// Only add to the cache if the task description is null, otherwise, it is possible
// for the task description to change between calls without the last active time
@@ -513,10 +318,8 @@ public class RecentsTaskLoader {
/**
* Returns the cached task icon if the task key is not expired, updating the cache if it is.
*/
- Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
+ Drawable getAndUpdateActivityIcon(TaskKey taskKey, ActivityManager.TaskDescription td,
Resources res, boolean loadIfNotCached) {
- SystemServicesProxy ssp = Recents.getSystemServices();
-
// Return the cached activity icon if it exists
Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
if (icon != null) {
@@ -525,7 +328,8 @@ public class RecentsTaskLoader {
if (loadIfNotCached) {
// Return and cache the task description icon if it exists
- icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res);
+ icon = ActivityManagerWrapper.getInstance().getBadgedTaskDescriptionIcon(mContext, td,
+ taskKey.userId, res);
if (icon != null) {
mIconCache.put(taskKey, icon);
return icon;
@@ -534,7 +338,8 @@ public class RecentsTaskLoader {
// Load the icon from the activity info and cache it
ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
- icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId);
+ icon = ActivityManagerWrapper.getInstance().getBadgedActivityIcon(activityInfo,
+ taskKey.userId);
if (icon != null) {
mIconCache.put(taskKey, icon);
return icon;
@@ -548,10 +353,8 @@ public class RecentsTaskLoader {
/**
* Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
*/
- synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
+ synchronized ThumbnailData getAndUpdateThumbnail(TaskKey taskKey, boolean loadIfNotCached,
boolean storeInCache) {
- SystemServicesProxy ssp = Recents.getSystemServices();
-
ThumbnailData cached = mThumbnailCache.getAndInvalidateIfModified(taskKey);
if (cached != null) {
return cached;
@@ -564,11 +367,10 @@ public class RecentsTaskLoader {
}
if (loadIfNotCached) {
- RecentsConfiguration config = Recents.getConfiguration();
- if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
+ if (mSvelteLevel < SVELTE_DISABLE_LOADING) {
// Load the thumbnail from the system
- ThumbnailData thumbnailData = ssp.getTaskThumbnail(taskKey.id,
- true /* reducedResolution */);
+ ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail(
+ taskKey.id, true /* reducedResolution */);
if (thumbnailData.thumbnail != null) {
if (storeInCache) {
mThumbnailCache.put(taskKey, thumbnailData);
@@ -607,12 +409,11 @@ public class RecentsTaskLoader {
* Returns the activity info for the given task key, retrieving one from the system if the
* task key is expired.
*/
- ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
- SystemServicesProxy ssp = Recents.getSystemServices();
+ ActivityInfo getAndUpdateActivityInfo(TaskKey taskKey) {
ComponentName cn = taskKey.getComponent();
ActivityInfo activityInfo = mActivityInfoCache.get(cn);
if (activityInfo == null) {
- activityInfo = ssp.getActivityInfo(cn, taskKey.userId);
+ activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId);
if (cn == null || activityInfo == null) {
Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " +
activityInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index ae417c0c403f..6bddbe01b11b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -14,23 +14,17 @@
* limitations under the License.
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
-import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.ViewDebug;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.Utilities;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -46,11 +40,11 @@ public class Task {
/* Task callbacks */
public interface TaskCallbacks {
/* Notifies when a task has been bound */
- public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
+ void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
/* Notifies when a task has been unbound */
- public void onTaskDataUnloaded();
+ void onTaskDataUnloaded();
/* Notifies when a task's windowing mode has changed. */
- public void onTaskWindowingModeChanged();
+ void onTaskWindowingModeChanged();
}
/* The Task Key represents the unique primary key for the task */
@@ -64,8 +58,6 @@ public class Task {
@ViewDebug.ExportedProperty(category="recents")
public final int userId;
@ViewDebug.ExportedProperty(category="recents")
- public long firstActiveTime;
- @ViewDebug.ExportedProperty(category="recents")
public long lastActiveTime;
private int mHashCode;
@@ -134,10 +126,6 @@ public class Task {
@ViewDebug.ExportedProperty(category="recents")
public String titleDescription;
@ViewDebug.ExportedProperty(category="recents")
- public String dismissDescription;
- @ViewDebug.ExportedProperty(category="recents")
- public String appInfoDescription;
- @ViewDebug.ExportedProperty(category="recents")
public int colorPrimary;
@ViewDebug.ExportedProperty(category="recents")
public int colorBackground;
@@ -180,17 +168,15 @@ public class Task {
}
public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title,
- String titleDescription, String dismissDescription, String appInfoDescription,
- int colorPrimary, int colorBackground, boolean isLaunchTarget, boolean isStackTask,
- boolean isSystemApp, boolean isDockable, TaskDescription taskDescription,
- int resizeMode, ComponentName topActivity, boolean isLocked) {
+ String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget,
+ boolean isStackTask, boolean isSystemApp, boolean isDockable,
+ TaskDescription taskDescription, int resizeMode, ComponentName topActivity,
+ boolean isLocked) {
this.key = key;
this.icon = icon;
this.thumbnail = thumbnail;
this.title = title;
this.titleDescription = titleDescription;
- this.dismissDescription = dismissDescription;
- this.appInfoDescription = appInfoDescription;
this.colorPrimary = colorPrimary;
this.colorBackground = colorBackground;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -214,8 +200,6 @@ public class Task {
this.thumbnail = o.thumbnail;
this.title = o.title;
this.titleDescription = o.titleDescription;
- this.dismissDescription = o.dismissDescription;
- this.appInfoDescription = o.appInfoDescription;
this.colorPrimary = o.colorPrimary;
this.colorBackground = o.colorBackground;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
new file mode 100644
index 000000000000..9a1ff544800d
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -0,0 +1,27 @@
+/*
+ * 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.shared.recents.model;
+
+import android.util.SparseArray;
+
+/**
+ * An interface for a task filter to query whether a particular task should show in a stack.
+ */
+interface TaskFilter {
+ /** Returns whether the filter accepts the specified task */
+ boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
index 247a654207c8..4bf3500a3405 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java
@@ -14,12 +14,12 @@
* limitations under the License
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import android.util.Log;
import android.util.SparseArray;
-import com.android.systemui.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
/**
* Base class for both strong and LRU task key cache.
@@ -34,7 +34,7 @@ public abstract class TaskKeyCache<V> {
* Gets a specific entry in the cache with the specified key, regardless of whether the cached
* value is valid or not.
*/
- final V get(Task.TaskKey key) {
+ final V get(TaskKey key) {
return getCacheEntry(key.id);
}
@@ -42,8 +42,8 @@ public abstract class TaskKeyCache<V> {
* Returns the value only if the key is valid (has not been updated since the last time it was
* in the cache)
*/
- final V getAndInvalidateIfModified(Task.TaskKey key) {
- Task.TaskKey lastKey = mKeys.get(key.id);
+ final V getAndInvalidateIfModified(TaskKey key) {
+ TaskKey lastKey = mKeys.get(key.id);
if (lastKey != null) {
if ((lastKey.windowingMode != key.windowingMode) ||
(lastKey.lastActiveTime != key.lastActiveTime)) {
@@ -59,7 +59,7 @@ public abstract class TaskKeyCache<V> {
}
/** Puts an entry in the cache for a specific key. */
- final void put(Task.TaskKey key, V value) {
+ final void put(TaskKey key, V value) {
if (key == null || value == null) {
Log.e(TAG, "Unexpected null key or value: " + key + ", " + value);
return;
@@ -70,7 +70,7 @@ public abstract class TaskKeyCache<V> {
/** Removes a cache entry for a specific key. */
- final void remove(Task.TaskKey key) {
+ final void remove(TaskKey key) {
// Remove the key after the cache value because we need it to make the callback
removeCacheEntry(key.id);
mKeys.remove(key.id);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
index 778df6be399b..0ba2c3bf6e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import android.util.LruCache;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+
import java.io.PrintWriter;
/**
- * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
+ * A mapping of {@link TaskKey} to value, with additional LRU functionality where the least
* recently referenced key/values will be evicted as more values than the given cache size are
* inserted.
*
@@ -31,7 +33,7 @@ import java.io.PrintWriter;
public class TaskKeyLruCache<V> extends TaskKeyCache<V> {
public interface EvictionCallback {
- public void onEntryEvicted(Task.TaskKey key);
+ void onEntryEvicted(TaskKey key);
}
private final LruCache<Integer, V> mCache;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
index c84df8a14288..4408eced3e93 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyStrongCache.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyStrongCache.java
@@ -14,13 +14,11 @@
* limitations under the License
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-import com.android.systemui.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
new file mode 100644
index 000000000000..fbb6acebc8e0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskResourceLoadQueue.java
@@ -0,0 +1,60 @@
+/*
+ * 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.shared.recents.model;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * A Task load queue
+ */
+class TaskResourceLoadQueue {
+
+ private final ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<>();
+
+ /** Adds a new task to the load queue */
+ void addTask(Task t) {
+ if (!mQueue.contains(t)) {
+ mQueue.add(t);
+ }
+ synchronized(this) {
+ notifyAll();
+ }
+ }
+
+ /**
+ * Retrieves the next task from the load queue, as well as whether we want that task to be
+ * force reloaded.
+ */
+ Task nextTask() {
+ return mQueue.poll();
+ }
+
+ /** Removes a task from the load queue */
+ void removeTask(Task t) {
+ mQueue.remove(t);
+ }
+
+ /** Clears all the tasks from the load queue */
+ void clearTasks() {
+ mQueue.clear();
+ }
+
+ /** Returns whether the load queue is empty */
+ boolean isEmpty() {
+ return mQueue.isEmpty();
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
new file mode 100644
index 000000000000..693379d3ee13
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskStack.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014 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.shared.recents.model;
+
+import android.content.ComponentName;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * The task stack contains a list of multiple tasks.
+ */
+public class TaskStack {
+
+ private static final String TAG = "TaskStack";
+
+ /** Task stack callbacks */
+ public interface TaskStackCallbacks {
+ /**
+ * Notifies when a new task has been added to the stack.
+ */
+ void onStackTaskAdded(TaskStack stack, Task newTask);
+
+ /**
+ * Notifies when a task has been removed from the stack.
+ */
+ void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
+ AnimationProps animation, boolean fromDockGesture,
+ boolean dismissRecentsIfAllRemoved);
+
+ /**
+ * Notifies when all tasks have been removed from the stack.
+ */
+ void onStackTasksRemoved(TaskStack stack);
+
+ /**
+ * Notifies when tasks in the stack have been updated.
+ */
+ void onStackTasksUpdated(TaskStack stack);
+ }
+
+ private final ArrayList<Task> mRawTaskList = new ArrayList<>();
+ private final FilteredTaskList mStackTaskList = new FilteredTaskList();
+ private TaskStackCallbacks mCb;
+
+ public TaskStack() {
+ // Ensure that we only show stack tasks
+ mStackTaskList.setFilter((taskIdMap, t, index) -> t.isStackTask);
+ }
+
+ /** Sets the callbacks for this task stack. */
+ public void setCallbacks(TaskStackCallbacks cb) {
+ mCb = cb;
+ }
+
+ /**
+ * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+ * how they should update themselves.
+ */
+ public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
+ removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */);
+ }
+
+ /**
+ * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
+ * how they should update themselves.
+ */
+ public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture,
+ boolean dismissRecentsIfAllRemoved) {
+ if (mStackTaskList.contains(t)) {
+ mStackTaskList.remove(t);
+ Task newFrontMostTask = getStackFrontMostTask();
+ if (mCb != null) {
+ // Notify that a task has been removed
+ mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
+ fromDockGesture, dismissRecentsIfAllRemoved);
+ }
+ }
+ mRawTaskList.remove(t);
+ }
+
+ /**
+ * Removes all tasks from the stack.
+ */
+ public void removeAllTasks(boolean notifyStackChanges) {
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ Task t = tasks.get(i);
+ mStackTaskList.remove(t);
+ mRawTaskList.remove(t);
+ }
+ if (mCb != null && notifyStackChanges) {
+ // Notify that all tasks have been removed
+ mCb.onStackTasksRemoved(this);
+ }
+ }
+
+
+ /**
+ * @see #setTasks(List, boolean)
+ */
+ public void setTasks(TaskStack stack, boolean notifyStackChanges) {
+ setTasks(stack.mRawTaskList, notifyStackChanges);
+ }
+
+ /**
+ * Sets a few tasks in one go, without calling any callbacks.
+ *
+ * @param tasks the new set of tasks to replace the current set.
+ * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
+ */
+ public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+ // Compute a has set for each of the tasks
+ ArrayMap<TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
+ ArrayMap<TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
+ ArrayList<Task> addedTasks = new ArrayList<>();
+ ArrayList<Task> removedTasks = new ArrayList<>();
+ ArrayList<Task> allTasks = new ArrayList<>();
+
+ // Disable notifications if there are no callbacks
+ if (mCb == null) {
+ notifyStackChanges = false;
+ }
+
+ // Remove any tasks that no longer exist
+ int taskCount = mRawTaskList.size();
+ for (int i = taskCount - 1; i >= 0; i--) {
+ Task task = mRawTaskList.get(i);
+ if (!newTasksMap.containsKey(task.key)) {
+ if (notifyStackChanges) {
+ removedTasks.add(task);
+ }
+ }
+ }
+
+ // Add any new tasks
+ taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task newTask = tasks.get(i);
+ Task currentTask = currentTasksMap.get(newTask.key);
+ if (currentTask == null && notifyStackChanges) {
+ addedTasks.add(newTask);
+ } else if (currentTask != null) {
+ // The current task has bound callbacks, so just copy the data from the new task
+ // state and add it back into the list
+ currentTask.copyFrom(newTask);
+ newTask = currentTask;
+ }
+ allTasks.add(newTask);
+ }
+
+ // Sort all the tasks to ensure they are ordered correctly
+ for (int i = allTasks.size() - 1; i >= 0; i--) {
+ allTasks.get(i).temporarySortIndexInStack = i;
+ }
+
+ mStackTaskList.set(allTasks);
+ mRawTaskList.clear();
+ mRawTaskList.addAll(allTasks);
+
+ // Only callback for the removed tasks after the stack has updated
+ int removedTaskCount = removedTasks.size();
+ Task newFrontMostTask = getStackFrontMostTask();
+ for (int i = 0; i < removedTaskCount; i++) {
+ mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
+ AnimationProps.IMMEDIATE, false /* fromDockGesture */,
+ true /* dismissRecentsIfAllRemoved */);
+ }
+
+ // Only callback for the newly added tasks after this stack has been updated
+ int addedTaskCount = addedTasks.size();
+ for (int i = 0; i < addedTaskCount; i++) {
+ mCb.onStackTaskAdded(this, addedTasks.get(i));
+ }
+
+ // Notify that the task stack has been updated
+ if (notifyStackChanges) {
+ mCb.onStackTasksUpdated(this);
+ }
+ }
+
+ /**
+ * Gets the front-most task in the stack.
+ */
+ public Task getStackFrontMostTask() {
+ ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+ if (stackTasks.isEmpty()) {
+ return null;
+ }
+ return stackTasks.get(stackTasks.size() - 1);
+ }
+
+ /** Gets the task keys */
+ public ArrayList<TaskKey> getTaskKeys() {
+ ArrayList<TaskKey> taskKeys = new ArrayList<>();
+ ArrayList<Task> tasks = computeAllTasksList();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ taskKeys.add(task.key);
+ }
+ return taskKeys;
+ }
+
+ /**
+ * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
+ */
+ public ArrayList<Task> getStackTasks() {
+ return mStackTaskList.getTasks();
+ }
+
+ /**
+ * Computes a set of all the active and historical tasks.
+ */
+ public ArrayList<Task> computeAllTasksList() {
+ ArrayList<Task> tasks = new ArrayList<>();
+ tasks.addAll(mStackTaskList.getTasks());
+ return tasks;
+ }
+
+ /**
+ * Returns the number of stacktasks.
+ */
+ public int getTaskCount() {
+ return mStackTaskList.size();
+ }
+
+ /**
+ * Returns the number of stack tasks.
+ */
+ public int getStackTaskCount() {
+ return mStackTaskList.size();
+ }
+
+ /**
+ * Returns the task in stack tasks which is the launch target.
+ */
+ public Task getLaunchTarget() {
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ if (task.isLaunchTarget) {
+ return task;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns whether the next launch target should actually be the PiP task.
+ */
+ public boolean isNextLaunchTargetPip(long lastPipTime) {
+ Task launchTarget = getLaunchTarget();
+ Task nextLaunchTarget = getNextLaunchTargetRaw();
+ if (nextLaunchTarget != null && lastPipTime > 0) {
+ // If the PiP time is more recent than the next launch target, then launch the PiP task
+ return lastPipTime > nextLaunchTarget.key.lastActiveTime;
+ } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) {
+ // Otherwise, if there is no next launch target, but there is a PiP, then launch
+ // the PiP task
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the task in stack tasks which should be launched next if Recents are toggled
+ * again, or null if there is no task to be launched. Callers should check
+ * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the
+ * stack.
+ */
+ public Task getNextLaunchTarget() {
+ Task nextLaunchTarget = getNextLaunchTargetRaw();
+ if (nextLaunchTarget != null) {
+ return nextLaunchTarget;
+ }
+ return getStackTasks().get(getTaskCount() - 1);
+ }
+
+ private Task getNextLaunchTargetRaw() {
+ int taskCount = getTaskCount();
+ if (taskCount == 0) {
+ return null;
+ }
+ int launchTaskIndex = indexOfStackTask(getLaunchTarget());
+ if (launchTaskIndex != -1 && launchTaskIndex > 0) {
+ return getStackTasks().get(launchTaskIndex - 1);
+ }
+ return null;
+ }
+
+ /** Returns the index of this task in this current task stack */
+ public int indexOfStackTask(Task t) {
+ return mStackTaskList.indexOf(t);
+ }
+
+ /** Finds the task with the specified task id. */
+ public Task findTaskWithId(int taskId) {
+ ArrayList<Task> tasks = computeAllTasksList();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ if (task.key.id == taskId) {
+ return task;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Computes the components of tasks in this stack that have been removed as a result of a change
+ * in the specified package.
+ */
+ public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
+ // Identify all the tasks that should be removed as a result of the package being removed.
+ // Using a set to ensure that we callback once per unique component.
+ ArraySet<ComponentName> existingComponents = new ArraySet<>();
+ ArraySet<ComponentName> removedComponents = new ArraySet<>();
+ ArrayList<TaskKey> taskKeys = getTaskKeys();
+ int taskKeyCount = taskKeys.size();
+ for (int i = 0; i < taskKeyCount; i++) {
+ TaskKey t = taskKeys.get(i);
+
+ // Skip if this doesn't apply to the current user
+ if (t.userId != userId) continue;
+
+ ComponentName cn = t.getComponent();
+ if (cn.getPackageName().equals(packageName)) {
+ if (existingComponents.contains(cn)) {
+ // If we know that the component still exists in the package, then skip
+ continue;
+ }
+ if (PackageManagerWrapper.getInstance().getActivityInfo(cn, userId) != null) {
+ existingComponents.add(cn);
+ } else {
+ removedComponents.add(cn);
+ }
+ }
+ }
+ return removedComponents;
+ }
+
+ @Override
+ public String toString() {
+ String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ str += " " + tasks.get(i).toString() + "\n";
+ }
+ return str;
+ }
+
+ /**
+ * Given a list of tasks, returns a map of each task's key to the task.
+ */
+ private ArrayMap<TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
+ ArrayMap<TaskKey, Task> map = new ArrayMap<>(tasks.size());
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ map.put(task.key, task);
+ }
+ return map;
+ }
+
+ public void dump(String prefix, PrintWriter writer) {
+ String innerPrefix = prefix + " ";
+
+ writer.print(prefix); writer.print(TAG);
+ writer.print(" numStackTasks="); writer.print(mStackTaskList.size());
+ writer.println();
+ ArrayList<Task> tasks = mStackTaskList.getTasks();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ tasks.get(i).dump(innerPrefix, writer);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 33ff1b634d64..dd1763bb118b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
+
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
import android.app.ActivityManager.TaskSnapshot;
import android.graphics.Bitmap;
@@ -25,20 +27,25 @@ import android.graphics.Rect;
*/
public class ThumbnailData {
- // TODO: Make these final once the non-snapshot path is removed.
- public Bitmap thumbnail;
+ public final Bitmap thumbnail;
public int orientation;
- public final Rect insets = new Rect();
+ public Rect insets;
public boolean reducedResolution;
public float scale;
- public static ThumbnailData createFromTaskSnapshot(TaskSnapshot snapshot) {
- ThumbnailData out = new ThumbnailData();
- out.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
- out.insets.set(snapshot.getContentInsets());
- out.orientation = snapshot.getOrientation();
- out.reducedResolution = snapshot.isReducedResolution();
- out.scale = snapshot.getScale();
- return out;
+ public ThumbnailData() {
+ thumbnail = null;
+ orientation = ORIENTATION_UNDEFINED;
+ insets = new Rect();
+ reducedResolution = false;
+ scale = 1f;
+ }
+
+ public ThumbnailData(TaskSnapshot snapshot) {
+ thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
+ insets = new Rect(snapshot.getContentInsets());
+ orientation = snapshot.getOrientation();
+ reducedResolution = snapshot.isReducedResolution();
+ scale = snapshot.getScale();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
index 716d1bcf78c2..2de7f74ba477 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/AnimationProps.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recents.views;
+package com.android.systemui.shared.recents.utilities;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -24,8 +24,7 @@ import android.util.SparseArray;
import android.util.SparseLongArray;
import android.view.View;
import android.view.animation.Interpolator;
-
-import com.android.systemui.Interpolators;
+import android.view.animation.LinearInterpolator;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -37,7 +36,8 @@ import java.util.List;
*/
public class AnimationProps {
- public static final AnimationProps IMMEDIATE = new AnimationProps(0, Interpolators.LINEAR);
+ private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
+ public static final AnimationProps IMMEDIATE = new AnimationProps(0, LINEAR_INTERPOLATOR);
@Retention(RetentionPolicy.SOURCE)
@IntDef({ALL, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, ALPHA, SCALE, BOUNDS})
@@ -51,7 +51,6 @@ public class AnimationProps {
public static final int SCALE = 5;
public static final int BOUNDS = 6;
public static final int DIM_ALPHA = 7;
- public static final int FOCUS_STATE = 8;
private SparseLongArray mPropStartDelay;
private SparseLongArray mPropDuration;
@@ -195,9 +194,9 @@ public class AnimationProps {
if (interp != null) {
return interp;
}
- return mPropInterpolators.get(ALL, Interpolators.LINEAR);
+ return mPropInterpolators.get(ALL, LINEAR_INTERPOLATOR);
}
- return Interpolators.LINEAR;
+ return LINEAR_INTERPOLATOR;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
index 72511de9ec80..51c1b5aa13d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/RectFEvaluator.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/RectFEvaluator.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.recents.misc;
+package com.android.systemui.shared.recents.utilities;
import android.animation.TypeEvaluator;
import android.graphics.RectF;
@@ -23,7 +23,7 @@ import android.graphics.RectF;
*/
public class RectFEvaluator implements TypeEvaluator<RectF> {
- private RectF mRect = new RectF();
+ private final RectF mRect = new RectF();
/**
* This function returns the result of linearly interpolating the start and
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 4349e30f60e0..a5d19639580e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recents.misc;
+package com.android.systemui.shared.recents.utilities;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -38,12 +38,8 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewStub;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.views.TaskViewTransform;
-
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
/* Common code */
public class Utilities {
@@ -76,7 +72,6 @@ public class Utilities {
public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
- public static final Rect EMPTY_RECT = new Rect();
/**
* @return the first parent walking up the view hierarchy that has the given class type.
@@ -253,24 +248,6 @@ public class Utilities {
}
/**
- * Updates {@param transforms} to be the same size as {@param tasks}.
- */
- public static void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
- // We can reuse the task transforms where possible to reduce object allocation
- int taskTransformCount = transforms.size();
- int taskCount = tasks.size();
- if (taskTransformCount < taskCount) {
- // If there are less transforms than tasks, then add as many transforms as necessary
- for (int i = taskTransformCount; i < taskCount; i++) {
- transforms.add(new TaskViewTransform());
- }
- } else if (taskTransformCount > taskCount) {
- // If there are more transforms than tasks, then just subset the transform list
- transforms.subList(taskCount, taskTransformCount).clear();
- }
- }
-
- /**
* Used for debugging, converts DP to PX.
*/
public static float dpToPx(Resources res, float dp) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
new file mode 100644
index 000000000000..3f93f76af7e4
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015 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.shared.system;
+
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
+import android.util.Log;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ActivityManagerWrapper {
+
+ private static final String TAG = "ActivityManagerWrapper";
+
+ private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
+
+ private final PackageManager mPackageManager;
+ private final IconDrawableFactory mDrawableFactory;
+
+ private ActivityManagerWrapper() {
+ final Context context = AppGlobals.getInitialApplication();
+ mPackageManager = context.getPackageManager();
+ mDrawableFactory = IconDrawableFactory.newInstance(context);
+ }
+
+ public static ActivityManagerWrapper getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * @return the current user's id.
+ */
+ public int getCurrentUserId() {
+ UserInfo ui;
+ try {
+ ui = ActivityManager.getService().getCurrentUser();
+ return ui != null ? ui.id : 0;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return a list of the recents tasks.
+ */
+ public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+ try {
+ return ActivityManager.getService().getRecentTasks(numTasks,
+ RECENT_IGNORE_UNAVAILABLE, userId).getList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get recent tasks", e);
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * @return the task snapshot for the given {@param taskId}.
+ */
+ public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean reducedResolution) {
+ ActivityManager.TaskSnapshot snapshot = null;
+ try {
+ snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to retrieve task snapshot", e);
+ }
+ if (snapshot != null) {
+ return new ThumbnailData(snapshot);
+ } else {
+ return new ThumbnailData();
+ }
+ }
+
+ /**
+ * @return the task description icon, loading and badging it if it necessary.
+ */
+ public Drawable getBadgedTaskDescriptionIcon(Context context,
+ ActivityManager.TaskDescription taskDescription, int userId, Resources res) {
+ Bitmap tdIcon = taskDescription.getInMemoryIcon();
+ Drawable dIcon = null;
+ if (tdIcon != null) {
+ dIcon = new BitmapDrawable(res, tdIcon);
+ } else if (taskDescription.getIconResource() != 0) {
+ try {
+ dIcon = context.getDrawable(taskDescription.getIconResource());
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Could not find icon drawable from resource", e);
+ }
+ } else {
+ tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+ taskDescription.getIconFilename(), userId);
+ if (tdIcon != null) {
+ dIcon = new BitmapDrawable(res, tdIcon);
+ }
+ }
+ if (dIcon != null) {
+ return getBadgedIcon(dIcon, userId);
+ }
+ return null;
+ }
+
+ /**
+ * @return the given icon for a user, badging if necessary.
+ */
+ private Drawable getBadgedIcon(Drawable icon, int userId) {
+ if (userId != UserHandle.myUserId()) {
+ icon = mPackageManager.getUserBadgedIcon(icon, new UserHandle(userId));
+ }
+ return icon;
+ }
+
+ /**
+ * @return the activity icon for the ActivityInfo for a user, badging if necessary.
+ */
+ public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
+ return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
+ }
+
+ /**
+ * @return the application icon for the ApplicationInfo for a user, badging if necessary.
+ */
+ public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
+ return mDrawableFactory.getBadgedIcon(appInfo, userId);
+ }
+
+ /**
+ * @return the activity label, badging if necessary.
+ */
+ public String getBadgedActivityLabel(ActivityInfo info, int userId) {
+ return getBadgedLabel(info.loadLabel(mPackageManager).toString(), userId);
+ }
+
+ /**
+ * @return the application label, badging if necessary.
+ */
+ public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
+ return getBadgedLabel(appInfo.loadLabel(mPackageManager).toString(), userId);
+ }
+
+ /**
+ * @return the content description for a given task, badging it if necessary. The content
+ * description joins the app and activity labels.
+ */
+ public String getBadgedContentDescription(ActivityInfo info, int userId,
+ ActivityManager.TaskDescription td) {
+ String activityLabel;
+ if (td != null && td.getLabel() != null) {
+ activityLabel = td.getLabel();
+ } else {
+ activityLabel = info.loadLabel(mPackageManager).toString();
+ }
+ String applicationLabel = info.applicationInfo.loadLabel(mPackageManager).toString();
+ String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
+ return applicationLabel.equals(activityLabel)
+ ? badgedApplicationLabel
+ : badgedApplicationLabel + " " + activityLabel;
+ }
+
+ /**
+ * @return the given label for a user, badging if necessary.
+ */
+ private String getBadgedLabel(String label, int userId) {
+ if (userId != UserHandle.myUserId()) {
+ label = mPackageManager.getUserBadgedLabel(label, new UserHandle(userId)).toString();
+ }
+ return label;
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
new file mode 100644
index 000000000000..d5e6e6efb3cf
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PackageManagerWrapper.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 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.shared.system;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.RemoteException;
+
+public class PackageManagerWrapper {
+
+ private static final String TAG = "PackageManagerWrapper";
+
+ private static final PackageManagerWrapper sInstance = new PackageManagerWrapper();
+
+ private static final IPackageManager mIPackageManager = AppGlobals.getPackageManager();
+
+ public static PackageManagerWrapper getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * @return the activity info for a given {@param componentName} and {@param userId}.
+ */
+ public ActivityInfo getActivityInfo(ComponentName componentName, int userId) {
+ try {
+ return mIPackageManager.getActivityInfo(componentName, PackageManager.GET_META_DATA,
+ userId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/packages/SystemUI/shared/tests/Android.mk b/packages/SystemUI/shared/tests/Android.mk
new file mode 100644
index 000000000000..ce3b4424de50
--- /dev/null
+++ b/packages/SystemUI/shared/tests/Android.mk
@@ -0,0 +1,53 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
+LOCAL_PACKAGE_NAME := SystemUISharedLibTests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+# Add local path sources as well as shared lib sources
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-java-files-under, ../src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ metrics-helper-lib \
+ android-support-test \
+ mockito-target-minus-junit4 \
+ SystemUI-proto \
+ SystemUI-tags \
+ legacy-android-test \
+ testables \
+ truth-prebuilt \
+
+LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
+
+# sign this with platform cert, so this test is allowed to inject key events into
+# UI it doesn't own. This is necessary to allow screenshots to be taken
+LOCAL_CERTIFICATE := platform
+
+ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
+ include $(BUILD_PACKAGE)
+endif \ No newline at end of file
diff --git a/packages/SystemUI/shared/tests/AndroidManifest.xml b/packages/SystemUI/shared/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..3e1de499c801
--- /dev/null
+++ b/packages/SystemUI/shared/tests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.systemui.shared.tests">
+
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.testing.TestableInstrumentation"
+ android:targetPackage="com.android.systemui.shared.tests"
+ android:label="Tests for SystemUISharedLib">
+ </instrumentation>
+</manifest>
diff --git a/packages/SystemUI/shared/tests/AndroidTest.xml b/packages/SystemUI/shared/tests/AndroidTest.xml
new file mode 100644
index 000000000000..b3de8368deec
--- /dev/null
+++ b/packages/SystemUI/shared/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Tests for SystemUISharedLib.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="SystemUISharedLibTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="SystemUISharedLibTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.systemui.shared.tests" />
+ <option name="runner" value="android.testing.TestableInstrumentation" />
+ </test>
+</configuration>
diff --git a/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
new file mode 100644
index 000000000000..04b341e38c04
--- /dev/null
+++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/SysuiSharedLibTestCase.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2014 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.shared;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * Base class that does System UI Shared Lib specific setup.
+ */
+public abstract class SysuiSharedLibTestCase {
+
+ private static final String TAG = "SysuiSharedLibTestCase";
+
+ private Handler mHandler;
+ private Context mContext = InstrumentationRegistry.getContext();
+
+ @Before
+ public void SysuiSetup() throws Exception {
+ // Enable shared class loader to test package-private classes/methods
+ System.setProperty("dexmaker.share_classloader", "true");
+ }
+
+ @After
+ public void SysuiTeardown() {
+ // Do nothing
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ protected void waitForIdleSync() {
+ if (mHandler == null) {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+ waitForIdleSync(mHandler);
+ }
+
+ public static void waitForIdleSync(Handler h) {
+ validateThread(h.getLooper());
+ Idler idler = new Idler(null);
+ h.getLooper().getQueue().addIdleHandler(idler);
+ // Ensure we are non-idle, so the idle handler can run.
+ h.post(new EmptyRunnable());
+ idler.waitForIdle();
+ }
+
+ private static final void validateThread(Looper l) {
+ if (Looper.myLooper() == l) {
+ throw new RuntimeException(
+ "This method can not be called from the looper being synced");
+ }
+ }
+
+ public static final class EmptyRunnable implements Runnable {
+ public void run() {
+ }
+ }
+
+ public static final class Idler implements MessageQueue.IdleHandler {
+ private final Runnable mCallback;
+ private boolean mIdle;
+
+ public Idler(Runnable callback) {
+ mCallback = callback;
+ mIdle = false;
+ }
+
+ @Override
+ public boolean queueIdle() {
+ if (mCallback != null) {
+ mCallback.run();
+ }
+ synchronized (this) {
+ mIdle = true;
+ notifyAll();
+ }
+ return false;
+ }
+
+ public void waitForIdle() {
+ synchronized (this) {
+ while (!mIdle) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
index 4564c8c79814..b03ea90fb1db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
+++ b/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
@@ -14,9 +14,10 @@
* limitations under the License
*/
-package com.android.systemui.recents.model;
+package com.android.systemui.shared.recents.model;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.anyBoolean;
@@ -29,9 +30,9 @@ import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task.TaskKey;
+import com.android.systemui.shared.SysuiSharedLibTestCase;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import org.junit.Before;
import org.junit.Test;
@@ -40,16 +41,16 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
- * runtest systemui -c com.android.systemui.recents.model.HighResThumbnailLoaderTest
+ * runtest --path frameworks/base/packages/SystemUI/shared/tests/src/com/android/systemui/shared/recents/model/HighResThumbnailLoaderTest.java
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class HighResThumbnailLoaderTest extends SysuiTestCase {
+public class HighResThumbnailLoaderTest extends SysuiSharedLibTestCase {
private HighResThumbnailLoader mLoader;
@Mock
- private SystemServicesProxy mMockSystemServicesProxy;
+ private ActivityManagerWrapper mMockActivityManagerWrapper;
@Mock
private Task mTask;
@@ -58,10 +59,10 @@ public class HighResThumbnailLoaderTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mLoader = new HighResThumbnailLoader(mMockSystemServicesProxy, Looper.getMainLooper(),
- false);
+ mLoader = new HighResThumbnailLoader(mMockActivityManagerWrapper, Looper.getMainLooper(),
+ false /* reducedResolution */);
mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, 0, 0);
- when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
+ when(mMockActivityManagerWrapper.getTaskThumbnail(anyInt(), anyBoolean()))
.thenReturn(mThumbnailData);
mLoader.setVisible(true);
mLoader.setTaskLoadQueueIdle(true);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index abc5667251ea..e6d6c5586ad8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -28,8 +28,6 @@ import android.view.InputEvent;
import android.view.IWindowManager;
import android.view.MotionEvent;
-import com.android.systemui.recents.misc.Utilities;
-
import java.io.PrintWriter;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 176112baa2a5..b3244a5947df 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -305,7 +305,15 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
state.state = Tile.STATE_UNAVAILABLE;
drawable = mDefaultIcon.loadDrawable(mContext);
}
- state.icon = new DrawableIcon(drawable);
+
+ final Drawable drawableF = drawable;
+ state.iconSupplier = () -> {
+ Drawable.ConstantState cs = drawableF.getConstantState();
+ if (cs != null) {
+ return new DrawableIcon(cs.newDrawable());
+ }
+ return null;
+ };
state.label = mTile.getLabel();
if (mTile.getContentDescription() != null) {
state.contentDescription = mTile.getContentDescription();
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 e8c8b9075792..c249e3778c0a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -87,14 +87,15 @@ public class QSIconViewImpl extends QSIconView {
}
protected void updateIcon(ImageView iv, State state) {
- if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))
+ final QSTile.Icon icon = state.iconSupplier != null ? state.iconSupplier.get() : state.icon;
+ if (!Objects.equals(icon, iv.getTag(R.id.qs_icon_tag))
|| !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) {
boolean shouldAnimate = iv.isShown() && mAnimationEnabled
&& iv.getDrawable() != null;
- Drawable d = state.icon != null
- ? shouldAnimate ? state.icon.getDrawable(mContext)
- : state.icon.getInvisibleDrawable(mContext) : null;
- int padding = state.icon != null ? state.icon.getPadding() : 0;
+ Drawable d = icon != null
+ ? shouldAnimate ? icon.getDrawable(mContext)
+ : icon.getInvisibleDrawable(mContext) : null;
+ int padding = icon != null ? icon.getPadding() : 0;
if (d != null) {
d.setAutoMirrored(false);
d.setLayoutDirection(getLayoutDirection());
@@ -107,7 +108,7 @@ public class QSIconViewImpl extends QSIconView {
iv.setImageDrawable(d);
}
- iv.setTag(R.id.qs_icon_tag, state.icon);
+ iv.setTag(R.id.qs_icon_tag, icon);
iv.setTag(R.id.qs_slash_tag, state.slash);
iv.setPadding(0, padding, 0, padding);
if (d instanceof Animatable2) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index cc7798e8721b..58d8d8fd600a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -31,5 +31,6 @@ oneway interface IRecentsSystemUserCallbacks {
void sendRecentsDrawnEvent();
void sendDockingTopTaskEvent(int dragMode, in Rect initialRect);
void sendLaunchRecentsEvent();
+ void sendDockedFirstAnimationFrameEvent();
void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index b96bd9b2d7cb..ce1438a14e52 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -29,14 +29,13 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.EventLog;
@@ -53,6 +52,7 @@ import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
@@ -62,7 +62,7 @@ import com.android.systemui.recents.events.component.SetWaitingForTransitionStar
import com.android.systemui.recents.events.component.ShowUserToastEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
@@ -191,10 +191,20 @@ public class Recents extends SystemUI
@Override
public void start() {
+ final Resources res = mContext.getResources();
+ final int defaultTaskBarBackgroundColor =
+ mContext.getColor(R.color.recents_task_bar_default_background_color);
+ final int defaultTaskViewBackgroundColor =
+ mContext.getColor(R.color.recents_task_view_default_background_color);
sDebugFlags = new RecentsDebugFlags();
sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
sConfiguration = new RecentsConfiguration(mContext);
- sTaskLoader = new RecentsTaskLoader(mContext);
+ sTaskLoader = new RecentsTaskLoader(mContext,
+ // TODO: Once we start building the AAR, move these into the loader
+ res.getInteger(R.integer.config_recents_max_thumbnail_count),
+ res.getInteger(R.integer.config_recents_max_icon_count),
+ res.getInteger(R.integer.recents_svelte_level));
+ sTaskLoader.setDefaultColors(defaultTaskBarBackgroundColor, defaultTaskViewBackgroundColor);
mHandler = new Handler();
mImpl = new RecentsImpl(mContext);
@@ -596,6 +606,23 @@ public class Recents extends SystemUI
}
}
+ public final void onBusEvent(DockedFirstAnimationFrameEvent event) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ int processUser = ssp.getProcessUser();
+ if (!ssp.isSystemUser(processUser)) {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mUserToSystemCallbacks.sendDockedFirstAnimationFrameEvent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
/**
* Handle screen pinning request.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 711885c40692..b75a142864e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -85,11 +85,11 @@ import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -427,7 +427,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
if (loadPlan == null) {
- loadPlan = loader.createLoadPlan(this);
+ loadPlan = new RecentsTaskLoadPlan(this);
}
// Start loading tasks according to the load plan
@@ -441,7 +441,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
loadOpts.runningTaskId = launchState.launchedToTaskId;
loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
+ loader.loadTasks(loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
mRecentsView.onReload(stack, mIsVisible);
@@ -815,13 +815,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ RecentsTaskLoadPlan loadPlan = new RecentsTaskLoadPlan(this);
loader.preloadTasks(loadPlan, -1 /* runningTaskId */);
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
- loader.loadTasks(this, loadPlan, loadOpts);
+ loader.loadTasks(loadPlan, loadOpts);
TaskStack stack = loadPlan.getTaskStack();
int numStackTasks = stack.getStackTaskCount();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 2c3a727e00b9..d2326ce2673d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -33,7 +33,6 @@ public class RecentsActivityLaunchState {
public boolean launchedFromPipApp;
// Set if the next activity that quick-switch will launch is the PiP activity
public boolean launchedWithNextPipApp;
- public boolean launchedFromBlacklistedApp;
public boolean launchedFromHome;
public boolean launchedViaDragGesture;
public boolean launchedViaDockGesture;
@@ -44,7 +43,6 @@ public class RecentsActivityLaunchState {
public void reset() {
launchedFromHome = false;
launchedFromApp = false;
- launchedFromBlacklistedApp = false;
launchedFromPipApp = false;
launchedWithNextPipApp = false;
launchedToTaskId = -1;
@@ -60,12 +58,6 @@ public class RecentsActivityLaunchState {
RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
if (launchedFromApp) {
- if (launchState.launchedFromBlacklistedApp) {
- // If we are launching from a blacklisted app, focus the front most task so that the
- // next tap will launch the task
- return numTasks - 1;
- }
-
if (useGridLayout) {
// If coming from another app to the grid layout, focus the front most task
return numTasks - 1;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 5dc6f31cae9a..68df1d5bd322 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -20,31 +20,31 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.os.SystemProperties;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.DockState;
+import com.android.systemui.shared.recents.model.TaskStack;
/**
* Represents the dock regions for each orientation.
*/
class DockRegion {
- public static TaskStack.DockState[] PHONE_LANDSCAPE = {
+ public static DockState[] PHONE_LANDSCAPE = {
// We only allow docking to the left in landscape for now on small devices
- TaskStack.DockState.LEFT
+ DockState.LEFT
};
- public static TaskStack.DockState[] PHONE_PORTRAIT = {
+ public static DockState[] PHONE_PORTRAIT = {
// We only allow docking to the top for now on small devices
- TaskStack.DockState.TOP
+ DockState.TOP
};
- public static TaskStack.DockState[] TABLET_LANDSCAPE = {
- TaskStack.DockState.LEFT,
- TaskStack.DockState.RIGHT
+ public static DockState[] TABLET_LANDSCAPE = {
+ DockState.LEFT,
+ DockState.RIGHT
};
- public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
+ public static DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
}
/**
@@ -56,18 +56,6 @@ public class RecentsConfiguration {
private static final int LARGE_SCREEN_MIN_DP = 600;
private static final int XLARGE_SCREEN_MIN_DP = 720;
- /** Levels of svelte in increasing severity/austerity. */
- // No svelting.
- public static final int SVELTE_NONE = 0;
- // Limit thumbnail cache to number of visible thumbnails when Recents was loaded, disable
- // caching thumbnails as you scroll.
- public static final int SVELTE_LIMIT_CACHE = 1;
- // Disable the thumbnail cache, load thumbnails asynchronously when the activity loads and
- // evict all thumbnails when hidden.
- public static final int SVELTE_DISABLE_CACHE = 2;
- // Disable all thumbnail loading.
- public static final int SVELTE_DISABLE_LOADING = 3;
-
// Launch states
public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState();
@@ -125,7 +113,7 @@ public class RecentsConfiguration {
* Returns the preferred dock states for the current orientation.
* @return a list of dock states for device and its orientation
*/
- public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
+ public DockState[] getDockStatesForCurrentOrientation() {
boolean isLandscape = mAppContext.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
RecentsConfiguration config = Recents.getConfiguration();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index a8dafbf70f4e..19185939c553 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -21,8 +21,6 @@ public class RecentsDebugFlags {
public static class Static {
// Enables debug drawing for the transition thumbnail
public static final boolean EnableTransitionThumbnailDebugMode = false;
- // Enables debug thumbnail to be fetched
- public static final boolean EnableThumbnailDebugMode = false;
// Disables enter and exit transitions for other tasks for low ram devices
public static final boolean DisableRecentsLowRamEnterExitAnimation = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 3f8d53f10616..868ed64bab2e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -71,12 +71,12 @@ import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.TaskStackChangeListener;
-import com.android.systemui.recents.model.RecentsTaskLoadPlan;
-import com.android.systemui.recents.model.RecentsTaskLoader;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.Task.TaskKey;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
+import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.recents.views.RecentsTransitionHelper;
import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
@@ -127,7 +127,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Preloads the next task
RecentsConfiguration config = Recents.getConfiguration();
- if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+ if (config.svelteLevel == RecentsTaskLoader.SVELTE_NONE) {
Rect windowRect = getWindowRect(null /* windowRectOverride */);
if (windowRect.isEmpty()) {
return;
@@ -137,7 +137,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
TaskStack stack = plan.getTaskStack();
RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
@@ -164,7 +164,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
launchOpts.onlyLoadPausedActivities = true;
launchOpts.loadThumbnails = true;
}
- loader.loadTasks(mContext, plan, launchOpts);
+ loader.loadTasks(plan, launchOpts);
}
}
@@ -203,7 +203,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId,
- ThumbnailData.createFromTaskSnapshot(snapshot)));
+ new ThumbnailData(snapshot)));
}
}
@@ -278,13 +278,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
launchOpts.numVisibleTasks = loader.getIconCacheSize();
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
launchOpts.onlyLoadForCache = true;
- loader.loadTasks(mContext, plan, launchOpts);
+ loader.loadTasks(plan, launchOpts);
}
public void onConfigurationChanged() {
@@ -471,7 +471,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
RecentsTaskLoader loader = Recents.getTaskLoader();
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
+ sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(sInstanceLoadPlan, runningTask.id);
TaskStack stack = sInstanceLoadPlan.getTaskStack();
if (stack.getTaskCount() > 0) {
@@ -511,7 +511,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
public void showNextTask() {
SystemServicesProxy ssp = Recents.getSystemServices();
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
TaskStack focusedStack = plan.getTaskStack();
@@ -566,7 +566,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
public void showRelativeAffiliatedTask(boolean showNextTask) {
SystemServicesProxy ssp = Recents.getSystemServices();
RecentsTaskLoader loader = Recents.getTaskLoader();
- RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
+ RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
TaskStack focusedStack = plan.getTaskStack();
@@ -827,7 +827,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
launchOpts.runningTaskId = runningTaskId;
launchOpts.loadThumbnails = false;
launchOpts.onlyLoadForCache = true;
- Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+ Recents.getTaskLoader().loadTasks(sInstanceLoadPlan, launchOpts);
}
/**
@@ -947,12 +947,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
boolean isHomeStackVisible, boolean animate, int growTarget) {
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- SystemServicesProxy ssp = Recents.getSystemServices();
- boolean isBlacklisted = (runningTask != null)
- ? ssp.isBlackListedActivity(runningTask.baseActivity.getClassName())
- : false;
- int runningTaskId = !mLaunchedWhileDocking && !isBlacklisted && (runningTask != null)
+ int runningTaskId = !mLaunchedWhileDocking && (runningTask != null)
? runningTask.id
: -1;
@@ -961,7 +957,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// the stacks might have changed.
if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) {
// Create a new load plan if preloadRecents() was never triggered
- sInstanceLoadPlan = loader.createLoadPlan(mContext);
+ sInstanceLoadPlan = new RecentsTaskLoadPlan(mContext);
}
if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
loader.preloadTasks(sInstanceLoadPlan, runningTaskId);
@@ -975,7 +971,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Update the launch state that we need in updateHeaderBarLayout()
launchState.launchedFromHome = !useThumbnailTransition && !mLaunchedWhileDocking;
launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
- launchState.launchedFromBlacklistedApp = launchState.launchedFromApp && isBlacklisted;
launchState.launchedFromPipApp = false;
launchState.launchedWithNextPipApp =
stack.isNextLaunchTargetPip(RecentsImpl.getLastPipTime());
@@ -1011,9 +1006,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
Pair<ActivityOptions, AppTransitionAnimationSpecsFuture> pair;
- if (isBlacklisted) {
- pair = new Pair<>(getUnknownTransitionActivityOptions(), null);
- } else if (useThumbnailTransition) {
+ if (useThumbnailTransition) {
// Try starting with a thumbnail transition
pair = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index 1285626015d2..ff1f7dc5a2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -27,6 +27,7 @@ import android.util.SparseArray;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
@@ -108,6 +109,11 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub {
}
@Override
+ public void sendDockedFirstAnimationFrameEvent() throws RemoteException {
+ EventBus.getDefault().post(new DockedFirstAnimationFrameEvent());
+ }
+
+ @Override
public void setWaitingForTransitionStartEvent(boolean waitingForTransitionStart) {
EventBus.getDefault().post(new SetWaitingForTransitionStartEvent(
waitingForTransitionStart));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
index 7604de1d05d0..fec34e3cd23d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/CancelEnterRecentsWindowAnimationEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.activity;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
/**
* This is sent when we want to cancel the enter-recents window animation for the launch task.
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 862a1eee8c39..2409f39d3760 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
@@ -22,7 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.graphics.Rect;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
index 64eeafa1ae17..e4972b1fd7f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.activity;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
/**
* This is sent by the activity whenever the multi-window state has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
index 0d614e8c675c..51d02b5b0018 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.activity;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
/**
* This is sent by the activity whenever the task stach has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
index 4ed027084def..b52e83b81649 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
/**
* This is sent when the data associated with a given {@link Task} should be deleted from the
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
index 40c30b884eae..da19384ae93a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
/**
* This is sent when a user wants to show the application info for a {@link Task}.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
index e0ed7a9e7e35..f08292801b62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.model.ThumbnailData;
/**
* Sent when a task snapshot has changed.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
index 0628c5015153..881a64af5b0f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java
@@ -17,8 +17,8 @@
package com.android.systemui.recents.events.ui;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.views.AnimationProps;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
import com.android.systemui.recents.views.TaskView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
index 216be6121f8d..cf61b1ef7637 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragDropTargetChangedEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui.dragndrop;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.DropTarget;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
index edd799597ea6..297afc53c557 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndCancelledEvent.java
@@ -17,9 +17,8 @@
package com.android.systemui.recents.events.ui.dragndrop;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DropTarget;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.TaskView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
index 73c282fe8816..73cbde998319 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui.dragndrop;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.DropTarget;
import com.android.systemui.recents.views.TaskView;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index e57fa2d86a66..021be77bcc8b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -19,7 +19,7 @@ package com.android.systemui.recents.events.ui.dragndrop;
import android.graphics.Point;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.TaskView;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
index 7030729d2a04..64ba5748bb89 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartInitializeDropTargetsEvent.java
@@ -17,7 +17,7 @@
package com.android.systemui.recents.events.ui.dragndrop;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.RecentsViewTouchHandler;
import com.android.systemui.recents.views.TaskView;
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 a392effb1bca..87f24fdb6cdb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -16,7 +16,6 @@
package com.android.systemui.recents.misc;
-import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -27,21 +26,17 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
-import android.app.KeyguardManager;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -53,7 +48,6 @@ import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IRemoteCallback;
@@ -66,8 +60,6 @@ import android.os.UserManager;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
-import android.util.ArraySet;
-import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.MutableBoolean;
import android.view.Display;
@@ -84,17 +76,11 @@ import com.android.internal.os.BackgroundThread;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
-import com.android.systemui.pip.tv.PipMenuActivity;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags.Static;
import com.android.systemui.recents.RecentsImpl;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.statusbar.policy.UserInfoController;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
/**
@@ -111,26 +97,18 @@ public class SystemServicesProxy {
sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
}
- final static List<String> sRecentsBlacklist;
- static {
- sRecentsBlacklist = new ArrayList<>();
- sRecentsBlacklist.add(PipMenuActivity.class.getName());
- }
-
private static SystemServicesProxy sSystemServicesProxy;
AccessibilityManager mAccm;
ActivityManager mAm;
IActivityManager mIam;
PackageManager mPm;
- IconDrawableFactory mDrawableFactory;
IPackageManager mIpm;
private final IDreamManager mDreamManager;
private final Context mContext;
AssistUtils mAssistUtils;
WindowManager mWm;
IWindowManager mIwm;
- KeyguardManager mKgm;
UserManager mUm;
Display mDisplay;
String mRecentsPackage;
@@ -166,12 +144,10 @@ public class SystemServicesProxy {
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mIam = ActivityManager.getService();
mPm = context.getPackageManager();
- mDrawableFactory = IconDrawableFactory.newInstance(context);
mIpm = AppGlobals.getPackageManager();
mAssistUtils = new AssistUtils(context);
mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mIwm = WindowManagerGlobal.getWindowManagerService();
- mKgm = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
mUm = UserManager.get(context);
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.checkService(DreamService.DREAM_SERVICE));
@@ -199,9 +175,6 @@ public class SystemServicesProxy {
// calls to fetch it.
UserInfoController userInfoController = Dependency.get(UserInfoController.class);
userInfoController.addCallback(mOnUserInfoChangedListener);
-
- Collections.addAll(sRecentsBlacklist,
- res.getStringArray(R.array.recents_blacklist_array));
}
/**
@@ -223,39 +196,6 @@ public class SystemServicesProxy {
}
/**
- * @return whether the provided {@param className} is blacklisted
- */
- public boolean isBlackListedActivity(String className) {
- return sRecentsBlacklist.contains(className);
- }
-
- /**
- * Returns a list of the recents tasks.
- */
- public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
- if (mAm == null) return null;
-
- try {
- List<ActivityManager.RecentTaskInfo> tasks = mIam.getRecentTasks(numTasks,
- RECENT_IGNORE_UNAVAILABLE, userId).getList();
- Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
- while (iter.hasNext()) {
- ActivityManager.RecentTaskInfo t = iter.next();
-
- // Remove the task if it or it's package are blacklsited
- if (sRecentsBlacklist.contains(t.realActivity.getClassName()) ||
- sRecentsBlacklist.contains(t.realActivity.getPackageName())) {
- iter.remove();
- }
- }
- return tasks;
- } catch (Exception e) {
- Log.e(TAG, "Failed to get recent tasks", e);
- return new ArrayList<>();
- }
- }
-
- /**
* Returns the top running task.
*/
public ActivityManager.RunningTaskInfo getRunningTask() {
@@ -457,43 +397,6 @@ public class SystemServicesProxy {
}
}
- /** Returns the top task thumbnail for the given task id */
- public ThumbnailData getTaskThumbnail(int taskId, boolean reduced) {
- if (mAm == null) return null;
-
- // If we are mocking, then just return a dummy thumbnail
- if (Static.EnableTransitionThumbnailDebugMode) {
- ThumbnailData thumbnailData = new ThumbnailData();
- thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
- mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
- thumbnailData.thumbnail.eraseColor(0xff333333);
- return thumbnailData;
- }
-
- return getThumbnail(taskId, reduced);
- }
-
- /**
- * Returns a task thumbnail from the activity manager
- */
- public @NonNull ThumbnailData getThumbnail(int taskId, boolean reducedResolution) {
- if (mAm == null) {
- return new ThumbnailData();
- }
-
- ActivityManager.TaskSnapshot snapshot = null;
- try {
- snapshot = mIam.getTaskSnapshot(taskId, reducedResolution);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to retrieve snapshot", e);
- }
- if (snapshot != null) {
- return ThumbnailData.createFromTaskSnapshot(snapshot);
- } else {
- return new ThumbnailData();
- }
- }
-
/** Set the task's windowing mode. */
public void setTaskWindowingMode(int taskId, int windowingMode) {
if (mIam == null) return;
@@ -531,112 +434,6 @@ public class SystemServicesProxy {
});
}
- /**
- * Returns the activity info for a given component name.
- *
- * @param cn The component name of the activity.
- * @param userId The userId of the user that this is for.
- */
- public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
- if (mIpm == null) return null;
-
- try {
- return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
- } catch (RemoteException e) {
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * Returns the activity info for a given component name.
- *
- * @param cn The component name of the activity.
- */
- public ActivityInfo getActivityInfo(ComponentName cn) {
- if (mPm == null) return null;
-
- try {
- return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * Returns the activity label, badging if necessary.
- */
- public String getBadgedActivityLabel(ActivityInfo info, int userId) {
- if (mPm == null) return null;
-
- return getBadgedLabel(info.loadLabel(mPm).toString(), userId);
- }
-
- /**
- * Returns the application label, badging if necessary.
- */
- public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
- if (mPm == null) return null;
-
- return getBadgedLabel(appInfo.loadLabel(mPm).toString(), userId);
- }
-
- /**
- * Returns the content description for a given task, badging it if necessary. The content
- * description joins the app and activity labels.
- */
- public String getBadgedContentDescription(ActivityInfo info, int userId,
- ActivityManager.TaskDescription td, Resources res) {
- String activityLabel;
- if (td != null && td.getLabel() != null) {
- activityLabel = td.getLabel();
- } else {
- activityLabel = info.loadLabel(mPm).toString();
- }
- String applicationLabel = info.applicationInfo.loadLabel(mPm).toString();
- String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
- return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
- : res.getString(R.string.accessibility_recents_task_header,
- badgedApplicationLabel, activityLabel);
- }
-
- /**
- * Returns the activity icon for the ActivityInfo for a user, badging if
- * necessary.
- */
- public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
- if (mPm == null) return null;
-
- return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId);
- }
-
- /**
- * Returns the application icon for the ApplicationInfo for a user, badging if
- * necessary.
- */
- public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
- if (mPm == null) return null;
-
- return mDrawableFactory.getBadgedIcon(appInfo, userId);
- }
-
- /**
- * Returns the task description icon, loading and badging it if it necessary.
- */
- public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription,
- int userId, Resources res) {
- Bitmap tdIcon = taskDescription.getInMemoryIcon();
- if (tdIcon == null) {
- tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
- taskDescription.getIconFilename(), userId);
- }
- if (tdIcon != null) {
- return getBadgedIcon(new BitmapDrawable(res, tdIcon), userId);
- }
- return null;
- }
-
public ActivityManager.TaskDescription getTaskDescription(int taskId) {
try {
return mIam.getTaskDescription(taskId);
@@ -646,46 +443,6 @@ public class SystemServicesProxy {
}
/**
- * Returns the given icon for a user, badging if necessary.
- */
- private Drawable getBadgedIcon(Drawable icon, int userId) {
- if (userId != UserHandle.myUserId()) {
- icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
- }
- return icon;
- }
-
- /**
- * Returns a banner used on TV for the specified Activity.
- */
- public Drawable getActivityBanner(ActivityInfo info) {
- if (mPm == null) return null;
-
- Drawable banner = info.loadBanner(mPm);
- return banner;
- }
-
- /**
- * Returns the given label for a user, badging if necessary.
- */
- private String getBadgedLabel(String label, int userId) {
- if (userId != UserHandle.myUserId()) {
- label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
- }
- return label;
- }
-
- /**
- * Returns whether the provided {@param userId} is currently locked (and showing Keyguard).
- */
- public boolean isDeviceLocked(int userId) {
- if (mKgm == null) {
- return false;
- }
- return mKgm.isDeviceLocked(userId);
- }
-
- /**
* Returns whether the provided {@param userId} represents the system user.
*/
public boolean isSystemUser(int userId) {
@@ -790,7 +547,7 @@ public class SystemServicesProxy {
ActivityManager.StackInfo stackInfo =
mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS);
if (stackInfo == null) {
- stackInfo = mIam.getStackInfo(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD);
+ stackInfo = mIam.getStackInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
}
if (stackInfo != null) {
windowRect.set(stackInfo.bounds);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
deleted file mode 100644
index 32e62cf29a4e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (C) 2014 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.recents.model;
-
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.annotation.IntDef;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ColorDrawable;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.IntProperty;
-import android.util.SparseArray;
-import android.view.animation.Interpolator;
-
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.systemui.Interpolators;
-import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.views.AnimationProps;
-import com.android.systemui.recents.views.DropTarget;
-import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
-
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * An interface for a task filter to query whether a particular task should show in a stack.
- */
-interface TaskFilter {
- /** Returns whether the filter accepts the specified task */
- boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
-}
-
-/**
- * A list of filtered tasks.
- */
-class FilteredTaskList {
-
- ArrayList<Task> mTasks = new ArrayList<>();
- ArrayList<Task> mFilteredTasks = new ArrayList<>();
- ArrayMap<Task.TaskKey, Integer> mFilteredTaskIndices = new ArrayMap<>();
- TaskFilter mFilter;
-
- /** Sets the task filter, saving the current touch state */
- boolean setFilter(TaskFilter filter) {
- ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
- mFilter = filter;
- updateFilteredTasks();
- if (!prevFilteredTasks.equals(mFilteredTasks)) {
- return true;
- } else {
- return false;
- }
- }
-
- /** Removes the task filter and returns the previous touch state */
- void removeFilter() {
- mFilter = null;
- updateFilteredTasks();
- }
-
- /** Adds a new task to the task list */
- void add(Task t) {
- mTasks.add(t);
- updateFilteredTasks();
- }
-
- /** Sets the list of tasks */
- void set(List<Task> tasks) {
- mTasks.clear();
- mTasks.addAll(tasks);
- updateFilteredTasks();
- }
-
- /** Removes a task from the base list only if it is in the filtered list */
- boolean remove(Task t) {
- if (mFilteredTasks.contains(t)) {
- boolean removed = mTasks.remove(t);
- updateFilteredTasks();
- return removed;
- }
- return false;
- }
-
- /** Returns the index of this task in the list of filtered tasks */
- int indexOf(Task t) {
- if (t != null && mFilteredTaskIndices.containsKey(t.key)) {
- return mFilteredTaskIndices.get(t.key);
- }
- return -1;
- }
-
- /** Returns the size of the list of filtered tasks */
- int size() {
- return mFilteredTasks.size();
- }
-
- /** Returns whether the filtered list contains this task */
- boolean contains(Task t) {
- return mFilteredTaskIndices.containsKey(t.key);
- }
-
- /** Updates the list of filtered tasks whenever the base task list changes */
- private void updateFilteredTasks() {
- mFilteredTasks.clear();
- if (mFilter != null) {
- // Create a sparse array from task id to Task
- SparseArray<Task> taskIdMap = new SparseArray<>();
- int taskCount = mTasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task t = mTasks.get(i);
- taskIdMap.put(t.key.id, t);
- }
-
- for (int i = 0; i < taskCount; i++) {
- Task t = mTasks.get(i);
- if (mFilter.acceptTask(taskIdMap, t, i)) {
- mFilteredTasks.add(t);
- }
- }
- } else {
- mFilteredTasks.addAll(mTasks);
- }
- updateFilteredTaskIndices();
- }
-
- /** Updates the mapping of tasks to indices. */
- private void updateFilteredTaskIndices() {
- int taskCount = mFilteredTasks.size();
- mFilteredTaskIndices.clear();
- for (int i = 0; i < taskCount; i++) {
- Task t = mFilteredTasks.get(i);
- mFilteredTaskIndices.put(t.key, i);
- }
- }
-
- /** Returns the list of filtered tasks */
- ArrayList<Task> getTasks() {
- return mFilteredTasks;
- }
-}
-
-/**
- * The task stack contains a list of multiple tasks.
- */
-public class TaskStack {
-
- private static final String TAG = "TaskStack";
-
- /** Task stack callbacks */
- public interface TaskStackCallbacks {
- /**
- * Notifies when a new task has been added to the stack.
- */
- void onStackTaskAdded(TaskStack stack, Task newTask);
-
- /**
- * Notifies when a task has been removed from the stack.
- */
- void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
- AnimationProps animation, boolean fromDockGesture,
- boolean dismissRecentsIfAllRemoved);
-
- /**
- * Notifies when all tasks have been removed from the stack.
- */
- void onStackTasksRemoved(TaskStack stack);
-
- /**
- * Notifies when tasks in the stack have been updated.
- */
- void onStackTasksUpdated(TaskStack stack);
- }
-
- /**
- * The various possible dock states when dragging and dropping a task.
- */
- public static class DockState implements DropTarget {
-
- public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
- public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
-
- // The rotation to apply to the hint text
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({HORIZONTAL, VERTICAL})
- public @interface TextOrientation {}
- private static final int HORIZONTAL = 0;
- private static final int VERTICAL = 1;
-
- private static final int DOCK_AREA_ALPHA = 80;
- public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
- null, null, null);
- public static final DockState LEFT = new DockState(DOCKED_LEFT,
- DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
- new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
- new RectF(0, 0, 0.5f, 1));
- public static final DockState TOP = new DockState(DOCKED_TOP,
- DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
- new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
- new RectF(0, 0, 1, 0.5f));
- public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
- DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
- new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
- new RectF(0.5f, 0, 1, 1));
- public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
- DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
- new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
- new RectF(0, 0.5f, 1, 1));
-
- @Override
- public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
- boolean isCurrentTarget) {
- if (isCurrentTarget) {
- getMappedRect(expandedTouchDockArea, width, height, mTmpRect);
- return mTmpRect.contains(x, y);
- } else {
- getMappedRect(touchArea, width, height, mTmpRect);
- updateBoundsWithSystemInsets(mTmpRect, insets);
- return mTmpRect.contains(x, y);
- }
- }
-
- // Represents the view state of this dock state
- public static class ViewState {
- private static final IntProperty<ViewState> HINT_ALPHA =
- new IntProperty<ViewState>("drawableAlpha") {
- @Override
- public void setValue(ViewState object, int alpha) {
- object.mHintTextAlpha = alpha;
- object.dockAreaOverlay.invalidateSelf();
- }
-
- @Override
- public Integer get(ViewState object) {
- return object.mHintTextAlpha;
- }
- };
-
- public final int dockAreaAlpha;
- public final ColorDrawable dockAreaOverlay;
- public final int hintTextAlpha;
- public final int hintTextOrientation;
-
- private final int mHintTextResId;
- private String mHintText;
- private Paint mHintTextPaint;
- private Point mHintTextBounds = new Point();
- private int mHintTextAlpha = 255;
- private AnimatorSet mDockAreaOverlayAnimator;
- private Rect mTmpRect = new Rect();
-
- private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
- int hintTextResId) {
- dockAreaAlpha = areaAlpha;
- dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
- ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
- dockAreaOverlay.setAlpha(0);
- hintTextAlpha = hintAlpha;
- hintTextOrientation = hintOrientation;
- mHintTextResId = hintTextResId;
- mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mHintTextPaint.setColor(Color.WHITE);
- }
-
- /**
- * Updates the view state with the given context.
- */
- public void update(Context context) {
- Resources res = context.getResources();
- mHintText = context.getString(mHintTextResId);
- mHintTextPaint.setTextSize(res.getDimensionPixelSize(
- R.dimen.recents_drag_hint_text_size));
- mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect);
- mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height());
- }
-
- /**
- * Draws the current view state.
- */
- public void draw(Canvas canvas) {
- // Draw the overlay background
- if (dockAreaOverlay.getAlpha() > 0) {
- dockAreaOverlay.draw(canvas);
- }
-
- // Draw the hint text
- if (mHintTextAlpha > 0) {
- Rect bounds = dockAreaOverlay.getBounds();
- int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2;
- int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2;
- mHintTextPaint.setAlpha(mHintTextAlpha);
- if (hintTextOrientation == VERTICAL) {
- canvas.save();
- canvas.rotate(-90f, bounds.centerX(), bounds.centerY());
- }
- canvas.drawText(mHintText, x, y, mHintTextPaint);
- if (hintTextOrientation == VERTICAL) {
- canvas.restore();
- }
- }
- }
-
- /**
- * Creates a new bounds and alpha animation.
- */
- public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration,
- Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
- if (mDockAreaOverlayAnimator != null) {
- mDockAreaOverlayAnimator.cancel();
- }
-
- ObjectAnimator anim;
- ArrayList<Animator> animators = new ArrayList<>();
- if (dockAreaOverlay.getAlpha() != areaAlpha) {
- if (animateAlpha) {
- anim = ObjectAnimator.ofInt(dockAreaOverlay,
- Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha);
- anim.setDuration(duration);
- anim.setInterpolator(interpolator);
- animators.add(anim);
- } else {
- dockAreaOverlay.setAlpha(areaAlpha);
- }
- }
- if (mHintTextAlpha != hintAlpha) {
- if (animateAlpha) {
- anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
- hintAlpha);
- anim.setDuration(150);
- anim.setInterpolator(hintAlpha > mHintTextAlpha
- ? Interpolators.ALPHA_IN
- : Interpolators.ALPHA_OUT);
- animators.add(anim);
- } else {
- mHintTextAlpha = hintAlpha;
- dockAreaOverlay.invalidateSelf();
- }
- }
- if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
- if (animateBounds) {
- PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
- Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
- new Rect(dockAreaOverlay.getBounds()), bounds);
- anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop);
- anim.setDuration(duration);
- anim.setInterpolator(interpolator);
- animators.add(anim);
- } else {
- dockAreaOverlay.setBounds(bounds);
- }
- }
- if (!animators.isEmpty()) {
- mDockAreaOverlayAnimator = new AnimatorSet();
- mDockAreaOverlayAnimator.playTogether(animators);
- mDockAreaOverlayAnimator.start();
- }
- }
- }
-
- public final int dockSide;
- public final int createMode;
- public final ViewState viewState;
- private final RectF touchArea;
- private final RectF dockArea;
- private final RectF expandedTouchDockArea;
- private static final Rect mTmpRect = new Rect();
-
- /**
- * @param createMode used to pass to ActivityManager to dock the task
- * @param touchArea the area in which touch will initiate this dock state
- * @param dockArea the visible dock area
- * @param expandedTouchDockArea the area in which touch will continue to dock after entering
- * the initial touch area. This is also the new dock area to
- * draw.
- */
- DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha,
- @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea,
- RectF expandedTouchDockArea) {
- this.dockSide = dockSide;
- this.createMode = createMode;
- this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation,
- R.string.recents_drag_hint_message);
- this.dockArea = dockArea;
- this.touchArea = touchArea;
- this.expandedTouchDockArea = expandedTouchDockArea;
- }
-
- /**
- * Updates the dock state with the given context.
- */
- public void update(Context context) {
- viewState.update(context);
- }
-
- /**
- * Returns the docked task bounds with the given {@param width} and {@param height}.
- */
- public Rect getPreDockedBounds(int width, int height, Rect insets) {
- getMappedRect(dockArea, width, height, mTmpRect);
- return updateBoundsWithSystemInsets(mTmpRect, insets);
- }
-
- /**
- * Returns the expanded docked task bounds with the given {@param width} and
- * {@param height}.
- */
- public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
- Resources res) {
- // Calculate the docked task bounds
- boolean isHorizontalDivision =
- res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
- int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
- insets, width, height, dividerSize);
- Rect newWindowBounds = new Rect();
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds,
- width, height, dividerSize);
- return newWindowBounds;
- }
-
- /**
- * Returns the task stack bounds with the given {@param width} and
- * {@param height}.
- */
- public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height,
- int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm,
- Resources res, Rect windowRectOut) {
- // Calculate the inverse docked task bounds
- boolean isHorizontalDivision =
- res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
- int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
- insets, width, height, dividerSize);
- DockedDividerUtils.calculateBoundsForPosition(position,
- DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
- dividerSize);
-
- // Calculate the task stack bounds from the new window bounds
- Rect taskStackBounds = new Rect();
- // If the task stack bounds is specifically under the dock area, then ignore the top
- // inset
- int top = dockArea.bottom < 1f
- ? 0
- : insets.top;
- // For now, ignore the left insets since we always dock on the left and show Recents
- // on the right
- layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right,
- taskStackBounds);
- return taskStackBounds;
- }
-
- /**
- * Returns the expanded bounds in certain dock sides such that the bounds account for the
- * system insets (namely the vertical nav bar). This call modifies and returns the given
- * {@param bounds}.
- */
- private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) {
- if (dockSide == DOCKED_LEFT) {
- bounds.right += insets.left;
- } else if (dockSide == DOCKED_RIGHT) {
- bounds.left -= insets.right;
- }
- return bounds;
- }
-
- /**
- * Returns the mapped rect to the given dimensions.
- */
- private void getMappedRect(RectF bounds, int width, int height, Rect out) {
- out.set((int) (bounds.left * width), (int) (bounds.top * height),
- (int) (bounds.right * width), (int) (bounds.bottom * height));
- }
- }
-
- ArrayList<Task> mRawTaskList = new ArrayList<>();
- FilteredTaskList mStackTaskList = new FilteredTaskList();
- TaskStackCallbacks mCb;
-
- public TaskStack() {
- // Ensure that we only show stack tasks
- mStackTaskList.setFilter(new TaskFilter() {
- @Override
- public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
- return t.isStackTask;
- }
- });
- }
-
- /** Sets the callbacks for this task stack. */
- public void setCallbacks(TaskStackCallbacks cb) {
- mCb = cb;
- }
-
- /**
- * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
- * how they should update themselves.
- */
- public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
- removeTask(t, animation, fromDockGesture, true /* dismissRecentsIfAllRemoved */);
- }
-
- /**
- * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
- * how they should update themselves.
- */
- public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture,
- boolean dismissRecentsIfAllRemoved) {
- if (mStackTaskList.contains(t)) {
- mStackTaskList.remove(t);
- Task newFrontMostTask = getStackFrontMostTask();
- if (mCb != null) {
- // Notify that a task has been removed
- mCb.onStackTaskRemoved(this, t, newFrontMostTask, animation,
- fromDockGesture, dismissRecentsIfAllRemoved);
- }
- }
- mRawTaskList.remove(t);
- }
-
- /**
- * Removes all tasks from the stack.
- */
- public void removeAllTasks(boolean notifyStackChanges) {
- ArrayList<Task> tasks = mStackTaskList.getTasks();
- for (int i = tasks.size() - 1; i >= 0; i--) {
- Task t = tasks.get(i);
- mStackTaskList.remove(t);
- mRawTaskList.remove(t);
- }
- if (mCb != null && notifyStackChanges) {
- // Notify that all tasks have been removed
- mCb.onStackTasksRemoved(this);
- }
- }
-
-
- /**
- * @see #setTasks(List, boolean)
- */
- public void setTasks(TaskStack stack, boolean notifyStackChanges) {
- setTasks(stack.mRawTaskList, notifyStackChanges);
- }
-
- /**
- * Sets a few tasks in one go, without calling any callbacks.
- *
- * @param tasks the new set of tasks to replace the current set.
- * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
- */
- public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
- // Compute a has set for each of the tasks
- ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
- ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
- ArrayList<Task> addedTasks = new ArrayList<>();
- ArrayList<Task> removedTasks = new ArrayList<>();
- ArrayList<Task> allTasks = new ArrayList<>();
-
- // Disable notifications if there are no callbacks
- if (mCb == null) {
- notifyStackChanges = false;
- }
-
- // Remove any tasks that no longer exist
- int taskCount = mRawTaskList.size();
- for (int i = taskCount - 1; i >= 0; i--) {
- Task task = mRawTaskList.get(i);
- if (!newTasksMap.containsKey(task.key)) {
- if (notifyStackChanges) {
- removedTasks.add(task);
- }
- }
- }
-
- // Add any new tasks
- taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task newTask = tasks.get(i);
- Task currentTask = currentTasksMap.get(newTask.key);
- if (currentTask == null && notifyStackChanges) {
- addedTasks.add(newTask);
- } else if (currentTask != null) {
- // The current task has bound callbacks, so just copy the data from the new task
- // state and add it back into the list
- currentTask.copyFrom(newTask);
- newTask = currentTask;
- }
- allTasks.add(newTask);
- }
-
- // Sort all the tasks to ensure they are ordered correctly
- for (int i = allTasks.size() - 1; i >= 0; i--) {
- allTasks.get(i).temporarySortIndexInStack = i;
- }
-
- mStackTaskList.set(allTasks);
- mRawTaskList = allTasks;
-
- // Only callback for the removed tasks after the stack has updated
- int removedTaskCount = removedTasks.size();
- Task newFrontMostTask = getStackFrontMostTask();
- for (int i = 0; i < removedTaskCount; i++) {
- mCb.onStackTaskRemoved(this, removedTasks.get(i), newFrontMostTask,
- AnimationProps.IMMEDIATE, false /* fromDockGesture */,
- true /* dismissRecentsIfAllRemoved */);
- }
-
- // Only callback for the newly added tasks after this stack has been updated
- int addedTaskCount = addedTasks.size();
- for (int i = 0; i < addedTaskCount; i++) {
- mCb.onStackTaskAdded(this, addedTasks.get(i));
- }
-
- // Notify that the task stack has been updated
- if (notifyStackChanges) {
- mCb.onStackTasksUpdated(this);
- }
- }
-
- /**
- * Gets the front-most task in the stack.
- */
- public Task getStackFrontMostTask() {
- ArrayList<Task> stackTasks = mStackTaskList.getTasks();
- if (stackTasks.isEmpty()) {
- return null;
- }
- return stackTasks.get(stackTasks.size() - 1);
- }
-
- /** Gets the task keys */
- public ArrayList<Task.TaskKey> getTaskKeys() {
- ArrayList<Task.TaskKey> taskKeys = new ArrayList<>();
- ArrayList<Task> tasks = computeAllTasksList();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- taskKeys.add(task.key);
- }
- return taskKeys;
- }
-
- /**
- * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
- */
- public ArrayList<Task> getStackTasks() {
- return mStackTaskList.getTasks();
- }
-
- /**
- * Computes a set of all the active and historical tasks.
- */
- public ArrayList<Task> computeAllTasksList() {
- ArrayList<Task> tasks = new ArrayList<>();
- tasks.addAll(mStackTaskList.getTasks());
- return tasks;
- }
-
- /**
- * Returns the number of stacktasks.
- */
- public int getTaskCount() {
- return mStackTaskList.size();
- }
-
- /**
- * Returns the number of stack tasks.
- */
- public int getStackTaskCount() {
- return mStackTaskList.size();
- }
-
- /**
- * Returns the task in stack tasks which is the launch target.
- */
- public Task getLaunchTarget() {
- ArrayList<Task> tasks = mStackTaskList.getTasks();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- if (task.isLaunchTarget) {
- return task;
- }
- }
- return null;
- }
-
- /**
- * Returns whether the next launch target should actually be the PiP task.
- */
- public boolean isNextLaunchTargetPip(long lastPipTime) {
- Task launchTarget = getLaunchTarget();
- Task nextLaunchTarget = getNextLaunchTargetRaw();
- if (nextLaunchTarget != null && lastPipTime > 0) {
- // If the PiP time is more recent than the next launch target, then launch the PiP task
- return lastPipTime > nextLaunchTarget.key.lastActiveTime;
- } else if (launchTarget != null && lastPipTime > 0 && getTaskCount() == 1) {
- // Otherwise, if there is no next launch target, but there is a PiP, then launch
- // the PiP task
- return true;
- }
- return false;
- }
-
- /**
- * Returns the task in stack tasks which should be launched next if Recents are toggled
- * again, or null if there is no task to be launched. Callers should check
- * {@link #isNextLaunchTargetPip(long)} before fetching the next raw launch target from the
- * stack.
- */
- public Task getNextLaunchTarget() {
- Task nextLaunchTarget = getNextLaunchTargetRaw();
- if (nextLaunchTarget != null) {
- return nextLaunchTarget;
- }
- return getStackTasks().get(getTaskCount() - 1);
- }
-
- private Task getNextLaunchTargetRaw() {
- int taskCount = getTaskCount();
- if (taskCount == 0) {
- return null;
- }
- int launchTaskIndex = indexOfStackTask(getLaunchTarget());
- if (launchTaskIndex != -1 && launchTaskIndex > 0) {
- return getStackTasks().get(launchTaskIndex - 1);
- }
- return null;
- }
-
- /** Returns the index of this task in this current task stack */
- public int indexOfStackTask(Task t) {
- return mStackTaskList.indexOf(t);
- }
-
- /** Finds the task with the specified task id. */
- public Task findTaskWithId(int taskId) {
- ArrayList<Task> tasks = computeAllTasksList();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- if (task.key.id == taskId) {
- return task;
- }
- }
- return null;
- }
-
- /**
- * Computes the components of tasks in this stack that have been removed as a result of a change
- * in the specified package.
- */
- public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
- // Identify all the tasks that should be removed as a result of the package being removed.
- // Using a set to ensure that we callback once per unique component.
- SystemServicesProxy ssp = Recents.getSystemServices();
- ArraySet<ComponentName> existingComponents = new ArraySet<>();
- ArraySet<ComponentName> removedComponents = new ArraySet<>();
- ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
- int taskKeyCount = taskKeys.size();
- for (int i = 0; i < taskKeyCount; i++) {
- Task.TaskKey t = taskKeys.get(i);
-
- // Skip if this doesn't apply to the current user
- if (t.userId != userId) continue;
-
- ComponentName cn = t.getComponent();
- if (cn.getPackageName().equals(packageName)) {
- if (existingComponents.contains(cn)) {
- // If we know that the component still exists in the package, then skip
- continue;
- }
- if (ssp.getActivityInfo(cn, userId) != null) {
- existingComponents.add(cn);
- } else {
- removedComponents.add(cn);
- }
- }
- }
- return removedComponents;
- }
-
- @Override
- public String toString() {
- String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
- ArrayList<Task> tasks = mStackTaskList.getTasks();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- str += " " + tasks.get(i).toString() + "\n";
- }
- return str;
- }
-
- /**
- * Given a list of tasks, returns a map of each task's key to the task.
- */
- private ArrayMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
- ArrayMap<Task.TaskKey, Task> map = new ArrayMap<>(tasks.size());
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- Task task = tasks.get(i);
- map.put(task.key, task);
- }
- return map;
- }
-
- public void dump(String prefix, PrintWriter writer) {
- String innerPrefix = prefix + " ";
-
- writer.print(prefix); writer.print(TAG);
- writer.print(" numStackTasks="); writer.print(mStackTaskList.size());
- writer.println();
- ArrayList<Task> tasks = mStackTaskList.getTasks();
- int taskCount = tasks.size();
- for (int i = 0; i < taskCount; i++) {
- tasks.get(i).dump(innerPrefix, writer);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index 7998ecb4290a..b598ec6fc31f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -22,7 +22,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.ViewOutlineProvider;
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.Utilities;
/* An outline provider that has a clip and outline that can be animated. */
public class AnimateableViewBounds extends ViewOutlineProvider {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
new file mode 100644
index 000000000000..59f28680a6e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/DockState.java
@@ -0,0 +1,351 @@
+/*
+ * 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.recents.views;
+
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
+import android.util.IntProperty;
+import android.view.animation.Interpolator;
+
+import com.android.internal.policy.DockedDividerUtils;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.shared.recents.utilities.Utilities;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+
+/**
+ * The various possible dock states when dragging and dropping a task.
+ */
+public class DockState implements DropTarget {
+
+ public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
+ public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
+
+ // The rotation to apply to the hint text
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HORIZONTAL, VERTICAL})
+ public @interface TextOrientation {}
+ private static final int HORIZONTAL = 0;
+ private static final int VERTICAL = 1;
+
+ private static final int DOCK_AREA_ALPHA = 80;
+ public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
+ null, null, null);
+ public static final DockState LEFT = new DockState(DOCKED_LEFT,
+ DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, VERTICAL,
+ new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
+ new RectF(0, 0, 0.5f, 1));
+ public static final DockState TOP = new DockState(DOCKED_TOP,
+ DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+ new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
+ new RectF(0, 0, 1, 0.5f));
+ public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
+ DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, VERTICAL,
+ new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
+ new RectF(0.5f, 0, 1, 1));
+ public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
+ DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA, 0, HORIZONTAL,
+ new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
+ new RectF(0, 0.5f, 1, 1));
+
+ @Override
+ public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
+ boolean isCurrentTarget) {
+ if (isCurrentTarget) {
+ getMappedRect(expandedTouchDockArea, width, height, mTmpRect);
+ return mTmpRect.contains(x, y);
+ } else {
+ getMappedRect(touchArea, width, height, mTmpRect);
+ updateBoundsWithSystemInsets(mTmpRect, insets);
+ return mTmpRect.contains(x, y);
+ }
+ }
+
+ // Represents the view state of this dock state
+ public static class ViewState {
+ private static final IntProperty<ViewState> HINT_ALPHA =
+ new IntProperty<ViewState>("drawableAlpha") {
+ @Override
+ public void setValue(ViewState object, int alpha) {
+ object.mHintTextAlpha = alpha;
+ object.dockAreaOverlay.invalidateSelf();
+ }
+
+ @Override
+ public Integer get(ViewState object) {
+ return object.mHintTextAlpha;
+ }
+ };
+
+ public final int dockAreaAlpha;
+ public final ColorDrawable dockAreaOverlay;
+ public final int hintTextAlpha;
+ public final int hintTextOrientation;
+
+ private final int mHintTextResId;
+ private String mHintText;
+ private Paint mHintTextPaint;
+ private Point mHintTextBounds = new Point();
+ private int mHintTextAlpha = 255;
+ private AnimatorSet mDockAreaOverlayAnimator;
+ private Rect mTmpRect = new Rect();
+
+ private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
+ int hintTextResId) {
+ dockAreaAlpha = areaAlpha;
+ dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
+ ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
+ dockAreaOverlay.setAlpha(0);
+ hintTextAlpha = hintAlpha;
+ hintTextOrientation = hintOrientation;
+ mHintTextResId = hintTextResId;
+ mHintTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mHintTextPaint.setColor(Color.WHITE);
+ }
+
+ /**
+ * Updates the view state with the given context.
+ */
+ public void update(Context context) {
+ Resources res = context.getResources();
+ mHintText = context.getString(mHintTextResId);
+ mHintTextPaint.setTextSize(res.getDimensionPixelSize(
+ R.dimen.recents_drag_hint_text_size));
+ mHintTextPaint.getTextBounds(mHintText, 0, mHintText.length(), mTmpRect);
+ mHintTextBounds.set((int) mHintTextPaint.measureText(mHintText), mTmpRect.height());
+ }
+
+ /**
+ * Draws the current view state.
+ */
+ public void draw(Canvas canvas) {
+ // Draw the overlay background
+ if (dockAreaOverlay.getAlpha() > 0) {
+ dockAreaOverlay.draw(canvas);
+ }
+
+ // Draw the hint text
+ if (mHintTextAlpha > 0) {
+ Rect bounds = dockAreaOverlay.getBounds();
+ int x = bounds.left + (bounds.width() - mHintTextBounds.x) / 2;
+ int y = bounds.top + (bounds.height() + mHintTextBounds.y) / 2;
+ mHintTextPaint.setAlpha(mHintTextAlpha);
+ if (hintTextOrientation == VERTICAL) {
+ canvas.save();
+ canvas.rotate(-90f, bounds.centerX(), bounds.centerY());
+ }
+ canvas.drawText(mHintText, x, y, mHintTextPaint);
+ if (hintTextOrientation == VERTICAL) {
+ canvas.restore();
+ }
+ }
+ }
+
+ /**
+ * Creates a new bounds and alpha animation.
+ */
+ public void startAnimation(Rect bounds, int areaAlpha, int hintAlpha, int duration,
+ Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
+ if (mDockAreaOverlayAnimator != null) {
+ mDockAreaOverlayAnimator.cancel();
+ }
+
+ ObjectAnimator anim;
+ ArrayList<Animator> animators = new ArrayList<>();
+ if (dockAreaOverlay.getAlpha() != areaAlpha) {
+ if (animateAlpha) {
+ anim = ObjectAnimator.ofInt(dockAreaOverlay,
+ Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha);
+ anim.setDuration(duration);
+ anim.setInterpolator(interpolator);
+ animators.add(anim);
+ } else {
+ dockAreaOverlay.setAlpha(areaAlpha);
+ }
+ }
+ if (mHintTextAlpha != hintAlpha) {
+ if (animateAlpha) {
+ anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
+ hintAlpha);
+ anim.setDuration(150);
+ anim.setInterpolator(hintAlpha > mHintTextAlpha
+ ? Interpolators.ALPHA_IN
+ : Interpolators.ALPHA_OUT);
+ animators.add(anim);
+ } else {
+ mHintTextAlpha = hintAlpha;
+ dockAreaOverlay.invalidateSelf();
+ }
+ }
+ if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
+ if (animateBounds) {
+ PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
+ Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
+ new Rect(dockAreaOverlay.getBounds()), bounds);
+ anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop);
+ anim.setDuration(duration);
+ anim.setInterpolator(interpolator);
+ animators.add(anim);
+ } else {
+ dockAreaOverlay.setBounds(bounds);
+ }
+ }
+ if (!animators.isEmpty()) {
+ mDockAreaOverlayAnimator = new AnimatorSet();
+ mDockAreaOverlayAnimator.playTogether(animators);
+ mDockAreaOverlayAnimator.start();
+ }
+ }
+ }
+
+ public final int dockSide;
+ public final int createMode;
+ public final ViewState viewState;
+ private final RectF touchArea;
+ private final RectF dockArea;
+ private final RectF expandedTouchDockArea;
+ private static final Rect mTmpRect = new Rect();
+
+ /**
+ * @param createMode used to pass to ActivityManager to dock the task
+ * @param touchArea the area in which touch will initiate this dock state
+ * @param dockArea the visible dock area
+ * @param expandedTouchDockArea the area in which touch will continue to dock after entering
+ * the initial touch area. This is also the new dock area to
+ * draw.
+ */
+ DockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha,
+ @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea,
+ RectF expandedTouchDockArea) {
+ this.dockSide = dockSide;
+ this.createMode = createMode;
+ this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation,
+ R.string.recents_drag_hint_message);
+ this.dockArea = dockArea;
+ this.touchArea = touchArea;
+ this.expandedTouchDockArea = expandedTouchDockArea;
+ }
+
+ /**
+ * Updates the dock state with the given context.
+ */
+ public void update(Context context) {
+ viewState.update(context);
+ }
+
+ /**
+ * Returns the docked task bounds with the given {@param width} and {@param height}.
+ */
+ public Rect getPreDockedBounds(int width, int height, Rect insets) {
+ getMappedRect(dockArea, width, height, mTmpRect);
+ return updateBoundsWithSystemInsets(mTmpRect, insets);
+ }
+
+ /**
+ * Returns the expanded docked task bounds with the given {@param width} and
+ * {@param height}.
+ */
+ public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
+ Resources res) {
+ // Calculate the docked task bounds
+ boolean isHorizontalDivision =
+ res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+ int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+ insets, width, height, dividerSize);
+ Rect newWindowBounds = new Rect();
+ DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds,
+ width, height, dividerSize);
+ return newWindowBounds;
+ }
+
+ /**
+ * Returns the task stack bounds with the given {@param width} and
+ * {@param height}.
+ */
+ public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height,
+ int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm,
+ Resources res, Rect windowRectOut) {
+ // Calculate the inverse docked task bounds
+ boolean isHorizontalDivision =
+ res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
+ int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
+ insets, width, height, dividerSize);
+ DockedDividerUtils.calculateBoundsForPosition(position,
+ DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height,
+ dividerSize);
+
+ // Calculate the task stack bounds from the new window bounds
+ Rect taskStackBounds = new Rect();
+ // If the task stack bounds is specifically under the dock area, then ignore the top
+ // inset
+ int top = dockArea.bottom < 1f
+ ? 0
+ : insets.top;
+ // For now, ignore the left insets since we always dock on the left and show Recents
+ // on the right
+ layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, 0, insets.right,
+ taskStackBounds);
+ return taskStackBounds;
+ }
+
+ /**
+ * Returns the expanded bounds in certain dock sides such that the bounds account for the
+ * system insets (namely the vertical nav bar). This call modifies and returns the given
+ * {@param bounds}.
+ */
+ private Rect updateBoundsWithSystemInsets(Rect bounds, Rect insets) {
+ if (dockSide == DOCKED_LEFT) {
+ bounds.right += insets.left;
+ } else if (dockSide == DOCKED_RIGHT) {
+ bounds.left -= insets.right;
+ }
+ return bounds;
+ }
+
+ /**
+ * Returns the mapped rect to the given dimensions.
+ */
+ private void getMappedRect(RectF bounds, int width, int height, Rect out) {
+ out.set((int) (bounds.left * width), (int) (bounds.top * height),
+ (int) (bounds.right * width), (int) (bounds.bottom * height));
+ }
+} \ No newline at end of file
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 baa5e6273e5e..25c2fc97eda4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -30,8 +30,6 @@ import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Bundle;
@@ -58,8 +56,8 @@ import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
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 e1b22b4452fd..5f12a04b5e4d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -53,7 +53,6 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
@@ -74,9 +73,9 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
import com.android.systemui.stackdivider.WindowManagerProxy;
@@ -498,7 +497,7 @@ public class RecentsView extends FrameLayout {
public void onDrawForeground(Canvas canvas) {
super.onDrawForeground(canvas);
- ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+ ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
for (int i = visDockStates.size() - 1; i >= 0; i--) {
visDockStates.get(i).viewState.draw(canvas);
}
@@ -506,7 +505,7 @@ public class RecentsView extends FrameLayout {
@Override
protected boolean verifyDrawable(Drawable who) {
- ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+ ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
for (int i = visDockStates.size() - 1; i >= 0; i--) {
Drawable d = visDockStates.get(i).viewState.dockAreaOverlay;
if (d == who) {
@@ -540,8 +539,8 @@ public class RecentsView extends FrameLayout {
public final void onBusEvent(DragStartEvent event) {
updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(),
- true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
- TaskStack.DockState.NONE.viewState.hintTextAlpha,
+ true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
+ DockState.NONE.viewState.hintTextAlpha,
true /* animateAlpha */, false /* animateBounds */);
// Temporarily hide the stack action button without changing visibility
@@ -555,15 +554,15 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(DragDropTargetChangedEvent event) {
- if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
+ if (event.dropTarget == null || !(event.dropTarget instanceof DockState)) {
updateVisibleDockRegions(
Recents.getConfiguration().getDockStatesForCurrentOrientation(),
- true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
- TaskStack.DockState.NONE.viewState.hintTextAlpha,
+ true /* isDefaultDockState */, DockState.NONE.viewState.dockAreaAlpha,
+ DockState.NONE.viewState.hintTextAlpha,
true /* animateAlpha */, true /* animateBounds */);
} else {
- final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
- updateVisibleDockRegions(new TaskStack.DockState[] {dockState},
+ final DockState dockState = (DockState) event.dropTarget;
+ updateVisibleDockRegions(new DockState[] {dockState},
false /* isDefaultDockState */, -1, -1, true /* animateAlpha */,
true /* animateBounds */);
}
@@ -582,8 +581,8 @@ public class RecentsView extends FrameLayout {
public final void onBusEvent(final DragEndEvent event) {
// Handle the case where we drop onto a dock region
- if (event.dropTarget instanceof TaskStack.DockState) {
- final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+ if (event.dropTarget instanceof DockState) {
+ final DockState dockState = (DockState) event.dropTarget;
// Hide the dock region
updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1,
@@ -812,15 +811,15 @@ public class RecentsView extends FrameLayout {
/**
* Updates the dock region to match the specified dock state.
*/
- private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates,
+ private void updateVisibleDockRegions(DockState[] newDockStates,
boolean isDefaultDockState, int overrideAreaAlpha, int overrideHintAlpha,
boolean animateAlpha, boolean animateBounds) {
- ArraySet<TaskStack.DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
- new ArraySet<TaskStack.DockState>());
- ArrayList<TaskStack.DockState> visDockStates = mTouchHandler.getVisibleDockStates();
+ ArraySet<DockState> newDockStatesSet = Utilities.arrayToSet(newDockStates,
+ new ArraySet<DockState>());
+ ArrayList<DockState> visDockStates = mTouchHandler.getVisibleDockStates();
for (int i = visDockStates.size() - 1; i >= 0; i--) {
- TaskStack.DockState dockState = visDockStates.get(i);
- TaskStack.DockState.ViewState viewState = dockState.viewState;
+ DockState dockState = visDockStates.get(i);
+ DockState.ViewState viewState = dockState.viewState;
if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
// This is no longer visible, so hide it
viewState.startAnimation(null, 0, 0, TaskStackView.SLOW_SYNC_STACK_DURATION,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index b6b24bcd8800..0cfdbdecdf2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.views;
import android.app.ActivityManager;
-import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.view.InputDevice;
@@ -32,7 +31,6 @@ import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.HideIncompatibleAppOverlayEvent;
import com.android.systemui.recents.events.ui.ShowIncompatibleAppOverlayEvent;
@@ -41,8 +39,8 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import java.util.ArrayList;
@@ -72,7 +70,7 @@ public class RecentsViewTouchHandler {
private DropTarget mLastDropTarget;
private DividerSnapAlgorithm mDividerSnapAlgorithm;
private ArrayList<DropTarget> mDropTargets = new ArrayList<>();
- private ArrayList<TaskStack.DockState> mVisibleDockStates = new ArrayList<>();
+ private ArrayList<DockState> mVisibleDockStates = new ArrayList<>();
public RecentsViewTouchHandler(RecentsView rv) {
mRv = rv;
@@ -96,7 +94,7 @@ public class RecentsViewTouchHandler {
/**
* Returns the set of visible dock states for this current drag.
*/
- public ArrayList<TaskStack.DockState> getVisibleDockStates() {
+ public ArrayList<DockState> getVisibleDockStates() {
return mVisibleDockStates;
}
@@ -148,9 +146,9 @@ public class RecentsViewTouchHandler {
EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
} else {
// Add the dock state drop targets (these take priority)
- TaskStack.DockState[] dockStates = Recents.getConfiguration()
+ DockState[] dockStates = Recents.getConfiguration()
.getDockStatesForCurrentOrientation();
- for (TaskStack.DockState dockState : dockStates) {
+ for (DockState dockState : dockStates) {
registerDropTargetForCurrentDrag(dockState);
dockState.update(mRv.getContext());
mVisibleDockStates.add(dockState);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 8f784b832e4c..7827c590ed81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -30,7 +30,7 @@ import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
/** Manages the scrims for the various system bars. */
public class SystemBarScrimViews {
@@ -159,7 +159,7 @@ public class SystemBarScrimViews {
public final void onBusEvent(final DragEndEvent event) {
// Hide the nav bar scrims once we drop to a dock region
- if (event.dropTarget instanceof TaskStack.DockState) {
+ if (event.dropTarget instanceof DockState) {
animateScrimToCurrentNavBarState(false /* hasStackTasks */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index f47c1d2877bf..26db26fa3c36 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -18,13 +18,11 @@ package com.android.systemui.recents.views;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
-import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -37,9 +35,10 @@ import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 5ba5f44a4433..acb058cee716 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -24,7 +24,6 @@ import android.graphics.Path;
import android.graphics.Rect;
import android.util.ArraySet;
import android.util.Log;
-import android.util.MutableFloat;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.ViewDebug;
@@ -36,9 +35,9 @@ import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.FreePathInterpolator;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
@@ -505,9 +504,7 @@ public class TaskStackLayoutAlgorithm {
boolean scrollToFront = launchState.launchedFromHome || launchState.launchedFromPipApp
|| launchState.launchedWithNextPipApp || launchState.launchedViaDockGesture;
- if (launchState.launchedFromBlacklistedApp) {
- mInitialScrollP = mMaxScrollP;
- } else if (launchState.launchedWithAltTab) {
+ if (launchState.launchedWithAltTab) {
mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
} else if (Recents.getConfiguration().isLowRamDevice) {
mInitialScrollP = mTaskStackLowRamLayoutAlgorithm.getInitialScrollP(mNumStackTasks,
@@ -535,7 +532,6 @@ public class TaskStackLayoutAlgorithm {
boolean scrollToFront = launchState.launchedFromHome ||
launchState.launchedFromPipApp ||
launchState.launchedWithNextPipApp ||
- launchState.launchedFromBlacklistedApp ||
launchState.launchedViaDockGesture;
if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
if (ignoreScrollToFront || (!launchState.launchedWithAltTab && !scrollToFront)) {
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 cda5fb825d5f..428113a2a065 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -87,9 +87,10 @@ import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.grid.GridTaskView;
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
@@ -470,7 +471,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
// We can reuse the task transforms where possible to reduce object allocation
- Utilities.matchTaskListSize(tasks, taskTransforms);
+ matchTaskListSize(tasks, taskTransforms);
// Update the stack transforms
TaskViewTransform frontTransform = null;
@@ -700,7 +701,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
*/
public void getCurrentTaskTransforms(ArrayList<Task> tasks,
ArrayList<TaskViewTransform> transformsOut) {
- Utilities.matchTaskListSize(tasks, transformsOut);
+ matchTaskListSize(tasks, transformsOut);
int focusState = mLayoutAlgorithm.getFocusState();
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
@@ -723,7 +724,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
*/
public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks,
boolean ignoreTaskOverrides, ArrayList<TaskViewTransform> transformsOut) {
- Utilities.matchTaskListSize(tasks, transformsOut);
+ matchTaskListSize(tasks, transformsOut);
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
TaskViewTransform transform = transformsOut.get(i);
@@ -1901,10 +1902,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
AnimationProps animation = new AnimationProps(SLOW_SYNC_STACK_DURATION,
Interpolators.FAST_OUT_SLOW_IN);
boolean ignoreTaskOverrides = false;
- if (event.dropTarget instanceof TaskStack.DockState) {
+ if (event.dropTarget instanceof DockState) {
// Calculate the new task stack bounds that matches the window size that Recents will
// have after the drop
- final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+ final DockState dockState = (DockState) event.dropTarget;
Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
// When docked, the nav bar insets are consumed and the activity is measured without
// insets. However, the window bounds include the insets, so we need to subtract them
@@ -1931,7 +1932,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
public final void onBusEvent(final DragEndEvent event) {
// We don't handle drops on the dock regions
- if (event.dropTarget instanceof TaskStack.DockState) {
+ if (event.dropTarget instanceof DockState) {
// However, we do need to reset the overrides, since the last state of this task stack
// view layout was ignoring task overrides (see DragDropTargetChangedEvent handler)
mLayoutAlgorithm.clearUnfocusedTaskOverrides();
@@ -2199,6 +2200,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
}
+ /**
+ * Updates {@param transforms} to be the same size as {@param tasks}.
+ */
+ private void matchTaskListSize(List<Task> tasks, List<TaskViewTransform> transforms) {
+ // We can reuse the task transforms where possible to reduce object allocation
+ int taskTransformCount = transforms.size();
+ int taskCount = tasks.size();
+ if (taskTransformCount < taskCount) {
+ // If there are less transforms than tasks, then add as many transforms as necessary
+ for (int i = taskTransformCount; i < taskCount; i++) {
+ transforms.add(new TaskViewTransform());
+ }
+ } else if (taskTransformCount > taskCount) {
+ // If there are more transforms than tasks, then just subset the transform list
+ transforms.subList(taskCount, taskTransformCount).clear();
+ }
+ }
+
public void dump(String prefix, PrintWriter writer) {
String innerPrefix = prefix + " ";
String id = Integer.toHexString(System.identityHashCode(this));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 0b20b105617d..6b23977410c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -24,7 +24,6 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.util.FloatProperty;
import android.util.Log;
-import android.util.MutableFloat;
import android.util.Property;
import android.view.ViewConfiguration;
import android.view.ViewDebug;
@@ -33,7 +32,8 @@ import android.widget.OverScroller;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.recents.views.lowram.TaskStackLowRamLayoutAlgorithm;
import com.android.systemui.statusbar.FlingAnimationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 1abaced83969..b9ca2483f3be 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -21,7 +21,6 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Path;
-import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.MutableBoolean;
import android.view.InputDevice;
@@ -45,9 +44,9 @@ import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.misc.FreePathInterpolator;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.statusbar.FlingAnimationUtils;
import java.util.ArrayList;
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 a75034a123ee..b44084743896 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -51,10 +51,10 @@ import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -709,7 +709,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
/**** Events ****/
public final void onBusEvent(DragEndEvent event) {
- if (!(event.dropTarget instanceof TaskStack.DockState)) {
+ if (!(event.dropTarget instanceof DockState)) {
event.addPostAnimationCallback(() -> {
// Reset the clip state for the drag view after the end animation completes
setClipViewInStack(true);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
index 0c6b6b842655..0fc507b92bf3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -28,11 +28,10 @@ import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.TaskStack;
public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
private static final String TAG = "TaskViewAccessibilityDelegate";
@@ -61,14 +60,14 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
super.onInitializeAccessibilityNodeInfo(host, info);
if (ActivityManager.supportsSplitScreenMultiWindow(mTaskView.getContext())
&& !Recents.getSystemServices().hasDockedTask()) {
- TaskStack.DockState[] dockStates = Recents.getConfiguration()
+ DockState[] dockStates = Recents.getConfiguration()
.getDockStatesForCurrentOrientation();
- for (TaskStack.DockState dockState: dockStates) {
- if (dockState == TaskStack.DockState.TOP) {
+ for (DockState dockState: dockStates) {
+ if (dockState == DockState.TOP) {
info.addAction(mActions.get(SPLIT_TASK_TOP));
- } else if (dockState == TaskStack.DockState.LEFT) {
+ } else if (dockState == DockState.LEFT) {
info.addAction(mActions.get(SPLIT_TASK_LEFT));
- } else if (dockState == TaskStack.DockState.RIGHT) {
+ } else if (dockState == DockState.RIGHT) {
info.addAction(mActions.get(SPLIT_TASK_RIGHT));
}
}
@@ -78,11 +77,11 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == SPLIT_TASK_TOP) {
- simulateDragIntoMultiwindow(TaskStack.DockState.TOP);
+ simulateDragIntoMultiwindow(DockState.TOP);
} else if (action == SPLIT_TASK_LEFT) {
- simulateDragIntoMultiwindow(TaskStack.DockState.LEFT);
+ simulateDragIntoMultiwindow(DockState.LEFT);
} else if (action == SPLIT_TASK_RIGHT) {
- simulateDragIntoMultiwindow(TaskStack.DockState.RIGHT);
+ simulateDragIntoMultiwindow(DockState.RIGHT);
} else {
return super.performAccessibilityAction(host, action, args);
}
@@ -90,8 +89,7 @@ public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
}
/** Simulate a user drag event to split the screen to the respected side */
- private void simulateDragIntoMultiwindow(TaskStack.DockState dockState) {
- int orientation = Utilities.getAppConfiguration(mTaskView.getContext()).orientation;
+ private void simulateDragIntoMultiwindow(DockState dockState) {
EventBus.getDefault().send(new DragStartEvent(mTaskView.getTask(), mTaskView,
new Point(0,0), false /* isUserTouchInitiated */));
EventBus.getDefault().send(new DragEndEvent(mTaskView.getTask(), mTaskView, dockState));
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 1420a0125f20..0272a9038ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -17,7 +17,6 @@
package com.android.systemui.recents.views;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.animation.Animator;
@@ -32,7 +31,6 @@ import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
@@ -58,8 +56,10 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
/* The task bar view */
public class TaskViewHeader extends FrameLayout
@@ -170,6 +170,8 @@ public class TaskViewHeader extends FrameLayout
int mTaskBarViewLightTextColor;
int mTaskBarViewDarkTextColor;
int mDisabledTaskBarBackgroundColor;
+ String mDismissDescFormat;
+ String mAppInfoDescFormat;
int mTaskWindowingMode = WINDOWING_MODE_UNDEFINED;
// Header background
@@ -218,6 +220,9 @@ public class TaskViewHeader extends FrameLayout
mDarkInfoIcon = context.getDrawable(R.drawable.recents_info_dark);
mDisabledTaskBarBackgroundColor =
context.getColor(R.color.recents_task_bar_disabled_background_color);
+ mDismissDescFormat = mContext.getString(
+ R.string.accessibility_recents_item_will_be_dismissed);
+ mAppInfoDescFormat = mContext.getString(R.string.accessibility_recents_item_open_app_info);
// Configure the background and dim
mBackground = new HighlightColorDrawable();
@@ -455,14 +460,14 @@ public class TaskViewHeader extends FrameLayout
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
- mDismissButton.setContentDescription(t.dismissDescription);
+ mDismissButton.setContentDescription(String.format(mDismissDescFormat, t.titleDescription));
mDismissButton.setOnClickListener(this);
mDismissButton.setClickable(false);
((RippleDrawable) mDismissButton.getBackground()).setForceSoftware(true);
// In accessibility, a single click on the focused app info button will show it
if (touchExplorationEnabled) {
- mIconView.setContentDescription(t.appInfoDescription);
+ mIconView.setContentDescription(String.format(mAppInfoDescFormat, t.titleDescription));
mIconView.setOnClickListener(this);
mIconView.setClickable(true);
}
@@ -599,7 +604,7 @@ public class TaskViewHeader extends FrameLayout
SystemServicesProxy ssp = Recents.getSystemServices();
ComponentName cn = mTask.key.getComponent();
int userId = mTask.key.userId;
- ActivityInfo activityInfo = ssp.getActivityInfo(cn, userId);
+ ActivityInfo activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, userId);
if (activityInfo == null) {
return;
}
@@ -619,11 +624,12 @@ public class TaskViewHeader extends FrameLayout
}
// Update the overlay contents for the current app
- mAppTitleView.setText(ssp.getBadgedApplicationLabel(activityInfo.applicationInfo, userId));
+ mAppTitleView.setText(ActivityManagerWrapper.getInstance().getBadgedApplicationLabel(
+ activityInfo.applicationInfo, userId));
mAppTitleView.setTextColor(mTask.useLightOnPrimaryColor ?
mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor);
- mAppIconView.setImageDrawable(ssp.getBadgedApplicationIcon(activityInfo.applicationInfo,
- userId));
+ mAppIconView.setImageDrawable(ActivityManagerWrapper.getInstance().getBadgedApplicationIcon(
+ activityInfo.applicationInfo, userId));
mAppInfoView.setImageDrawable(mTask.useLightOnPrimaryColor
? mLightInfoIcon
: mDarkInfoIcon);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index d0ebc8dfc21f..4152b05a960e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -37,9 +37,9 @@ import android.view.ViewDebug;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index c9dbe2ad2c4a..9b717e0e5e2f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -21,11 +21,11 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.graphics.Rect;
import android.graphics.RectF;
-import android.util.IntProperty;
import android.util.Property;
import android.view.View;
-import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.shared.recents.utilities.AnimationProps;
+import com.android.systemui.shared.recents.utilities.Utilities;
import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index c5132024d505..ccda4b5aaf1f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -25,10 +25,9 @@ import android.graphics.Rect;
import android.view.WindowManager;
import com.android.systemui.R;
-import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskViewTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
index 86ed583b07aa..95f1d5837e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -23,7 +23,7 @@ import android.view.View;
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
import com.android.systemui.R;
-import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.TaskStackView;
public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
index 17e6b9e3c195..49cac269f51d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/lowram/TaskStackLowRamLayoutAlgorithm.java
@@ -23,8 +23,8 @@ import android.view.ViewConfiguration;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivityLaunchState;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
+import com.android.systemui.shared.recents.utilities.Utilities;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskViewTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index 9211e3f6e86c..195f4d3f480d 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -20,37 +20,24 @@ import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIG
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.os.UserHandle.USER_CURRENT;
-import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.ActivityManager;
-import android.app.IActivityManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.settingslib.accessibility.AccessibilityUtils;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.stackdivider.DividerView;
-import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import java.util.List;
-import java.util.Set;
/**
* Dispatches shortcut to System UI components
@@ -62,7 +49,6 @@ public class ShortcutKeyDispatcher extends SystemUI
private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
- private IActivityManager mActivityManager = ActivityManager.getService();
protected final long META_MASK = ((long) KeyEvent.META_META_ON) << Integer.SIZE;
protected final long ALT_MASK = ((long) KeyEvent.META_ALT_ON) << Integer.SIZE;
@@ -109,7 +95,7 @@ public class ShortcutKeyDispatcher extends SystemUI
? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT
: DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
List<ActivityManager.RecentTaskInfo> taskList =
- SystemServicesProxy.getInstance(mContext).getRecentTasks(1, USER_CURRENT);
+ ActivityManagerWrapper.getInstance().getRecentTasks(1, USER_CURRENT);
recents.showRecentApps(
false /* triggeredFromAltTab */,
false /* fromHome */);
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 27c16d53ce78..b695919dc2b5 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,6 +38,7 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
LOCAL_STATIC_ANDROID_LIBRARIES := \
SystemUIPluginLib \
+ SystemUISharedLib \
android-support-v4 \
android-support-v7-recyclerview \
android-support-v7-preference \
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 47d21f8026e1..f6fcaae4f4c3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -19,6 +19,9 @@ package com.android.server.accessibility;
import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
+import android.util.DebugUtils;
+import android.util.ExceptionUtils;
+import android.util.Log;
import android.util.Pools.SimplePool;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -31,6 +34,7 @@ import android.view.MotionEvent;
import android.view.WindowManagerPolicy;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.util.BitUtils;
import com.android.server.LocalServices;
/**
@@ -188,6 +192,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
if (mEventHandler == null) {
+ if (DEBUG) Slog.d(TAG, "mEventHandler == null for event " + event);
super.onInputEvent(event, policyFlags);
return;
}
@@ -339,6 +344,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
MotionEvent transformedEvent = MotionEvent.obtain(event);
mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
transformedEvent.recycle();
+ } else {
+ if (DEBUG) Slog.d(TAG, "mEventHandler == null for " + event);
}
}
@@ -376,6 +383,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
void setUserAndEnabledFeatures(int userId, int enabledFeatures) {
+ if (DEBUG) {
+ Slog.i(TAG, "setUserAndEnabledFeatures(userId = " + userId + ", enabledFeatures = 0x"
+ + Integer.toHexString(enabledFeatures) + ")");
+ }
if (mEnabledFeatures == enabledFeatures && mUserId == userId) {
return;
}
@@ -402,6 +413,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
}
private void enableFeatures() {
+ if (DEBUG) Slog.i(TAG, "enableFeatures()");
+
resetStreamState();
if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
@@ -448,7 +461,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
*/
private void addFirstEventHandler(EventStreamTransformation handler) {
if (mEventHandler != null) {
- handler.setNext(mEventHandler);
+ handler.setNext(mEventHandler);
} else {
handler.setNext(this);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index 98b8e6b723ac..a10b7a20d741 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -56,6 +56,7 @@ import java.util.Locale;
* constraints.
*/
class MagnificationController implements Handler.Callback {
+ private static final boolean DEBUG = false;
private static final String LOG_TAG = "MagnificationController";
public static final float MIN_SCALE = 1.0f;
@@ -509,6 +510,12 @@ class MagnificationController implements Handler.Callback {
private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY,
boolean animate, int id) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "setScaleAndCenterLocked(scale = " + scale + ", centerX = " + centerX
+ + ", centerY = " + centerY + ", animate = " + animate + ", id = " + id
+ + ")");
+ }
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
sendSpecToAnimation(mCurrentMagnificationSpec, animate);
if (isMagnifying() && (id != INVALID_ID)) {
@@ -535,7 +542,9 @@ class MagnificationController implements Handler.Callback {
final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
- updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY);
+ if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
+ onMagnificationChangedLocked();
+ }
if (id != INVALID_ID) {
mIdOfLastServiceToMagnify = id;
}
@@ -633,6 +642,11 @@ class MagnificationController implements Handler.Callback {
}
private boolean updateCurrentSpecWithOffsetsLocked(float nonNormOffsetX, float nonNormOffsetY) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "updateCurrentSpecWithOffsetsLocked(nonNormOffsetX = " + nonNormOffsetX
+ + ", nonNormOffsetY = " + nonNormOffsetY + ")");
+ }
boolean changed = false;
final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
if (Float.compare(mCurrentMagnificationSpec.offsetX, offsetX) != 0) {
@@ -750,6 +764,9 @@ class MagnificationController implements Handler.Callback {
}
private void sendSpecToAnimation(MagnificationSpec spec, boolean animate) {
+ if (DEBUG) {
+ Slog.i(LOG_TAG, "sendSpecToAnimation(spec = " + spec + ", animate = " + animate + ")");
+ }
if (Thread.currentThread().getId() == mMainThreadId) {
mSpecAnimationBridge.updateSentSpecMainThread(spec, animate);
} else {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 969f5b014ac8..9b2b4eb7ebee 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -101,21 +101,12 @@ import com.android.internal.annotations.VisibleForTesting;
*/
@SuppressWarnings("WeakerAccess")
class MagnificationGestureHandler extends BaseEventStreamTransformation {
- private static final String LOG_TAG = "MagnificationEventHandler";
+ private static final String LOG_TAG = "MagnificationGestureHandler";
private static final boolean DEBUG_ALL = false;
private static final boolean DEBUG_STATE_TRANSITIONS = false || DEBUG_ALL;
private static final boolean DEBUG_DETECTING = false || DEBUG_ALL;
- private static final boolean DEBUG_PANNING = false || DEBUG_ALL;
-
- /** @see DelegatingState */
- @VisibleForTesting static final int STATE_DELEGATING = 1;
- /** @see DetectingState */
- @VisibleForTesting static final int STATE_DETECTING = 2;
- /** @see ViewportDraggingState */
- @VisibleForTesting static final int STATE_VIEWPORT_DRAGGING = 3;
- /** @see PanningScalingState */
- @VisibleForTesting static final int STATE_PANNING_SCALING = 4;
+ private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
private static final float MIN_SCALE = 2.0f;
private static final float MAX_SCALE = 5.0f;
@@ -184,6 +175,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (DEBUG_ALL) Slog.i(LOG_TAG, "onMotionEvent(" + event + ")");
+
if ((!mDetectTripleTap && !mDetectShortcutTrigger)
|| !event.isFromSource(SOURCE_TOUCHSCREEN)) {
dispatchTransformedEvent(event, rawEvent, policyFlags);
@@ -213,6 +206,11 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
@Override
public void onDestroy() {
+ if (DEBUG_STATE_TRANSITIONS) {
+ Slog.i(LOG_TAG, "onDestroy(); delayed = "
+ + MotionEventInfo.toString(mDetectingState.mDelayedEventQueue));
+ }
+
if (mScreenStateReceiver != null) {
mScreenStateReceiver.unregister();
}
@@ -239,6 +237,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
+ if (DEBUG_ALL) Slog.i(LOG_TAG, "dispatchTransformedEvent(event = " + event + ")");
+
// If the touchscreen event is within the magnified portion of the screen we have
// to change its location to be where the user thinks he is poking the
// UI which may have been magnified and panned.
@@ -332,8 +332,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
* magnification level.
* This makes it the preferred mode for one-off adjustments, due to its precision and ease of
* triggering.
- *
- * @see #STATE_PANNING_SCALING
*/
final class PanningScalingState extends SimpleOnGestureListener
implements OnScaleGestureListener, State {
@@ -385,7 +383,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
if (mCurrentState != mPanningScalingState) {
return true;
}
- if (DEBUG_PANNING) {
+ if (DEBUG_PANNING_SCALING) {
Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
+ " scrollY: " + distanceY);
}
@@ -402,12 +400,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
return false;
}
final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
- if (abs(deltaScale) > mScalingThreshold) {
- mScaling = true;
- return true;
- } else {
- return false;
- }
+ mScaling = abs(deltaScale) > mScalingThreshold;
+ return mScaling;
}
final float initialScale = mMagnificationController.getScale();
@@ -431,6 +425,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
final float pivotX = detector.getFocusX();
final float pivotY = detector.getFocusY();
+ if (DEBUG_PANNING_SCALING) Slog.i(LOG_TAG, "Scaled content to: " + scale + "x");
mMagnificationController.setScale(scale, pivotX, pivotY, false,
AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
return /* handled: */ true;
@@ -469,8 +464,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
* Unlike when {@link PanningScalingState panning}, the viewport moves in the opposite direction
* of the finger, and any part of the screen is reachable without lifting the finger.
* This makes it the preferable mode for tasks like reading text spanning full screen width.
- *
- * @see #STATE_VIEWPORT_DRAGGING
*/
final class ViewportDraggingState implements State {
@@ -534,7 +527,7 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
final class DelegatingState implements State {
/**
- * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link #STATE_DELEGATING}
+ * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link DelegatingState}
*/
public long mLastDelegatedDownEventTime;
@@ -563,8 +556,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
/**
* This class handles motion events when the event dispatch has not yet
* determined what the user is doing. It watches for various tap events.
- *
- * @see #STATE_DETECTING
*/
final class DetectingState implements State, Handler.Callback {
@@ -737,14 +728,14 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP);
}
- /** -> {@link #STATE_DELEGATING} */
+ /** -> {@link DelegatingState} */
public void afterMultiTapTimeoutTransitionToDelegatingState() {
mHandler.sendEmptyMessageDelayed(
MESSAGE_TRANSITION_TO_DELEGATING_STATE,
mMultiTapMaxDelay);
}
- /** -> {@link #STATE_VIEWPORT_DRAGGING} */
+ /** -> {@link ViewportDraggingState} */
public void afterLongTapTimeoutTransitionToDraggingState(MotionEvent event) {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
@@ -865,6 +856,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
}
private void zoomOn(float centerX, float centerY) {
+ if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOn(" + centerX + ", " + centerY + ")");
+
final float scale = MathUtils.constrain(
mMagnificationController.getPersistedScale(),
MIN_SCALE, MAX_SCALE);
@@ -875,6 +868,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
}
private void zoomOff() {
+ if (DEBUG_DETECTING) Slog.i(LOG_TAG, "zoomOff()");
+
mMagnificationController.reset(/* animate */ true);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
index 7925510c6178..b6b781290c65 100644
--- a/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
+++ b/services/accessibility/java/com/android/server/accessibility/MotionEventInjector.java
@@ -36,6 +36,7 @@ import android.view.WindowManagerPolicy;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -241,17 +242,24 @@ public class MotionEventInjector extends BaseEventStreamTransformation implement
int continuedPointerId = mStrokeIdToPointerId
.get(touchPoint.mContinuedStrokeId, -1);
if (continuedPointerId == -1) {
+ Slog.w(LOG_TAG, "Can't continue gesture due to unknown continued stroke id in "
+ + touchPoint);
return false;
}
mStrokeIdToPointerId.put(touchPoint.mStrokeId, continuedPointerId);
int lastPointIndex = findPointByStrokeId(
mLastTouchPoints, mNumLastTouchPoints, touchPoint.mContinuedStrokeId);
if (lastPointIndex < 0) {
+ Slog.w(LOG_TAG, "Can't continue gesture due continued gesture id of "
+ + touchPoint + " not matching any previous strokes in "
+ + Arrays.asList(mLastTouchPoints));
return false;
}
if (mLastTouchPoints[lastPointIndex].mIsEndOfPath
|| (mLastTouchPoints[lastPointIndex].mX != touchPoint.mX)
|| (mLastTouchPoints[lastPointIndex].mY != touchPoint.mY)) {
+ Slog.w(LOG_TAG, "Can't continue gesture due to points mismatch between "
+ + mLastTouchPoints[lastPointIndex] + " and " + touchPoint);
return false;
}
// Update the last touch point to match the continuation, so the gestures will
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 6d9c977fe4c7..47be0a704d00 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -24,6 +24,7 @@ import android.os.PowerManager;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.server.am.BatteryStatsService;
@@ -35,7 +36,10 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
import android.hardware.health.V2_0.HealthInfo;
+import android.hardware.health.V2_0.IHealth;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryProperties;
@@ -63,6 +67,9 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
/**
* <p>BatteryService monitors the charging status, and charge level of the device
@@ -1020,4 +1027,121 @@ public final class BatteryService extends SystemService {
}
}
}
+
+ /**
+ * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
+ * necessary.
+ *
+ * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
+ * the internal service is refreshed.
+ * On death of an existing IHealth service, the internal service is NOT cleared to avoid
+ * race condition between death notification and new service notification. Hence,
+ * a caller must check for transaction errors when calling into the service.
+ *
+ * @hide Should only be used internally.
+ */
+ @VisibleForTesting
+ static final class HealthServiceWrapper {
+ private static final String TAG = "HealthServiceWrapper";
+ public static final String INSTANCE_HEALTHD = "backup";
+ public static final String INSTANCE_VENDOR = "default";
+ // All interesting instances, sorted by priority high -> low.
+ private static final List<String> sAllInstances =
+ Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
+
+ private final IServiceNotification mNotification = new Notification();
+ private Callback mCallback;
+ private IHealthSupplier mHealthSupplier;
+
+ /**
+ * init should be called after constructor. For testing purposes, init is not called by
+ * constructor.
+ */
+ HealthServiceWrapper() {
+ }
+
+ /**
+ * Start monitoring registration of new IHealth services. Only instances that are in
+ * {@code sAllInstances} and in device / framework manifest are used. This function should
+ * only be called once.
+ * @throws RemoteException transaction error when talking to IServiceManager
+ * @throws NoSuchElementException if one of the following cases:
+ * - No service manager;
+ * - none of {@code sAllInstances} are in manifests (i.e. not
+ * available on this device), or none of these instances are available to current
+ * process.
+ * @throws NullPointerException when callback is null or supplier is null
+ */
+ void init(Callback callback,
+ IServiceManagerSupplier managerSupplier,
+ IHealthSupplier healthSupplier)
+ throws RemoteException, NoSuchElementException, NullPointerException {
+ if (callback == null || managerSupplier == null || healthSupplier == null)
+ throw new NullPointerException();
+
+ mCallback = callback;
+ mHealthSupplier = healthSupplier;
+
+ IServiceManager manager = managerSupplier.get();
+ for (String name : sAllInstances) {
+ if (manager.getTransport(IHealth.kInterfaceName, name) ==
+ IServiceManager.Transport.EMPTY) {
+ continue;
+ }
+
+ manager.registerForNotifications(IHealth.kInterfaceName, name, mNotification);
+ Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + name);
+ return;
+ }
+
+ throw new NoSuchElementException(String.format(
+ "No IHealth service instance among %s is available. Perhaps no permission?",
+ sAllInstances.toString()));
+ }
+
+ interface Callback {
+ /**
+ * This function is invoked asynchronously when a new and related IServiceNotification
+ * is received.
+ * @param service the recently retrieved service from IServiceManager.
+ * Can be a dead service before service notification of a new service is delivered.
+ * Implementation must handle cases for {@link RemoteException}s when calling
+ * into service.
+ * @param instance instance name.
+ */
+ void onRegistration(IHealth service, String instance);
+ }
+
+ /**
+ * Supplier of services.
+ * Must not return null; throw {@link NoSuchElementException} if a service is not available.
+ */
+ interface IServiceManagerSupplier {
+ IServiceManager get() throws NoSuchElementException, RemoteException;
+ }
+ /**
+ * Supplier of services.
+ * Must not return null; throw {@link NoSuchElementException} if a service is not available.
+ */
+ interface IHealthSupplier {
+ IHealth get(String instanceName) throws NoSuchElementException, RemoteException;
+ }
+
+ private class Notification extends IServiceNotification.Stub {
+ @Override
+ public final void onRegistration(String interfaceName, String instanceName,
+ boolean preexisting) {
+ if (!IHealth.kInterfaceName.equals(interfaceName)) return;
+ if (!sAllInstances.contains(instanceName)) return;
+ try {
+ IHealth service = mHealthSupplier.get(instanceName);
+ Slog.i(TAG, "health: new instance registered " + instanceName);
+ mCallback.onRegistration(service, instanceName);
+ } catch (NoSuchElementException | RemoteException ex) {
+ Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " +
+ ex.getMessage() + ". Perhaps no permission?");
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5f377f7aa7a6..f17c9ac3ecf9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1710,7 +1710,6 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70;
- static final int TOP_APP_KILLED_BY_LMK_MSG = 73;
static final int NOTIFY_VR_KEYGUARD_MSG = 74;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -1936,17 +1935,6 @@ public class ActivityManagerService extends IActivityManager.Stub
dispatchProcessDied(pid, uid);
break;
}
- case TOP_APP_KILLED_BY_LMK_MSG: {
- final String appName = (String) msg.obj;
- final AlertDialog d = new BaseErrorDialog(mUiContext);
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
- d.setTitle(mUiContext.getText(R.string.top_app_killed_title));
- d.setMessage(mUiContext.getString(R.string.top_app_killed_message, appName));
- d.setButton(DialogInterface.BUTTON_POSITIVE, mUiContext.getText(R.string.close),
- obtainMessage(DISMISS_DIALOG_UI_MSG, d));
- d.show();
- break;
- }
case DISPATCH_UIDS_CHANGED_UI_MSG: {
dispatchUidsChanged();
} break;
@@ -5424,7 +5412,6 @@ public class ActivityManagerService extends IActivityManager.Stub
boolean doLowMem = app.instr == null;
boolean doOomAdj = doLowMem;
if (!app.killedByAm) {
- maybeNotifyTopAppKilledLocked(app);
Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+ ProcessList.makeOomAdjString(app.setAdj)
+ ProcessList.makeProcStateString(app.setProcState));
@@ -5458,25 +5445,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- /** Show system error dialog when a top app is killed by LMK */
- void maybeNotifyTopAppKilledLocked(ProcessRecord app) {
- if (!shouldNotifyTopAppKilledLocked(app)) {
- return;
- }
-
- Message msg = mHandler.obtainMessage(TOP_APP_KILLED_BY_LMK_MSG);
- msg.obj = mContext.getPackageManager().getApplicationLabel(app.info);
- mUiHandler.sendMessage(msg);
- }
-
- /** Only show notification when the top app is killed on low ram devices */
- private boolean shouldNotifyTopAppKilledLocked(ProcessRecord app) {
- final ActivityRecord TOP_ACT = resumedAppLocked();
- final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
- return app == TOP_APP &&
- ActivityManager.isLowRamDeviceStatic();
- }
-
/**
* If a stack trace dump file is configured, dump process stack traces.
* @param clearTraces causes the dump file to be erased prior to the new
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 40e568c27900..2c72a4db635a 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -423,9 +423,13 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
if (iconFilename != null || taskDescription.getLabel() != null ||
taskDescription.getPrimaryColor() != 0) {
pw.print(prefix); pw.print("taskDescription:");
- pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
pw.print(" label=\""); pw.print(taskDescription.getLabel());
pw.print("\"");
+ pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null
+ ? taskDescription.getInMemoryIcon().getByteCount() + " bytes"
+ : "null");
+ pw.print(" iconResource="); pw.print(taskDescription.getIconResource());
+ pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
pw.print(" primaryColor=");
pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
pw.print(prefix + " backgroundColor=");
@@ -435,9 +439,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
pw.print(prefix + " navigationBarColor=");
pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
}
- if (iconFilename == null && taskDescription.getIcon() != null) {
- pw.print(prefix); pw.println("taskDescription contains Bitmap");
- }
}
if (results != null) {
pw.print(prefix); pw.print("results="); pw.println(results);
@@ -2746,6 +2747,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void setShowWhenLocked(boolean showWhenLocked) {
mShowWhenLocked = showWhenLocked;
+ mStackSupervisor.ensureActivitiesVisibleLocked(null, 0 /* configChanges */,
+ false /* preserveWindows */);
}
/**
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 0bc30cf4110b..a1b45a1e1757 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1559,6 +1559,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
// values in the TaskRecord.
String label = null;
String iconFilename = null;
+ int iconResource = -1;
int colorPrimary = 0;
int colorBackground = 0;
int statusBarColor = 0;
@@ -1570,6 +1571,9 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
if (label == null) {
label = r.taskDescription.getLabel();
}
+ if (iconResource == -1) {
+ iconResource = r.taskDescription.getIconResource();
+ }
if (iconFilename == null) {
iconFilename = r.taskDescription.getIconFilename();
}
@@ -1584,8 +1588,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
topActivity = false;
}
- lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary,
- colorBackground, statusBarColor, navigationBarColor);
+ lastTaskDescription = new TaskDescription(label, null, iconResource, iconFilename,
+ colorPrimary, colorBackground, statusBarColor, navigationBarColor);
if (mWindowContainerController != null) {
mWindowContainerController.setTaskDescription(lastTaskDescription);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5a295942a84f..4aa8adb9dc78 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -67,6 +67,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
@@ -79,6 +80,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.TimingsTraceLog;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -232,6 +234,7 @@ class UserController implements Handler.Callback {
mUiHandler = mInjector.getUiHandler(this);
// User 0 is the first and only user that runs at boot.
final UserState uss = new UserState(UserHandle.SYSTEM);
+ uss.mUnlockProgress.addListener(new UserProgressListener());
mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
mUserLru.add(UserHandle.USER_SYSTEM);
mLockPatternUtils = mInjector.getLockPatternUtils();
@@ -903,6 +906,7 @@ class UserController implements Handler.Callback {
uss = mStartedUsers.get(userId);
if (uss == null) {
uss = new UserState(UserHandle.of(userId));
+ uss.mUnlockProgress.addListener(new UserProgressListener());
mStartedUsers.put(userId, uss);
updateStartedUserArrayLU();
needStart = true;
@@ -1854,6 +1858,33 @@ class UserController implements Handler.Callback {
return false;
}
+ private static class UserProgressListener extends IProgressListener.Stub {
+ private volatile long mUnlockStarted;
+ @Override
+ public void onStarted(int id, Bundle extras) throws RemoteException {
+ Slog.d(TAG, "Started unlocking user " + id);
+ mUnlockStarted = SystemClock.uptimeMillis();
+ }
+
+ @Override
+ public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
+ Slog.d(TAG, "Unlocking user " + id + " progress " + progress);
+ }
+
+ @Override
+ public void onFinished(int id, Bundle extras) throws RemoteException {
+ long unlockTime = SystemClock.uptimeMillis() - mUnlockStarted;
+
+ // Report system user unlock time to perf dashboard
+ if (id == UserHandle.USER_SYSTEM) {
+ new TimingsTraceLog("SystemServerTiming", Trace.TRACE_TAG_SYSTEM_SERVER)
+ .logDuration("SystemUserUnlock", unlockTime);
+ } else {
+ Slog.d(TAG, "Unlocking user " + id + " took " + unlockTime + " ms");
+ }
+ }
+ };
+
@VisibleForTesting
static class Injector {
private final ActivityManagerService mService;
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index e6228d46e15c..0c9d70a95ab9 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -435,11 +435,12 @@ public class ClipboardService extends SystemService {
}
private boolean isDeviceLocked() {
+ int callingUserId = UserHandle.getCallingUserId();
final long token = Binder.clearCallingIdentity();
try {
final KeyguardManager keyguardManager = getContext().getSystemService(
KeyguardManager.class);
- return keyguardManager != null && keyguardManager.isDeviceLocked();
+ return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index d90699a61928..ee4c606fa6d3 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -110,7 +110,7 @@ public final class TimeController extends StateController {
maybeUpdateAlarmsLocked(
job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
job.hasDeadlineConstraint() ? job.getLatestRunTimeElapsed() : Long.MAX_VALUE,
- job.getSourceUid());
+ new WorkSource(job.getSourceUid(), job.getSourcePackageName()));
}
}
@@ -156,6 +156,7 @@ public final class TimeController extends StateController {
synchronized (mLock) {
long nextExpiryTime = Long.MAX_VALUE;
int nextExpiryUid = 0;
+ String nextExpiryPackageName = null;
final long nowElapsedMillis = SystemClock.elapsedRealtime();
Iterator<JobStatus> it = mTrackedJobs.iterator();
@@ -171,10 +172,13 @@ public final class TimeController extends StateController {
} else { // Sorted by expiry time, so take the next one and stop.
nextExpiryTime = job.getLatestRunTimeElapsed();
nextExpiryUid = job.getSourceUid();
+ nextExpiryPackageName = job.getSourcePackageName();
break;
}
}
- setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryUid);
+ setDeadlineExpiredAlarmLocked(nextExpiryTime, nextExpiryPackageName != null
+ ? new WorkSource(nextExpiryUid, nextExpiryPackageName)
+ : new WorkSource(nextExpiryUid));
}
}
@@ -200,6 +204,7 @@ public final class TimeController extends StateController {
final long nowElapsedMillis = SystemClock.elapsedRealtime();
long nextDelayTime = Long.MAX_VALUE;
int nextDelayUid = 0;
+ String nextDelayPackageName = null;
boolean ready = false;
Iterator<JobStatus> it = mTrackedJobs.iterator();
while (it.hasNext()) {
@@ -221,13 +226,16 @@ public final class TimeController extends StateController {
if (nextDelayTime > jobDelayTime) {
nextDelayTime = jobDelayTime;
nextDelayUid = job.getSourceUid();
+ nextDelayPackageName = job.getSourcePackageName();
}
}
}
if (ready) {
mStateChangedListener.onControllerStateChanged();
}
- setDelayExpiredAlarmLocked(nextDelayTime, nextDelayUid);
+ setDelayExpiredAlarmLocked(nextDelayTime, nextDelayPackageName != null
+ ? new WorkSource(nextDelayUid, nextDelayPackageName)
+ : new WorkSource(nextDelayUid));
}
}
@@ -241,12 +249,12 @@ public final class TimeController extends StateController {
}
private void maybeUpdateAlarmsLocked(long delayExpiredElapsed, long deadlineExpiredElapsed,
- int uid) {
+ WorkSource ws) {
if (delayExpiredElapsed < mNextDelayExpiredElapsedMillis) {
- setDelayExpiredAlarmLocked(delayExpiredElapsed, uid);
+ setDelayExpiredAlarmLocked(delayExpiredElapsed, ws);
}
if (deadlineExpiredElapsed < mNextJobExpiredElapsedMillis) {
- setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, uid);
+ setDeadlineExpiredAlarmLocked(deadlineExpiredElapsed, ws);
}
}
@@ -255,11 +263,11 @@ public final class TimeController extends StateController {
* delay will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) {
+ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
- mNextDelayExpiredElapsedMillis, uid);
+ mNextDelayExpiredElapsedMillis, ws);
}
/**
@@ -267,11 +275,11 @@ public final class TimeController extends StateController {
* deadline will expire.
* This alarm <b>will</b> wake up the phone.
*/
- private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, int uid) {
+ private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
- mNextJobExpiredElapsedMillis, uid);
+ mNextJobExpiredElapsedMillis, ws);
}
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
@@ -283,7 +291,7 @@ public final class TimeController extends StateController {
}
private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
- long alarmTimeElapsed, int uid) {
+ long alarmTimeElapsed, WorkSource ws) {
ensureAlarmServiceLocked();
if (alarmTimeElapsed == Long.MAX_VALUE) {
mAlarmService.cancel(listener);
@@ -292,7 +300,7 @@ public final class TimeController extends StateController {
Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
}
mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
- AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, new WorkSource(uid));
+ AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 710684f4351d..f61cec9713c0 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -126,12 +126,6 @@ public class ZenModeHelper {
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mDefaultConfig = new ZenModeConfig();
- mDefaultRuleWeeknightsName = mContext.getResources()
- .getString(R.string.zen_mode_default_weeknights_name);
- mDefaultRuleWeekendsName = mContext.getResources()
- .getString(R.string.zen_mode_default_weekends_name);
- mDefaultRuleEventsName = mContext.getResources()
- .getString(R.string.zen_mode_default_events_name);
setDefaultZenRules(mContext);
mConfig = mDefaultConfig;
mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
@@ -436,6 +430,7 @@ public class ZenModeHelper {
}
private void appendDefaultRules (ZenModeConfig config) {
+ getDefaultRuleNames();
appendDefaultScheduleRules(config);
appendDefaultEventRules(config);
}
@@ -815,6 +810,16 @@ public class ZenModeHelper {
}
}
+ private void getDefaultRuleNames() {
+ // on locale-change, these values differ
+ mDefaultRuleWeeknightsName = mContext.getResources()
+ .getString(R.string.zen_mode_default_weeknights_name);
+ mDefaultRuleWeekendsName = mContext.getResources()
+ .getString(R.string.zen_mode_default_weekends_name);
+ mDefaultRuleEventsName = mContext.getResources()
+ .getString(R.string.zen_mode_default_events_name);
+ }
+
@VisibleForTesting
protected void applyRestrictions() {
final boolean zen = mZenMode != Global.ZEN_MODE_OFF;
@@ -928,6 +933,7 @@ public class ZenModeHelper {
weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
weeknights.startHour = 22;
weeknights.endHour = 7;
+ weeknights.exitAtAlarm = true;
final ZenRule rule1 = new ZenRule();
rule1.enabled = false;
rule1.name = mDefaultRuleWeeknightsName;
@@ -943,6 +949,7 @@ public class ZenModeHelper {
weekends.startHour = 23;
weekends.startMinute = 30;
weekends.endHour = 10;
+ weekends.exitAtAlarm = true;
final ZenRule rule2 = new ZenRule();
rule2.enabled = false;
rule2.name = mDefaultRuleWeekendsName;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d62f0934669d..496ebc2320d6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1127,15 +1127,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mResolvedInstructionSets.add(archSubDir.getName());
List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
-
- // Only add compiled files associated with the base.
- // Once b/62269291 is resolved, we can add all compiled files again.
- for (File oatFile : oatFiles) {
- if (oatFile.getName().equals("base.art")
- || oatFile.getName().equals("base.odex")
- || oatFile.getName().equals("base.vdex")) {
- mResolvedInheritedFiles.add(oatFile);
- }
+ if (!oatFiles.isEmpty()) {
+ mResolvedInheritedFiles.addAll(oatFiles);
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d2f242695891..275db1fa543d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3261,23 +3261,6 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- // If we have a profile for a compressed APK, copy it to the reference location.
- // Since the package is the stub one, remove the stub suffix to get the normal package and
- // APK name.
- File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, ""));
- if (profileFile.exists()) {
- try {
- // We could also do this lazily before calling dexopt in
- // PackageDexOptimizer to prevent this happening on first boot. The issue
- // is that we don't have a good way to say "do this only once".
- if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
- pkg.applicationInfo.uid, pkg.packageName)) {
- Log.e(TAG, "decompressPackage failed to copy system profile!");
- }
- } catch (Exception e) {
- Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e);
- }
- }
return dstCodePath;
}
@@ -9114,10 +9097,30 @@ public class PackageManagerService extends IPackageManager.Stub
// package and APK names.
String systemProfilePath =
getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
- File systemProfile = new File(systemProfilePath);
- // Use the profile for compilation if there exists one for the same package
- // in the system partition.
- useProfileForDexopt = systemProfile.exists();
+ profileFile = new File(systemProfilePath);
+ // If we have a profile for a compressed APK, copy it to the reference
+ // location.
+ // Note that copying the profile here will cause it to override the
+ // reference profile every OTA even though the existing reference profile
+ // may have more data. We can't copy during decompression since the
+ // directories are not set up at that point.
+ if (profileFile.exists()) {
+ try {
+ // We could also do this lazily before calling dexopt in
+ // PackageDexOptimizer to prevent this happening on first boot. The
+ // issue is that we don't have a good way to say "do this only
+ // once".
+ if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+ pkg.applicationInfo.uid, pkg.packageName)) {
+ Log.e(TAG, "Failed to copy system profile for stub package!");
+ } else {
+ useProfileForDexopt = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to copy profile " +
+ profileFile.getAbsolutePath() + " ", e);
+ }
+ }
}
}
}
@@ -21857,11 +21860,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
synchronized (mAvailableFeatures) {
final int count = mAvailableFeatures.size();
for (int i = 0; i < count; i++) {
- final FeatureInfo feat = mAvailableFeatures.valueAt(i);
- final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
- proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
- proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
- proto.end(featureToken);
+ mAvailableFeatures.valueAt(i).writeToProto(proto, PackageServiceDumpProto.FEATURES);
}
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 56595c947ed4..191b43a66d51 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4929,11 +4929,7 @@ public final class Settings {
void dumpSharedUsersProto(ProtoOutputStream proto) {
final int count = mSharedUsers.size();
for (int i = 0; i < count; i++) {
- final SharedUserSetting su = mSharedUsers.valueAt(i);
- final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
- proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
- proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
- proto.end(sharedUserToken);
+ mSharedUsers.valueAt(i).writeToProto(proto, PackageServiceDumpProto.SHARED_USERS);
}
}
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index a0dadae37624..877da144730f 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,7 +18,9 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.pm.PackageParser;
+import android.service.pm.PackageServiceDumpProto;
import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
import java.util.ArrayList;
import java.util.Collection;
@@ -53,6 +55,13 @@ public final class SharedUserSetting extends SettingBase {
+ name + "/" + userId + "}";
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId);
+ proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
+ proto.end(token);
+ }
+
void removePackage(PackageSetting packageSetting) {
if (packages.remove(packageSetting)) {
// recalculate the pkgFlags for this shared user if needed
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 062aa3310c21..d2d857caa240 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -417,8 +417,8 @@ public class PermissionManagerService {
bp = new BasePermission(info.name, tree.getSourcePackageName(),
BasePermission.TYPE_DYNAMIC);
} else if (bp.isDynamic()) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
+ // TODO: switch this back to SecurityException
+ Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ info.name);
}
changed = bp.addToTree(fixedLevel, info, tree);
@@ -444,8 +444,8 @@ public class PermissionManagerService {
return;
}
if (bp.isDynamic()) {
- throw new SecurityException(
- "Not allowed to modify non-dynamic permission "
+ // TODO: switch this back to SecurityException
+ Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ permName);
}
mSettings.removePermissionLocked(permName);
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index af1fa2fe0291..fa33fe8fa92a 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -449,6 +449,9 @@ class WindowSurfacePlacer {
// animating?
wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
wtoken.updateReportedVisibilityLocked();
+ // setAllAppWinAnimators so the windows get onExitAnimationDone once the animation is
+ // done.
+ wtoken.setAllAppWinAnimators();
// Force the allDrawn flag, because we want to start
// this guy's animations regardless of whether it's
// gotten drawn.
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 6d7d4cbcfd5a..8e41a554b9e3 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -33,7 +33,10 @@ LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aid
aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src)
-LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test
+LOCAL_JAVA_LIBRARIES := \
+ android.hidl.manager-V1.0-java \
+ android.test.mock \
+ legacy-android-test \
LOCAL_PACKAGE_NAME := FrameworksServicesTests
LOCAL_COMPATIBILITY_SUITE := device-tests
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
new file mode 100644
index 000000000000..5d1d07bf42a2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import static junit.framework.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.hardware.health.V2_0.IHealth;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.RemoteException;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+
+public class BatteryServiceTest extends AndroidTestCase {
+
+ @Mock IServiceManager mMockedManager;
+ @Mock IHealth mMockedHal;
+
+ @Mock BatteryService.HealthServiceWrapper.Callback mCallback;
+ @Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
+ @Mock BatteryService.HealthServiceWrapper.IHealthSupplier mHealthServiceSupplier;
+ BatteryService.HealthServiceWrapper mWrapper;
+
+ private static final String HEALTHD = BatteryService.HealthServiceWrapper.INSTANCE_HEALTHD;
+ private static final String VENDOR = BatteryService.HealthServiceWrapper.INSTANCE_VENDOR;
+
+ @Override
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
+ return new ArgumentMatcher<T>() {
+ @Override public boolean matches(T e) {
+ return collection.contains(e);
+ }
+ @Override public String toString() {
+ return collection.toString();
+ }
+ };
+ }
+
+ private void initForInstances(String... instanceNamesArr) throws Exception {
+ final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
+ doAnswer((invocation) -> {
+ Slog.e("BatteryServiceTest", "health: onRegistration " + invocation.getArguments()[2]);
+ ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
+ IHealth.kInterfaceName,
+ (String)invocation.getArguments()[1],
+ true /* preexisting */);
+ return null;
+ }).when(mMockedManager).registerForNotifications(
+ eq(IHealth.kInterfaceName),
+ argThat(isOneOf(instanceNames)),
+ any(IServiceNotification.class));
+
+ doReturn(mMockedHal).when(mMockedManager)
+ .get(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
+
+ doReturn(IServiceManager.Transport.HWBINDER).when(mMockedManager)
+ .getTransport(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
+
+ doReturn(mMockedManager).when(mManagerSupplier).get();
+ doReturn(mMockedHal).when(mHealthServiceSupplier)
+ .get(argThat(isOneOf(instanceNames)));
+
+ mWrapper = new BatteryService.HealthServiceWrapper();
+ }
+
+ @SmallTest
+ public void testWrapPreferVendor() throws Exception {
+ initForInstances(VENDOR, HEALTHD);
+ mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+ verify(mCallback).onRegistration(same(mMockedHal), eq(VENDOR));
+ }
+
+ @SmallTest
+ public void testUseHealthd() throws Exception {
+ initForInstances(HEALTHD);
+ mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+ verify(mCallback).onRegistration(same(mMockedHal), eq(HEALTHD));
+ }
+
+ @SmallTest
+ public void testNoService() throws Exception {
+ initForInstances("unrelated");
+ try {
+ mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
+ fail("Expect NoSuchElementException");
+ } catch (NoSuchElementException ex) {
+ // expected
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 54f7363aff8a..de980b2ffec2 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1592,6 +1592,18 @@ public class CarrierConfigManager {
public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL =
"disable_charge_indication_bool";
+ /**
+ * Boolean indicating whether to skip the call forwarding (CF) fail-to-disable dialog.
+ * The logic used to determine whether we succeeded in disabling is carrier specific,
+ * so the dialog may not always be accurate.
+ * {@code false} - show CF fail-to-disable dialog.
+ * {@code true} - skip showing CF fail-to-disable dialog.
+ *
+ * @hide
+ */
+ public static final String KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL =
+ "skip_cf_fail_to_disable_dialog_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1746,6 +1758,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL, false);
+ sDefaults.putBoolean(KEY_SKIP_CF_FAIL_TO_DISABLE_DIALOG_BOOL, false);
// MMS defaults
sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index d2aef2007044..9674c9300602 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -19,6 +19,7 @@ package android.telephony;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
import java.util.Arrays;
/**
@@ -38,6 +39,20 @@ public final class NetworkScanRequest implements Parcelable {
public static final int MAX_BANDS = 8;
/** @hide */
public static final int MAX_CHANNELS = 32;
+ /** @hide */
+ public static final int MAX_MCC_MNC_LIST_SIZE = 20;
+ /** @hide */
+ public static final int MIN_SEARCH_PERIODICITY_SEC = 5;
+ /** @hide */
+ public static final int MAX_SEARCH_PERIODICITY_SEC = 300;
+ /** @hide */
+ public static final int MIN_SEARCH_MAX_SEC = 60;
+ /** @hide */
+ public static final int MAX_SEARCH_MAX_SEC = 3600;
+ /** @hide */
+ public static final int MIN_INCREMENTAL_PERIODICITY_SEC = 1;
+ /** @hide */
+ public static final int MAX_INCREMENTAL_PERIODICITY_SEC = 10;
/** Performs the scan only once */
public static final int SCAN_TYPE_ONE_SHOT = 0;
@@ -46,24 +61,84 @@ public final class NetworkScanRequest implements Parcelable {
*
* The modem will start new scans periodically, and the interval between two scans is usually
* multiple minutes.
- * */
+ */
public static final int SCAN_TYPE_PERIODIC = 1;
/** Defines the type of the scan. */
public int scanType;
+ /**
+ * Search periodicity (in seconds).
+ * Expected range for the input is [5s - 300s]
+ * This value must be less than or equal to maxSearchTime
+ */
+ public int searchPeriodicity;
+
+ /**
+ * Maximum duration of the periodic search (in seconds).
+ * Expected range for the input is [60s - 3600s]
+ * If the search lasts this long, it will be terminated.
+ */
+ public int maxSearchTime;
+
+ /**
+ * Indicates whether the modem should report incremental
+ * results of the network scan to the client.
+ * FALSE – Incremental results are not reported.
+ * TRUE (default) – Incremental results are reported
+ */
+ public boolean incrementalResults;
+
+ /**
+ * Indicates the periodicity with which the modem should
+ * report incremental results to the client (in seconds).
+ * Expected range for the input is [1s - 10s]
+ * This value must be less than or equal to maxSearchTime
+ */
+ public int incrementalResultsPeriodicity;
+
/** Describes the radio access technologies with bands or channels that need to be scanned. */
public RadioAccessSpecifier[] specifiers;
/**
+ * Describes the List of PLMN ids (MCC-MNC)
+ * If any PLMN of this list is found, search should end at that point and
+ * results with all PLMN found till that point should be sent as response.
+ * If list not sent, search to be completed till end and all PLMNs found to be reported.
+ * Max size of array is MAX_MCC_MNC_LIST_SIZE
+ */
+ public ArrayList<String> mccMncs;
+
+ /**
* Creates a new NetworkScanRequest with scanType and network specifiers
*
* @param scanType The type of the scan
* @param specifiers the radio network with bands / channels to be scanned
+ * @param searchPeriodicity Search periodicity (in seconds)
+ * @param maxSearchTime Maximum duration of the periodic search (in seconds)
+ * @param incrementalResults Indicates whether the modem should report incremental
+ * results of the network scan to the client
+ * @param incrementalResultsPeriodicity Indicates the periodicity with which the modem should
+ * report incremental results to the client (in seconds)
+ * @param mccMncs Describes the List of PLMN ids (MCC-MNC)
*/
- public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers) {
+ public NetworkScanRequest(int scanType, RadioAccessSpecifier[] specifiers,
+ int searchPeriodicity,
+ int maxSearchTime,
+ boolean incrementalResults,
+ int incrementalResultsPeriodicity,
+ ArrayList<String> mccMncs) {
this.scanType = scanType;
this.specifiers = specifiers;
+ this.searchPeriodicity = searchPeriodicity;
+ this.maxSearchTime = maxSearchTime;
+ this.incrementalResults = incrementalResults;
+ this.incrementalResultsPeriodicity = incrementalResultsPeriodicity;
+ if (mccMncs != null) {
+ this.mccMncs = mccMncs;
+ } else {
+ this.mccMncs = new ArrayList<>();
+ }
}
@Override
@@ -75,6 +150,11 @@ public final class NetworkScanRequest implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(scanType);
dest.writeParcelableArray(specifiers, flags);
+ dest.writeInt(searchPeriodicity);
+ dest.writeInt(maxSearchTime);
+ dest.writeBoolean(incrementalResults);
+ dest.writeInt(incrementalResultsPeriodicity);
+ dest.writeStringList(mccMncs);
}
private NetworkScanRequest(Parcel in) {
@@ -82,6 +162,12 @@ public final class NetworkScanRequest implements Parcelable {
specifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
Object.class.getClassLoader(),
RadioAccessSpecifier.class);
+ searchPeriodicity = in.readInt();
+ maxSearchTime = in.readInt();
+ incrementalResults = in.readBoolean();
+ incrementalResultsPeriodicity = in.readInt();
+ mccMncs = new ArrayList<>();
+ in.readStringList(mccMncs);
}
@Override
@@ -99,13 +185,24 @@ public final class NetworkScanRequest implements Parcelable {
}
return (scanType == nsr.scanType
- && Arrays.equals(specifiers, nsr.specifiers));
+ && Arrays.equals(specifiers, nsr.specifiers)
+ && searchPeriodicity == nsr.searchPeriodicity
+ && maxSearchTime == nsr.maxSearchTime
+ && incrementalResults == nsr.incrementalResults
+ && incrementalResultsPeriodicity == nsr.incrementalResultsPeriodicity
+ && (((mccMncs != null)
+ && mccMncs.equals(nsr.mccMncs))));
}
@Override
public int hashCode () {
return ((scanType * 31)
- + (Arrays.hashCode(specifiers)) * 37);
+ + (Arrays.hashCode(specifiers)) * 37
+ + (searchPeriodicity * 41)
+ + (maxSearchTime * 43)
+ + ((incrementalResults == true? 1 : 0) * 47)
+ + (incrementalResultsPeriodicity * 53)
+ + (mccMncs.hashCode() * 59));
}
public static final Creator<NetworkScanRequest> CREATOR =
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 2f85a1df8a22..c3b2c482049b 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -113,6 +113,10 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
@Override
public final int initialize(final int subscriptionId,
final IMbmsDownloadSessionCallback callback) throws RemoteException {
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
final int uid = Binder.getCallingUid();
callback.asBinder().linkToDeath(new DeathRecipient() {
@Override
@@ -240,6 +244,13 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
public final int registerStateCallback(final DownloadRequest downloadRequest,
final IDownloadStateCallback callback, int flags) throws RemoteException {
final int uid = Binder.getCallingUid();
+ if (downloadRequest == null) {
+ throw new NullPointerException("Download request must not be null");
+ }
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
DeathRecipient deathRecipient = new DeathRecipient() {
@Override
public void binderDied() {
@@ -292,6 +303,13 @@ public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
public final int unregisterStateCallback(
final DownloadRequest downloadRequest, final IDownloadStateCallback callback)
throws RemoteException {
+ if (downloadRequest == null) {
+ throw new NullPointerException("Download request must not be null");
+ }
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
DeathRecipient deathRecipient =
mDownloadCallbackDeathRecipients.remove(callback.asBinder());
if (deathRecipient == null) {
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index f8f370a5fe8d..65b726dfb45d 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -65,6 +65,10 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
@Override
public final int initialize(final IMbmsStreamingSessionCallback callback,
final int subscriptionId) throws RemoteException {
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
final int uid = Binder.getCallingUid();
callback.asBinder().linkToDeath(new DeathRecipient() {
@Override
@@ -152,6 +156,10 @@ public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
@Override
public int startStreaming(final int subscriptionId, String serviceId,
final IStreamingServiceCallback callback) throws RemoteException {
+ if (callback == null) {
+ throw new NullPointerException("Callback must not be null");
+ }
+
final int uid = Binder.getCallingUid();
callback.asBinder().linkToDeath(new DeathRecipient() {
@Override
diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk
index 93f6d7a5f52b..6da1b38773ed 100644
--- a/tests/FeatureSplit/base/Android.mk
+++ b/tests/FeatureSplit/base/Android.mk
@@ -17,6 +17,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := FeatureSplitBase
LOCAL_EXPORT_PACKAGE_RESOURCES := true
diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk
index e6ba5c2d04c9..b3ea97b03d5d 100644
--- a/tests/FeatureSplit/feature1/Android.mk
+++ b/tests/FeatureSplit/feature1/Android.mk
@@ -26,6 +26,6 @@ LOCAL_APK_LIBRARIES := FeatureSplitBase
LOCAL_RES_LIBRARIES := FeatureSplitBase
LOCAL_AAPT_FLAGS += --package-id 0x80
-LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.one
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature1/AndroidManifest.xml b/tests/FeatureSplit/feature1/AndroidManifest.xml
index b87361faac62..4e7d15102a6e 100644
--- a/tests/FeatureSplit/feature1/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature1/AndroidManifest.xml
@@ -15,13 +15,13 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature"
+ package="com.android.test.split.feature.one"
featureSplit="feature1">
<uses-sdk android:minSdkVersion="21" />
<application>
- <activity android:name=".one.One" android:label="Feature One">
+ <activity android:name=".One" android:label="Feature One">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/FeatureSplit/feature1/res/values/values.xml b/tests/FeatureSplit/feature1/res/values/values.xml
index 10dbd9733889..0e3e73c32480 100644
--- a/tests/FeatureSplit/feature1/res/values/values.xml
+++ b/tests/FeatureSplit/feature1/res/values/values.xml
@@ -20,7 +20,7 @@
<integer name="test_integer2">200</integer>
<color name="test_color2">#00ff00</color>
<string-array name="string_array2">
- <item>@*string/app_title</item>
+ <item>@*com.android.test.split.feature:string/app_title</item>
</string-array>
</resources>
diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk
index c8e860942fa3..e2fd90384538 100644
--- a/tests/FeatureSplit/feature2/Android.mk
+++ b/tests/FeatureSplit/feature2/Android.mk
@@ -26,6 +26,6 @@ LOCAL_APK_LIBRARIES := FeatureSplitBase
LOCAL_RES_LIBRARIES := FeatureSplitBase
LOCAL_AAPT_FLAGS += --package-id 0x81
-LOCAL_AAPT_FLAGS += --custom-package com.android.test.split.feature.two
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.test.split.feature
include $(BUILD_PACKAGE)
diff --git a/tests/FeatureSplit/feature2/AndroidManifest.xml b/tests/FeatureSplit/feature2/AndroidManifest.xml
index abd0b5eb6933..bfe6f38201bd 100644
--- a/tests/FeatureSplit/feature2/AndroidManifest.xml
+++ b/tests/FeatureSplit/feature2/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.test.split.feature"
+ package="com.android.test.split.feature.two"
featureSplit="feature2">
<uses-sdk android:minSdkVersion="21" />
diff --git a/tests/FeatureSplit/feature2/res/values/values.xml b/tests/FeatureSplit/feature2/res/values/values.xml
index af5ed1b79b26..2fa6f907b8ab 100644
--- a/tests/FeatureSplit/feature2/res/values/values.xml
+++ b/tests/FeatureSplit/feature2/res/values/values.xml
@@ -18,7 +18,7 @@
<integer name="test_integer3">300</integer>
<color name="test_color3">#0000ff</color>
<string-array name="string_array3">
- <item>@string/app_title</item>
+ <item>@*com.android.test.split.feature:string/app_title</item>
</string-array>
</resources>
diff --git a/tools/bit/command.cpp b/tools/bit/command.cpp
index 1ff7c221b26e..f95ea117a96e 100644
--- a/tools/bit/command.cpp
+++ b/tools/bit/command.cpp
@@ -189,7 +189,7 @@ run_command(const Command& command)
int
exec_with_path_search(const char* prog, char const* const* argv, char const* const* envp)
{
- if (prog[0] == '/') {
+ if (strchr(prog, '/') != NULL) {
return execve(prog, (char*const*)argv, (char*const*)envp);
} else {
char* pathEnv = strdup(getenv("PATH"));
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index a8a4cfcab351..a71cea1c44f9 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -623,12 +623,13 @@ run_phases(vector<Target*> targets, const Options& options)
const string buildProduct = get_required_env("TARGET_PRODUCT", false);
const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
- const string buildDevice = get_build_var(buildTop, "TARGET_DEVICE", false);
- const string buildId = get_build_var(buildTop, "BUILD_ID", false);
- const string buildOut = get_out_dir();
chdir_or_exit(buildTop.c_str());
+ const string buildDevice = get_build_var("TARGET_DEVICE", false);
+ const string buildId = get_build_var("BUILD_ID", false);
+ const string buildOut = get_out_dir();
+
// Get the modules for the targets
map<string,Module> modules;
read_modules(buildOut, buildDevice, &modules, false);
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index b2ee99c2c74c..5a9ab22719cb 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -36,31 +36,16 @@ using namespace std;
map<string,string> g_buildVars;
-static unsigned int
-get_thread_count()
-{
- unsigned int threads = std::thread::hardware_concurrency();
- // Guess if the value cannot be computed
- return threads == 0 ? 4 : static_cast<unsigned int>(threads * 1.3f);
-}
-
string
-get_build_var(const string& buildTop, const string& name, bool quiet)
+get_build_var(const string& name, bool quiet)
{
int err;
map<string,string>::iterator it = g_buildVars.find(name);
if (it == g_buildVars.end()) {
- Command cmd("make");
- cmd.AddArg("--no-print-directory");
- cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
- cmd.AddArg("-C");
- cmd.AddArg(buildTop);
- cmd.AddArg("-f");
- cmd.AddArg("build/core/config.mk");
- cmd.AddArg(string("dumpvar-") + name);
- cmd.AddEnv("CALLED_FROM_SETUP", "true");
- cmd.AddEnv("BUILD_SYSTEM", "build/core");
+ Command cmd("build/soong/soong_ui.bash");
+ cmd.AddArg("--dumpvar-mode");
+ cmd.AddArg(name);
string output = trim(get_command_output(cmd, &err, quiet));
if (err == 0) {
@@ -208,10 +193,8 @@ read_modules(const string& buildOut, const string& device, map<string,Module>* r
int
build_goals(const vector<string>& goals)
{
- Command cmd("make");
- cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
- cmd.AddArg("-f");
- cmd.AddArg("build/core/main.mk");
+ Command cmd("build/soong/soong_ui.bash");
+ cmd.AddArg("--make-mode");
for (size_t i=0; i<goals.size(); i++) {
cmd.AddArg(goals[i]);
}
diff --git a/tools/bit/make.h b/tools/bit/make.h
index bb83c6e14226..1c9504d62d46 100644
--- a/tools/bit/make.h
+++ b/tools/bit/make.h
@@ -31,7 +31,7 @@ struct Module
vector<string> installed;
};
-string get_build_var(const string& buildTop, const string& name, bool quiet);
+string get_build_var(const string& name, bool quiet);
/**
* Poke around in the out directory and try to find a device name that matches
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index c6ad4c2aa396..dcb90e411d34 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -13,6 +13,7 @@ EMOJI_VS = 0xFE0F
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'be': 'Cyrl',
'bg': 'Cyrl',
'bn': 'Beng',
'cu': 'Cyrl',
@@ -33,6 +34,7 @@ LANG_TO_SCRIPT = {
'ja': 'Jpan',
'kn': 'Knda',
'ko': 'Kore',
+ 'la': 'Latn',
'ml': 'Mlym',
'mn': 'Cyrl',
'mr': 'Deva',