summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt39
-rw-r--r--api/system-current.txt8
-rw-r--r--api/test-current.txt39
-rw-r--r--core/java/android/app/ActivityThread.java14
-rw-r--r--core/java/android/app/LoadedApk.java7
-rw-r--r--core/java/android/app/Notification.java1
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java45
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/job/JobInfo.java11
-rw-r--r--core/java/android/app/usage/UsageStats.java41
-rw-r--r--core/java/android/content/ContentProviderClient.java3
-rw-r--r--core/java/android/content/Intent.java2
-rw-r--r--core/java/android/content/res/Configuration.java8
-rw-r--r--core/java/android/content/res/Resources.java10
-rw-r--r--core/java/android/nfc/tech/NfcF.java9
-rw-r--r--core/java/android/os/BatteryStats.java44
-rw-r--r--core/java/android/os/UserHandle.java3
-rw-r--r--core/java/android/os/storage/IMountService.java10
-rw-r--r--core/java/android/os/storage/StorageManager.java13
-rw-r--r--core/java/android/provider/BlockedNumberContract.java119
-rw-r--r--core/java/android/provider/ContactsContract.java5
-rwxr-xr-xcore/java/android/provider/Settings.java17
-rw-r--r--core/java/android/service/notification/NotificationAssistantService.java25
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java5
-rw-r--r--core/java/android/text/style/LocaleSpan.java4
-rw-r--r--core/java/android/util/LocaleList.java9
-rw-r--r--core/java/android/view/RenderNode.java5
-rw-r--r--core/java/android/view/SurfaceView.java101
-rw-r--r--core/java/android/view/View.java12
-rw-r--r--core/java/android/view/ViewRootImpl.java28
-rw-r--r--core/java/android/view/WindowCallbacks.java18
-rw-r--r--core/java/android/view/WindowManagerInternal.java5
-rw-r--r--core/java/android/widget/AbsSeekBar.java2
-rw-r--r--core/java/android/widget/GridView.java2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java3
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl1
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java5
-rw-r--r--core/java/com/android/internal/app/ResolverComparator.java2
-rw-r--r--core/java/com/android/internal/os/BatterySipper.java10
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java348
-rw-r--r--core/java/com/android/internal/os/BluetoothPowerCalculator.java41
-rw-r--r--core/java/com/android/internal/os/WifiPowerCalculator.java8
-rw-r--r--core/java/com/android/internal/policy/BackdropFrameRenderer.java114
-rw-r--r--core/java/com/android/internal/policy/DecorView.java53
-rw-r--r--core/jni/android/graphics/Graphics.cpp8
-rw-r--r--core/jni/android_graphics_Canvas.cpp2
-rw-r--r--core/jni/android_graphics_drawable_VectorDrawable.cpp6
-rw-r--r--core/jni/android_hardware_SensorManager.cpp4
-rw-r--r--core/jni/android_view_RenderNode.cpp72
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp23
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/drawable/ic_close.xml24
-rw-r--r--core/res/res/drawable/ic_feedback.xml27
-rw-r--r--core/res/res/drawable/ic_refresh.xml27
-rw-r--r--core/res/res/drawable/ic_schedule.xml30
-rw-r--r--core/res/res/layout/app_anr_dialog.xml11
-rw-r--r--core/res/res/layout/app_error_dialog.xml10
-rw-r--r--core/res/res/layout/resolve_grid_item.xml1
-rw-r--r--core/res/res/values/colors_material.xml2
-rw-r--r--core/res/res/values/dimens.xml2
-rw-r--r--core/res/res/values/styles.xml8
-rw-r--r--core/res/res/values/styles_material.xml2
-rw-r--r--core/tests/coretests/src/android/print/BasePrintTest.java2
-rw-r--r--data/fonts/Android.mk5
-rw-r--r--data/fonts/AndroidClock_Highlight.ttfbin4464 -> 0 bytes
-rw-r--r--data/fonts/AndroidClock_Solid.ttfbin4464 -> 0 bytes
-rw-r--r--data/fonts/Clockopia.ttfbin6564 -> 0 bytes
-rw-r--r--data/fonts/MTLc3m.ttfbin1922720 -> 0 bytes
-rw-r--r--data/fonts/MTLmr3m.ttfbin2558716 -> 0 bytes
-rw-r--r--data/fonts/fonts.mk3
-rw-r--r--data/fonts/fonts.xml3
-rw-r--r--graphics/java/android/graphics/Paint.java12
-rw-r--r--graphics/java/android/graphics/Rect.java15
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java65
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java42
-rw-r--r--keystore/java/android/security/keystore/KeyInfo.java2
-rw-r--r--libs/hwui/Android.mk3
-rw-r--r--libs/hwui/DamageAccumulator.h2
-rw-r--r--libs/hwui/GradientCache.cpp7
-rw-r--r--libs/hwui/RenderNode.cpp4
-rw-r--r--libs/hwui/RenderNode.h15
-rw-r--r--libs/hwui/TreeInfo.h6
-rw-r--r--libs/hwui/VectorDrawable.cpp4
-rw-r--r--libs/hwui/VectorDrawable.h4
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp29
-rw-r--r--libs/hwui/renderthread/CanvasContext.h13
-rw-r--r--libs/hwui/renderthread/EglManager.cpp11
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp24
-rw-r--r--libs/hwui/renderthread/RenderProxy.h6
-rw-r--r--libs/hwui/tests/unit/GradientCacheTests.cpp40
-rw-r--r--media/java/android/media/AudioTrack.java22
-rw-r--r--media/java/android/media/audiopolicy/AudioMixingRule.java13
-rw-r--r--media/java/android/media/browse/MediaBrowser.java3
-rw-r--r--media/java/android/service/media/MediaBrowserService.java54
-rw-r--r--packages/DocumentsUI/res/drawable/cabinet.pngbin21844 -> 0 bytes
-rw-r--r--packages/DocumentsUI/res/drawable/cabinet.xml81
-rw-r--r--packages/DocumentsUI/res/drawable/hourglass.xml168
-rw-r--r--packages/DocumentsUI/res/layout/directory_cluster.xml2
-rw-r--r--packages/DocumentsUI/res/menu/activity.xml36
-rw-r--r--packages/DocumentsUI/res/values/strings.xml20
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java209
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java61
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java158
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java29
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java61
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/PairedTask.java77
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java52
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/State.java13
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java16
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java14
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java15
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java195
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TetherUtil.java30
-rw-r--r--packages/SystemUI/res/anim/recents_from_app_enter.xml28
-rw-r--r--packages/SystemUI/res/anim/recents_from_app_exit.xml30
-rw-r--r--packages/SystemUI/res/anim/recents_from_launcher_enter.xml2
-rw-r--r--packages/SystemUI/res/anim/recents_from_launcher_exit.xml4
-rw-r--r--packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml4
-rw-r--r--packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml30
-rw-r--r--packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml31
-rw-r--r--packages/SystemUI/res/anim/recents_to_launcher_enter.xml4
-rw-r--r--packages/SystemUI/res/anim/recents_to_launcher_exit.xml2
-rw-r--r--packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml4
-rw-r--r--packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml2
-rw-r--r--packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml36
-rw-r--r--packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml29
-rw-r--r--packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml (renamed from packages/SystemUI/res/anim/recents_return_to_launcher_enter.xml)15
-rw-r--r--packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml (renamed from packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml)17
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_category_separator.xml (renamed from packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml)13
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_container.xml8
-rw-r--r--packages/SystemUI/res/layout/keyboard_shortcuts_view.xml40
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/res/values/config.xml14
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/res/values/styles.xml25
-rw-r--r--packages/SystemUI/res/xml/tuner_prefs.xml5
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/Interpolators.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java32
-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.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java4
-rw-r--r--proto/src/metrics_constants.proto4
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java6
-rw-r--r--services/core/java/com/android/server/DeviceIdleController.java1
-rw-r--r--services/core/java/com/android/server/MountService.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java6
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java49
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java21
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java70
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java120
-rw-r--r--services/core/java/com/android/server/am/UserController.java55
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java2
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java6
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java6
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java7
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java27
-rw-r--r--services/core/java/com/android/server/pm/Installer.java21
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java66
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java40
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java7
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java55
-rw-r--r--services/core/java/com/android/server/wm/Task.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java29
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java120
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java31
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java76
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rw-r--r--services/tests/servicestests/Android.mk5
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java100
-rw-r--r--services/usage/java/com/android/server/usage/AppIdleHistory.java366
-rw-r--r--services/usage/java/com/android/server/usage/IntervalStats.java18
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java291
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsXmlV1.java23
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java201
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java9
-rw-r--r--telephony/java/android/telephony/SubscriptionInfo.java3
-rw-r--r--telephony/java/com/android/ims/ImsCallForwardInfo.java8
-rw-r--r--telephony/java/com/android/ims/ImsReasonInfo.java13
-rw-r--r--telephony/java/com/android/ims/ImsStreamMediaProfile.java10
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java125
-rw-r--r--wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl8
-rw-r--r--wifi/java/android/net/wifi/nan/IWifiNanManager.aidl6
-rw-r--r--wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl6
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanEventListener.java14
-rw-r--r--wifi/java/android/net/wifi/nan/WifiNanSessionListener.java8
215 files changed, 4003 insertions, 2163 deletions
diff --git a/api/current.txt b/api/current.txt
index 5361d0a977b1..5c0628c40d64 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28,7 +28,6 @@ package android {
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
- field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -34369,6 +34368,9 @@ package android.service.media {
ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle);
method public android.os.Bundle getExtras();
method public java.lang.String getRootId();
+ field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
}
public class MediaBrowserService.Result {
@@ -34422,39 +34424,6 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
- ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
- method public final void clearAnnotation(java.lang.String);
- method public void onNotificationActionClick(java.lang.String, long, int);
- method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
- method public void onNotificationRemoved(java.lang.String, long, int);
- method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
- method public final void setAnnotation(java.lang.String, android.app.Notification);
- field public static final int REASON_APP_CANCEL = 8; // 0x8
- field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
- field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
- field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
- field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
- field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
- field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
- field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 15; // 0xf
- field public static final int REASON_PROFILE_TURNED_OFF = 16; // 0x10
- field public static final int REASON_TOPIC_BANNED = 14; // 0xe
- field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
- }
-
- public class NotificationAssistantService.Adjustment {
- ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
- }
-
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -36475,6 +36444,7 @@ package android.telephony {
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+ field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
@@ -40070,7 +40040,6 @@ package android.util {
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
- method public java.util.Locale getPrimary();
method public int indexOf(java.util.Locale);
method public boolean isEmpty();
method public static void setDefault(android.util.LocaleList);
diff --git a/api/system-current.txt b/api/system-current.txt
index a43e3f61c743..2adb1e61afdf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -41,7 +41,6 @@ package android {
field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
- field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -36779,6 +36778,9 @@ package android.service.media {
ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle);
method public android.os.Bundle getExtras();
method public java.lang.String getRootId();
+ field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
}
public class MediaBrowserService.Result {
@@ -36836,13 +36838,11 @@ package android.service.notification {
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
ctor public NotificationAssistantService();
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
- method public final void clearAnnotation(java.lang.String);
method public void onNotificationActionClick(java.lang.String, long, int);
method public void onNotificationClick(java.lang.String, long);
method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
method public void onNotificationRemoved(java.lang.String, long, int);
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
- method public final void setAnnotation(java.lang.String, android.app.Notification);
field public static final int REASON_APP_CANCEL = 8; // 0x8
field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
@@ -39059,6 +39059,7 @@ package android.telephony {
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+ field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
@@ -42718,7 +42719,6 @@ package android.util {
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
- method public java.util.Locale getPrimary();
method public int indexOf(java.util.Locale);
method public boolean isEmpty();
method public static void setDefault(android.util.LocaleList);
diff --git a/api/test-current.txt b/api/test-current.txt
index 278a47d1debb..7abc6d43cd90 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28,7 +28,6 @@ package android {
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
field public static final java.lang.String BIND_MIDI_DEVICE_SERVICE = "android.permission.BIND_MIDI_DEVICE_SERVICE";
field public static final java.lang.String BIND_NFC_SERVICE = "android.permission.BIND_NFC_SERVICE";
- field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
@@ -34384,6 +34383,9 @@ package android.service.media {
ctor public MediaBrowserService.BrowserRoot(java.lang.String, android.os.Bundle);
method public android.os.Bundle getExtras();
method public java.lang.String getRootId();
+ field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
}
public class MediaBrowserService.Result {
@@ -34437,39 +34439,6 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
}
- public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
- ctor public NotificationAssistantService();
- method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
- method public final void clearAnnotation(java.lang.String);
- method public void onNotificationActionClick(java.lang.String, long, int);
- method public void onNotificationClick(java.lang.String, long);
- method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
- method public void onNotificationRemoved(java.lang.String, long, int);
- method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
- method public final void setAnnotation(java.lang.String, android.app.Notification);
- field public static final int REASON_APP_CANCEL = 8; // 0x8
- field public static final int REASON_APP_CANCEL_ALL = 9; // 0x9
- field public static final int REASON_DELEGATE_CANCEL = 2; // 0x2
- field public static final int REASON_DELEGATE_CANCEL_ALL = 3; // 0x3
- field public static final int REASON_DELEGATE_CLICK = 1; // 0x1
- field public static final int REASON_DELEGATE_ERROR = 4; // 0x4
- field public static final int REASON_GROUP_OPTIMIZATION = 13; // 0xd
- field public static final int REASON_GROUP_SUMMARY_CANCELED = 12; // 0xc
- field public static final int REASON_LISTENER_CANCEL = 10; // 0xa
- field public static final int REASON_LISTENER_CANCEL_ALL = 11; // 0xb
- field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
- field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
- field public static final int REASON_PACKAGE_SUSPENDED = 15; // 0xf
- field public static final int REASON_PROFILE_TURNED_OFF = 16; // 0x10
- field public static final int REASON_TOPIC_BANNED = 14; // 0xe
- field public static final int REASON_USER_STOPPED = 6; // 0x6
- field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
- }
-
- public class NotificationAssistantService.Adjustment {
- ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
- }
-
public abstract class NotificationListenerService extends android.app.Service {
ctor public NotificationListenerService();
method public final void cancelAllNotifications();
@@ -36490,6 +36459,7 @@ package android.telephony {
field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
+ field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
@@ -40087,7 +40057,6 @@ package android.util {
method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getFirstMatch(java.lang.String[]);
- method public java.util.Locale getPrimary();
method public int indexOf(java.util.Locale);
method public boolean isEmpty();
method public static void setDefault(android.util.LocaleList);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 805b2034ff05..6424520df3ec 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4822,14 +4822,12 @@ public final class ActivityThread {
}
private void updateDefaultDensity() {
- if (mCurDefaultDisplayDpi != Configuration.DENSITY_DPI_UNDEFINED
- && mCurDefaultDisplayDpi != DisplayMetrics.DENSITY_DEVICE
- && !mDensityCompatMode) {
- Slog.i(TAG, "Switching default density from "
- + DisplayMetrics.DENSITY_DEVICE + " to "
- + mCurDefaultDisplayDpi);
- DisplayMetrics.DENSITY_DEVICE = mCurDefaultDisplayDpi;
- Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
+ final int densityDpi = mCurDefaultDisplayDpi;
+ if (!mDensityCompatMode
+ && densityDpi != Configuration.DENSITY_DPI_UNDEFINED
+ && densityDpi != DisplayMetrics.DENSITY_DEVICE) {
+ DisplayMetrics.DENSITY_DEVICE = densityDpi;
+ Bitmap.setDefaultDensity(densityDpi);
}
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 1e22bef63d8c..da52c1e5ba1d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -382,6 +382,13 @@ public final class LoadedApk {
libraryPermittedPath += File.pathSeparator +
System.getProperty("java.library.path");
}
+ // DO NOT SHIP: this is a workaround for apps loading native libraries
+ // provided by 3rd party apps using absolute path instead of corresponding
+ // classloader; see http://b/26954419 for example.
+ if (mApplicationInfo.targetSdkVersion <= 23) {
+ libraryPermittedPath += File.pathSeparator + "/data/app";
+ }
+ // -----------------------------------------------------------------------------
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 34c90c165490..a78076bdfa6f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3236,6 +3236,7 @@ public class Notification implements Parcelable
return;
}
contentView.setTextViewText(R.id.app_name_text, appName);
+ contentView.setTextColor(R.id.app_name_text, resolveColor());
}
private void bindSmallIcon(RemoteViews contentView) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 1247afefcd01..02eb115175fd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4109,6 +4109,29 @@ public class DevicePolicyManager {
}
/**
+ * Called by the system to check if a specific accessibility service is disabled by admin.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName Accessibility service package name that needs to be checked.
+ * @param userHandle user id the admin is running as.
+ * @return true if the accessibility service is permitted, otherwise false.
+ *
+ * @hide
+ */
+ public boolean isAccessibilityServicePermittedByAdmin(@NonNull ComponentName admin,
+ @NonNull String packageName, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.isAccessibilityServicePermittedByAdmin(admin, packageName,
+ userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns the list of accessibility services permitted by the device or profiles
* owners of this user.
*
@@ -4188,6 +4211,28 @@ public class DevicePolicyManager {
}
/**
+ * Called by the system to check if a specific input method is disabled by admin.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName Input method package name that needs to be checked.
+ * @param userHandle user id the admin is running as.
+ * @return true if the input method is permitted, otherwise false.
+ *
+ * @hide
+ */
+ public boolean isInputMethodPermittedByAdmin(@NonNull ComponentName admin,
+ @NonNull String packageName, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.isInputMethodPermittedByAdmin(admin, packageName, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns the list of input methods permitted by the device or profiles
* owners of the current user. (*Not* calling user, due to a limitation in InputMethodManager.)
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b57e1b7d8081..c6a53443b51c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -174,10 +174,12 @@ interface IDevicePolicyManager {
boolean setPermittedAccessibilityServices(in ComponentName admin,in List packageList);
List getPermittedAccessibilityServices(in ComponentName admin);
List getPermittedAccessibilityServicesForUser(int userId);
+ boolean isAccessibilityServicePermittedByAdmin(in ComponentName admin, String packageName, int userId);
boolean setPermittedInputMethods(in ComponentName admin,in List packageList);
List getPermittedInputMethods(in ComponentName admin);
List getPermittedInputMethodsForCurrentUser();
+ boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId);
boolean setApplicationHidden(in ComponentName admin, in String packageName, boolean hidden);
boolean isApplicationHidden(in ComponentName admin, in String packageName);
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index b2ca023a017f..5398e7f2dc95 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -24,6 +24,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.Log;
+import static android.util.TimeUtils.formatForLogging;
import java.util.ArrayList;
@@ -640,12 +641,14 @@ public class JobInfo implements Parcelable {
}
JobInfo job = new JobInfo(this);
if (job.intervalMillis != job.getIntervalMillis()) {
- Log.w(TAG, "Specified interval is less than minimum interval. Clamped to "
- + job.getIntervalMillis());
+ Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
+ + formatForLogging(mIntervalMillis) + ". Clamped to " +
+ formatForLogging(job.getIntervalMillis()));
}
if (job.flexMillis != job.getFlexMillis()) {
- Log.w(TAG, "Specified flex is less than minimum flex. Clamped to "
- + job.getFlexMillis());
+ Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
+ + formatForLogging(mFlexMillis) + ". Clamped to " +
+ formatForLogging(job.getFlexMillis()));
}
return job;
}
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index a88aa312550d..2937ccc879a5 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -47,20 +47,6 @@ public final class UsageStats implements Parcelable {
public long mLastTimeUsed;
/**
- * The last time the package was used via implicit, non-user initiated actions (service
- * was bound, etc).
- * {@hide}
- */
- public long mLastTimeSystemUsed;
-
- /**
- * Last time the package was used and the beginning of the idle countdown.
- * This uses a different timebase that is about how much the device has been in use in general.
- * {@hide}
- */
- public long mBeginIdleTime;
-
- /**
* {@hide}
*/
public long mTotalTimeInForeground;
@@ -89,8 +75,6 @@ public final class UsageStats implements Parcelable {
mTotalTimeInForeground = stats.mTotalTimeInForeground;
mLaunchCount = stats.mLaunchCount;
mLastEvent = stats.mLastEvent;
- mBeginIdleTime = stats.mBeginIdleTime;
- mLastTimeSystemUsed = stats.mLastTimeSystemUsed;
}
public String getPackageName() {
@@ -127,25 +111,6 @@ public final class UsageStats implements Parcelable {
}
/**
- * @hide
- * Get the last time this package was used by the system (not the user). This can be different
- * from {@link #getLastTimeUsed()} when the system binds to one of this package's services.
- * See {@link System#currentTimeMillis()}.
- */
- public long getLastTimeSystemUsed() {
- return mLastTimeSystemUsed;
- }
-
- /**
- * @hide
- * Get the last time this package was active, measured in milliseconds. This timestamp
- * uses a timebase that represents how much the device was used and not wallclock time.
- */
- public long getBeginIdleTime() {
- return mBeginIdleTime;
- }
-
- /**
* Get the total time this package spent in the foreground, measured in milliseconds.
*/
public long getTotalTimeInForeground() {
@@ -172,8 +137,6 @@ public final class UsageStats implements Parcelable {
// regards to their mEndTimeStamp.
mLastEvent = right.mLastEvent;
mLastTimeUsed = right.mLastTimeUsed;
- mBeginIdleTime = right.mBeginIdleTime;
- mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
@@ -195,8 +158,6 @@ public final class UsageStats implements Parcelable {
dest.writeLong(mTotalTimeInForeground);
dest.writeInt(mLaunchCount);
dest.writeInt(mLastEvent);
- dest.writeLong(mBeginIdleTime);
- dest.writeLong(mLastTimeSystemUsed);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -210,8 +171,6 @@ public final class UsageStats implements Parcelable {
stats.mTotalTimeInForeground = in.readLong();
stats.mLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
- stats.mBeginIdleTime = in.readLong();
- stats.mLastTimeSystemUsed = in.readLong();
return stats;
}
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 4135487a78d2..9221fbb50c96 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -148,8 +148,7 @@ public class ContentProviderClient implements AutoCloseable {
return null;
}
- if ("com.google.android.gms".equals(mPackageName)
- || "com.google.android.syncadapters.contacts".equals(mPackageName)) {
+ if ("com.google.android.gms".equals(mPackageName)) {
// They're casting to a concrete subclass, sigh
return cursor;
} else {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 83943ade7d82..7dc74010aa77 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8939,6 +8939,8 @@ public class Intent implements Parcelable, Cloneable {
case ACTION_MEDIA_SCANNER_STARTED:
case ACTION_MEDIA_SCANNER_FINISHED:
case ACTION_MEDIA_SCANNER_SCAN_FILE:
+ case ACTION_PACKAGE_NEEDS_VERIFICATION:
+ case ACTION_PACKAGE_VERIFIED:
// Ignore legacy actions
break;
default:
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 7db5a0889a35..be4f89567f51 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -715,7 +715,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* about setLocales() has changed locale directly. */
private void fixUpLocaleList() {
if ((locale == null && !mLocaleList.isEmpty()) ||
- (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
+ (locale != null && !locale.equals(mLocaleList.get(0)))) {
mLocaleList = new LocaleList(locale);
}
}
@@ -1269,7 +1269,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
localeArray[i] = Locale.forLanguageTag(source.readString());
}
mLocaleList = new LocaleList(localeArray);
- locale = mLocaleList.getPrimary();
+ locale = mLocaleList.get(0);
userSetLocale = (source.readInt()==1);
touchscreen = source.readInt();
@@ -1435,7 +1435,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public void setLocales(@Nullable LocaleList locales) {
mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
- locale = mLocaleList.getPrimary();
+ locale = mLocaleList.get(0);
setLayoutDirection(locale);
}
@@ -1900,7 +1900,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
- configOut.locale = configOut.mLocaleList.getPrimary();
+ configOut.locale = configOut.mLocaleList.get(0);
configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
TOUCHSCREEN_UNDEFINED);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 4967d05e2727..915fae0ff6b5 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -381,7 +381,7 @@ public class Resources {
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
}
return mPluralRule;
}
@@ -444,7 +444,7 @@ public class Resources {
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
+ return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
}
/**
@@ -475,7 +475,7 @@ public class Resources {
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
+ return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
}
/**
@@ -1971,7 +1971,7 @@ public class Resources {
}
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- adjustLanguageTag(locales.getPrimary().toLanguageTag()),
+ adjustLanguageTag(locales.get(0).toLanguageTag()),
mConfiguration.orientation,
mConfiguration.touchscreen,
mConfiguration.densityDpi, mConfiguration.keyboard,
@@ -1996,7 +1996,7 @@ public class Resources {
}
synchronized (sSync) {
if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
}
}
}
diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java
index b3e3ab6251c8..44871212daef 100644
--- a/core/java/android/nfc/tech/NfcF.java
+++ b/core/java/android/nfc/tech/NfcF.java
@@ -98,8 +98,13 @@ public final class NfcF extends BasicTagTechnology {
/**
* Send raw NFC-F commands to the tag and receive the response.
*
- * <p>Applications must not append the SoD (length) or EoD (CRC) to the payload,
- * it will be automatically calculated.
+ * <p>Applications must not prefix the SoD (preamble and sync code)
+ * and/or append the EoD (CRC) to the payload, it will be automatically calculated.
+ *
+ * <p>A typical NFC-F frame for this method looks like:
+ * <pre>
+ * LENGTH (1 byte) --- CMD (1 byte) -- IDm (8 bytes) -- PARAMS (LENGTH - 10 bytes)
+ * </pre>
*
* <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum amount of bytes
* that can be sent with {@link #transceive}.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 52fa2ed162f1..b33e807235bf 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -147,6 +147,11 @@ public abstract class BatteryStats implements Parcelable {
public static final int WAKE_TYPE_DRAW = 18;
/**
+ * A constant indicating a bluetooth scan timer.
+ */
+ public static final int BLUETOOTH_SCAN_ON = 19;
+
+ /**
* Include all of the data in the stats, including previously saved data.
*/
public static final int STATS_SINCE_CHARGED = 0;
@@ -438,6 +443,7 @@ public abstract class BatteryStats implements Parcelable {
public abstract Timer getFlashlightTurnedOnTimer();
public abstract Timer getCameraTurnedOnTimer();
public abstract Timer getForegroundActivityTimer();
+ public abstract Timer getBluetoothScanTimer();
// Time this uid has any processes in the top state.
public static final int PROCESS_STATE_TOP = 0;
@@ -1179,6 +1185,7 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE2_PHONE_IN_CALL_FLAG = 1<<23;
public static final int STATE2_BLUETOOTH_ON_FLAG = 1<<22;
public static final int STATE2_CAMERA_FLAG = 1<<21;
+ public static final int STATE2_BLUETOOTH_SCAN_FLAG = 1 << 20;
public static final int MOST_INTERESTING_STATES2 =
STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_MASK
@@ -1922,6 +1929,7 @@ public abstract class BatteryStats implements Parcelable {
HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT, "wifi_suppl", "Wsp",
WIFI_SUPPL_STATE_NAMES, WIFI_SUPPL_STATE_SHORT_NAMES),
new BitDescription(HistoryItem.STATE2_CAMERA_FLAG, "camera", "ca"),
+ new BitDescription(HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG, "ble_scan", "bles"),
};
public static final String[] HISTORY_EVENT_NAMES = new String[] {
@@ -2041,6 +2049,13 @@ public abstract class BatteryStats implements Parcelable {
*/
public abstract long getCameraOnTime(long elapsedRealtimeUs, int which);
+ /**
+ * Returns the time in microseconds that bluetooth scans were running while the device was
+ * on battery.
+ *
+ * {@hide}
+ */
+ public abstract long getBluetoothScanTime(long elapsedRealtimeUs, int which);
public static final int NETWORK_MOBILE_RX_DATA = 0;
public static final int NETWORK_MOBILE_TX_DATA = 1;
@@ -2797,9 +2812,12 @@ public abstract class BatteryStats implements Parcelable {
final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long btRxTotalBytes = getNetworkActivityBytes(NETWORK_BT_RX_DATA, which);
+ final long btTxTotalBytes = getNetworkActivityBytes(NETWORK_BT_TX_DATA, which);
dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA,
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
- mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets);
+ mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets,
+ btRxTotalBytes, btTxTotalBytes);
// Dump Modem controller stats
dumpControllerActivityLine(pw, 0 /* uid */, category, GLOBAL_MODEM_CONTROLLER_DATA,
@@ -3017,14 +3035,18 @@ public abstract class BatteryStats implements Parcelable {
final int mobileActiveCount = u.getMobileRadioActiveCount(which);
final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+ final long btBytesRx = u.getNetworkActivityBytes(NETWORK_BT_RX_DATA, which);
+ final long btBytesTx = u.getNetworkActivityBytes(NETWORK_BT_TX_DATA, which);
if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
|| mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
- || wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0) {
+ || wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0
+ || btBytesRx > 0 || btBytesTx > 0) {
dumpLine(pw, uid, category, NETWORK_DATA, mobileBytesRx, mobileBytesTx,
wifiBytesRx, wifiBytesTx,
mobilePacketsRx, mobilePacketsTx,
wifiPacketsRx, wifiPacketsTx,
- mobileActiveTime, mobileActiveCount);
+ mobileActiveTime, mobileActiveCount,
+ btBytesRx, btBytesTx);
}
// Dump modem controller data, per UID.
@@ -3046,6 +3068,9 @@ public abstract class BatteryStats implements Parcelable {
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
u.getWifiControllerActivity(), which);
+ dumpControllerActivityLine(pw, uid, category, BLUETOOTH_CONTROLLER_DATA,
+ u.getBluetoothControllerActivity(), which);
+
if (u.hasUserActivity()) {
args = new Object[Uid.NUM_USER_ACTIVITY_TYPES];
boolean hasData = false;
@@ -3668,6 +3693,12 @@ public abstract class BatteryStats implements Parcelable {
pw.print(" Bluetooth total received: "); pw.print(formatBytesLocked(btRxTotalBytes));
pw.print(", sent: "); pw.println(formatBytesLocked(btTxTotalBytes));
+ final long bluetoothScanTimeMs = getBluetoothScanTime(rawRealtime, which) / 1000;
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Bluetooth scan time: "); formatTimeMs(sb, bluetoothScanTimeMs);
+ pw.println(sb.toString());
+
printControllerActivity(pw, sb, prefix, "Bluetooth", getBluetoothControllerActivity(),
which);
@@ -3793,6 +3824,10 @@ public abstract class BatteryStats implements Parcelable {
pw.print(" wifi=");
printmAh(pw, bs.wifiPowerMah);
}
+ if (bs.bluetoothPowerMah != 0) {
+ pw.print(" bt=");
+ printmAh(pw, bs.bluetoothPowerMah);
+ }
if (bs.gpsPowerMah != 0) {
pw.print(" gps=");
printmAh(pw, bs.gpsPowerMah);
@@ -4035,6 +4070,9 @@ public abstract class BatteryStats implements Parcelable {
pw.println(" sent");
}
+ uidActivity |= printTimer(pw, sb, u.getBluetoothScanTimer(), rawRealtime, which, prefix,
+ "Bluetooth Scan");
+
if (u.hasUserActivity()) {
boolean hasData = false;
for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 344d06ec3143..24666fe71724 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -74,6 +74,9 @@ public final class UserHandle implements Parcelable {
/** @hide A user id constant to indicate the "system" user of the device */
public static final @UserIdInt int USER_SYSTEM = 0;
+ /** @hide A user serial constant to indicate the "system" user of the device */
+ public static final int USER_SERIAL_SYSTEM = 0;
+
/** @hide A user handle to indicate the "system" user of the device */
public static final UserHandle SYSTEM = new UserHandle(USER_SYSTEM);
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 9b3f02d69e9f..dd8eb5f2c634 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -1284,7 +1284,7 @@ public interface IMountService extends IInterface {
@Override
public void prepareUserStorage(
- String volumeUuid, int userId, int serialNumber, boolean ephemeral)
+ String volumeUuid, int userId, int serialNumber, int flags)
throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -1293,7 +1293,7 @@ public interface IMountService extends IInterface {
_data.writeString(volumeUuid);
_data.writeInt(userId);
_data.writeInt(serialNumber);
- _data.writeInt(ephemeral ? 1 : 0);
+ _data.writeInt(flags);
mRemote.transact(Stub.TRANSACTION_prepareUserStorage, _data, _reply, 0);
_reply.readException();
} finally {
@@ -2055,8 +2055,8 @@ public interface IMountService extends IInterface {
String volumeUuid = data.readString();
int userId = data.readInt();
int serialNumber = data.readInt();
- boolean ephemeral = data.readInt() != 0;
- prepareUserStorage(volumeUuid, userId, serialNumber, ephemeral);
+ int _flags = data.readInt();
+ prepareUserStorage(volumeUuid, userId, serialNumber, _flags);
reply.writeNoException();
return true;
}
@@ -2389,7 +2389,7 @@ public interface IMountService extends IInterface {
public boolean isUserKeyUnlocked(int userId) throws RemoteException;
public void prepareUserStorage(String volumeUuid, int userId, int serialNumber,
- boolean ephemeral) throws RemoteException;
+ int flags) throws RemoteException;
public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c8b942bb27de..b82638aa005b 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -92,8 +92,14 @@ public class StorageManager {
/** {@hide} */
public static final int DEBUG_EMULATE_FBE = 1 << 1;
+ // NOTE: keep in sync with installd
/** {@hide} */
- public static final int FLAG_FOR_WRITE = 1 << 0;
+ public static final int FLAG_STORAGE_DE = 1 << 0;
+ /** {@hide} */
+ public static final int FLAG_STORAGE_CE = 1 << 1;
+
+ /** {@hide} */
+ public static final int FLAG_FOR_WRITE = 1 << 8;
private final Context mContext;
private final ContentResolver mResolver;
@@ -1003,10 +1009,9 @@ public class StorageManager {
}
/** {@hide} */
- public void prepareUserStorage(
- String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
try {
- mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, ephemeral);
+ mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 7a9d0625c199..ea54f9203873 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -20,35 +20,126 @@ import android.net.Uri;
import android.os.Bundle;
/**
- * Constants and methods to access blocked phone numbers for incoming calls and texts.
+ * <p>
+ * The contract between the blockednumber provider and applications. Contains definitions for
+ * the supported URIs and columns.
+ * </p>
*
- * TODO javadoc
- * - Proper javadoc tagging.
- * - Code sample?
- * - Describe who can access it.
+ * <h3> Overview </h3>
+ * <p>
+ * The content provider exposes a table containing blocked numbers. The columns and URIs for
+ * accessing this table are defined by the {@link BlockedNumbers} class. Messages, and calls from
+ * blocked numbers are discarded by the platform. Notifications upon provider changes can be
+ * received using a {@link android.database.ContentObserver}.
+ * </p>
+ *
+ * <h3> Permissions </h3>
+ * <p>
+ * Only the system, the default SMS application, and the default phone app
+ * (See {@link android.telecom.TelecomManager#getDefaultDialerPackage()}), and carrier apps
+ * (See {@link android.service.carrier.CarrierService}) can read, and write to the blockednumber
+ * provider.
+ * </p>
+ *
+ * <h3> Data </h3>
+ * <p>
+ * Other than regular phone numbers, the blocked number provider can also store addresses (such
+ * as email) from which a user can receive messages, and calls. The blocked numbers are stored
+ * in the {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column. A normalized version of phone
+ * numbers (if normalization is possible) is stored in {@link BlockedNumbers#COLUMN_E164_NUMBER}
+ * column. The platform blocks calls, and messages from an address if it is present in in the
+ * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} column or if the E164 version of the address
+ * matches the {@link BlockedNumbers#COLUMN_E164_NUMBER} column.
+ * </p>
+ *
+ * <h3> Operations </h3>
+ * <dl>
+ * <dt><b>Insert</b></dt>
+ * <dd>
+ * <p>
+ * {@link BlockedNumbers#COLUMN_ORIGINAL_NUMBER} is a required column that needs to be populated.
+ * Apps can optionally provide the {@link BlockedNumbers#COLUMN_E164_NUMBER} which is the phone
+ * number's E164 representation. The provider automatically populates this column if the app does
+ * not provide it. Note that this column is not populated if normalization fails or if the address
+ * is not a phone number (eg: email). The provider enforces uniqueness constraint on this column.
+ * Examples:
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890");
+ * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
+ * </pre>
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890");
+ * values.put(BlockedNumbers.COLUMN_E164_NUMBER, "+11234567890");
+ * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
+ * </pre>
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "12345@abdcde.com");
+ * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
+ * </pre>
+ * </p>
+ * </dd>
+ * <dt><b>Update</b></dt>
+ * <dd>
+ * <p>
+ * Updates are not supported. Use Delete, and Insert instead.
+ * </p>
+ * </dd>
+ * <dt><b>Delete</b></dt>
+ * <dd>
+ * <p>
+ * Deletions can be performed as follows:
+ * <pre>
+ * ContentValues values = new ContentValues();
+ * values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890");
+ * Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
+ * getContentResolver().delete(uri, null, null);
+ * </pre>
+ * </p>
+ * </dd>
+ * <dt><b>Query</b></dt>
+ * <dd>
+ * <p>
+ * All blocked numbers can be enumerated as follows:
+ * <pre>
+ * Cursor c = getContentResolver().query(BlockedNumbers.CONTENT_URI,
+ * new String[]{BlockedNumbers.COLUMN_ID, BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
+ * BlockedNumbers.COLUMN_E164_NUMBER}, null, null, null);
+ * </pre>
+ * To check if a particular number is blocked, use the method
+ * {@link #isBlocked(Context, String)}.
+ * </p>
+ * </dd>
+ *
+ * <h3> Multi-user </h3>
+ * <p>
+ * Apps must use the method {@link #canCurrentUserBlockNumbers(Context)} before performing any
+ * operation on the blocked number provider. If {@link #canCurrentUserBlockNumbers(Context)} returns
+ * {@code false}, all operations on the provider will fail with an
+ * {@link UnsupportedOperationException}. The platform will block calls, and messages from numbers
+ * in the provider independent of the current user.
+ * </p>
*/
public class BlockedNumberContract {
private BlockedNumberContract() {
}
- /** The authority for the contacts provider */
+ /** The authority for the blocked number provider */
public static final String AUTHORITY = "com.android.blockednumber";
- /** A content:// style uri to the authority for the contacts provider */
+ /** A content:// style uri to the authority for the blocked number provider */
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
/**
- * TODO javadoc
- *
- * Constants to interact with the blocked phone number list.
+ * Constants to interact with the blocked numbers list.
*/
public static class BlockedNumbers {
private BlockedNumbers() {
}
/**
- * TODO javadoc
- *
* Content URI for the blocked numbers.
*
* Supported operations
@@ -117,8 +208,8 @@ public class BlockedNumberContract {
* context {@code context}, this method will throw an {@link UnsupportedOperationException}.
*/
public static boolean isBlocked(Context context, String phoneNumber) {
- final Bundle res = context.getContentResolver().call(AUTHORITY_URI,
- METHOD_IS_BLOCKED, phoneNumber, null);
+ final Bundle res = context.getContentResolver().call(
+ AUTHORITY_URI, METHOD_IS_BLOCKED, phoneNumber, null);
return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 330fcf6c4c74..dfdd36d2e9cf 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -2079,10 +2079,11 @@ public final class ContactsContract {
if (preferHighres) {
final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
Contacts.Photo.DISPLAY_PHOTO);
- InputStream inputStream;
try {
AssetFileDescriptor fd = cr.openAssetFileDescriptor(displayPhotoUri, "r");
- return fd.createInputStream();
+ if (fd != null) {
+ return fd.createInputStream();
+ }
} catch (IOException e) {
// fallback to the thumbnail code
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dfc86012c810..7830142d4e4b 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3869,7 +3869,6 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING);
MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED);
- MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_DENSITY_FORCED);
MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED);
MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE);
MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE);
@@ -5104,6 +5103,15 @@ public final class Settings {
"disabled_print_services";
/**
+ * The saved value for WindowManagerService.setForcedDisplayDensity()
+ * formatted as a single integer representing DPI. If unset, then use
+ * the real display density.
+ *
+ * @hide
+ */
+ public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
+
+ /**
* Setting to always use the default text-to-speech settings regardless
* of the application settings.
* 1 = override application settings,
@@ -6535,13 +6543,6 @@ public final class Settings {
public static final String DEVICE_PROVISIONED = "device_provisioned";
/**
- * The saved value for WindowManagerService.setForcedDisplayDensity().
- * One integer in dpi. If unset, then use the real display density.
- * @hide
- */
- public static final String DISPLAY_DENSITY_FORCED = "display_density_forced";
-
- /**
* The saved value for WindowManagerService.setForcedDisplaySize().
* Two integers separated by a comma. If unset, then use the real display size.
* @hide
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index a56e0301840f..fb58f4e519c3 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -45,7 +45,9 @@ import android.util.Log;
* &lt;action android:name="android.service.notification.NotificationAssistantService" />
* &lt;/intent-filter>
* &lt;/service></pre>
+ * @hide
*/
+@SystemApi
public abstract class NotificationAssistantService extends NotificationListenerService {
private static final String TAG = "NotificationAssistant";
@@ -210,29 +212,6 @@ public abstract class NotificationAssistantService extends NotificationListenerS
}
}
- /**
- * Add an annotation to a an existing notification. The delete intent will
- * be fired when the host notification is deleted, or when this annotation
- * is removed or replaced.
- *
- * @param key the key of the notification to be annotated
- * @param annotation the new annotation object
- */
- public final void setAnnotation(String key, Notification annotation)
- {
- // TODO: pack up the annotation and send it to the NotificationManager.
- }
-
- /**
- * Remove the annotation from a notification.
- *
- * @param key the key of the notification to be cleansed of annotatons
- */
- public final void clearAnnotation(String key)
- {
- // TODO: ask the NotificationManager to clear the annotation.
- }
-
private class NotificationAssistantWrapper extends NotificationListenerWrapper {
@Override
public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ed90e795af00..7ff883e1d127 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -695,7 +695,7 @@ public abstract class NotificationListenerService extends Service {
/**
* Request that the listener be rebound, after a previous call to (@link requestUnbind).
*
- * <P>This method will fail for assistants that have
+ * <P>This method will fail for listeners that have
* not been granted the permission by the user.
*
* <P>The service should wait for the {@link #onListenerConnected()} event
@@ -1022,8 +1022,7 @@ public abstract class NotificationListenerService extends Service {
}
/**
- * If the importance has been overriden by user preference, or by a
- * {@link NotificationAssistantService}, then this will be non-null,
+ * If the importance has been overriden by user preference, then this will be non-null,
* and should be displayed to the user.
*
* @return the explanation for the importance, or null if it is the natural importance
diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java
index 117de77442fb..4f687c857362 100644
--- a/core/java/android/text/style/LocaleSpan.java
+++ b/core/java/android/text/style/LocaleSpan.java
@@ -97,12 +97,12 @@ public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan {
* @return The {@link Locale} for this span. If multiple locales are associated with this
* span, only the first locale is returned. {@code null} if no {@link Locale} is specified.
*
- * @see LocaleList#getPrimary()
+ * @see LocaleList#get()
* @see #getLocales()
*/
@Nullable
public Locale getLocale() {
- return mLocales.getPrimary();
+ return mLocales.get(0);
}
/**
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 90a20bc2ab24..fc39004cf2cb 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -47,12 +47,7 @@ public final class LocaleList implements Parcelable {
private static final LocaleList sEmptyLocaleList = new LocaleList();
public Locale get(int location) {
- return location < mList.length ? mList[location] : null;
- }
-
- @Nullable
- public Locale getPrimary() {
- return mList.length == 0 ? null : get(0);
+ return (0 <= location && location < mList.length) ? mList[location] : null;
}
public boolean isEmpty() {
@@ -464,7 +459,7 @@ public final class LocaleList implements Parcelable {
// someone has called Locale.setDefault() since we last set or adjusted the default
// locale list. So let's recalculate the locale list.
if (sDefaultLocaleList != null
- && defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
+ && defaultLocale.equals(sDefaultLocaleList.get(0))) {
// The default Locale has changed, but it happens to be the first locale in the
// default locale list, so we don't need to construct a new locale list.
return sDefaultLocaleList;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 2aace0f30139..7017ff5a3fa0 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -136,6 +136,9 @@ public class RenderNode {
private RenderNode(String name, View owningView) {
mNativeRenderNode = nCreate(name);
mOwningView = owningView;
+ if (mOwningView instanceof SurfaceView) {
+ nRequestPositionUpdates(mNativeRenderNode, (SurfaceView) mOwningView);
+ }
}
/**
@@ -863,6 +866,8 @@ public class RenderNode {
private static native void nOutput(long renderNode);
private static native int nGetDebugSize(long renderNode);
+ private static native void nRequestPositionUpdates(long renderNode, SurfaceView callback);
+
///////////////////////////////////////////////////////////////////////////
// Animations
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 5b48e2893fc7..a2960515da08 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -135,7 +135,7 @@ public class SurfaceView extends View {
}
};
- final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
+ private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
= new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
@@ -143,6 +143,17 @@ public class SurfaceView extends View {
}
};
+ private final ViewTreeObserver.OnPreDrawListener mDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ // reposition ourselves where the surface is
+ mHaveFrame = getWidth() > 0 && getHeight() > 0;
+ updateWindow(false, false);
+ return true;
+ }
+ };
+
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
boolean mViewVisibility = false;
@@ -168,17 +179,9 @@ public class SurfaceView extends View {
boolean mUpdateWindowNeeded;
boolean mReportDrawNeeded;
private Translator mTranslator;
+ private int mWindowInsetLeft;
+ private int mWindowInsetTop;
- private final ViewTreeObserver.OnPreDrawListener mDrawListener =
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- // reposition ourselves where the surface is
- mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateWindow(false, false);
- return true;
- }
- };
private boolean mGlobalListenersAdded;
public SurfaceView(Context context) {
@@ -443,17 +446,17 @@ public class SurfaceView extends View {
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- getLocationInWindow(mLocation);
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
final boolean layoutSizeChanged = getWidth() != mLayout.width
|| getHeight() != mLayout.height;
- final boolean positionChanged = mWindowSpaceLeft != mLocation[0] || mWindowSpaceTop != mLocation[1];
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
+ getLocationInWindow(mLocation);
+
if (DEBUG) Log.i(TAG, "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged
@@ -643,24 +646,66 @@ public class SurfaceView extends View {
TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
" w=" + mLayout.width + " h=" + mLayout.height +
", frame=" + mSurfaceFrame);
- } else if (positionChanged || layoutSizeChanged) { // Only the position has changed
- mWindowSpaceLeft = mLocation[0];
- mWindowSpaceTop = mLocation[1];
- // For our size changed check, we keep mLayout.width and mLayout.height
- // in view local space.
- mLocation[0] = mLayout.width = getWidth();
- mLocation[1] = mLayout.height = getHeight();
+ } else if (!isHardwareAccelerated()) {
+ getLocationInWindow(mLocation);
+ final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
+ || mWindowSpaceTop != mLocation[1];
+ if (positionChanged || layoutSizeChanged) { // Only the position has changed
+ mWindowSpaceLeft = mLocation[0];
+ mWindowSpaceTop = mLocation[1];
+ // For our size changed check, we keep mLayout.width and mLayout.height
+ // in view local space.
+ mLocation[0] = mLayout.width = getWidth();
+ mLocation[1] = mLayout.height = getHeight();
- transformFromViewToWindowSpace(mLocation);
+ transformFromViewToWindowSpace(mLocation);
- try {
- mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
- mLocation[0], mLocation[1],
- viewRoot != null ? viewRoot.getNextFrameNumber() : -1,
- mWinFrame);
- } catch (RemoteException ex) {
- Log.e(TAG, "Exception from relayout", ex);
+ try {
+ Log.d(TAG, String.format("updateWindowPosition UI, " +
+ "postion = [%d, %d, %d, %d]", mWindowSpaceLeft, mWindowSpaceTop,
+ mLocation[0], mLocation[1]));
+ mSession.repositionChild(mWindow, mWindowSpaceLeft, mWindowSpaceTop,
+ mLocation[0], mLocation[1], -1, mWinFrame);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Exception from relayout", ex);
+ }
+ }
+ }
+ }
+
+ private Rect mRTLastReportedPosition = new Rect();
+
+ /**
+ * Called by native on RenderThread to update the window position
+ * @hide
+ */
+ public final void updateWindowPositionRT(long frameNumber,
+ int left, int top, int right, int bottom) {
+ IWindowSession session = mSession;
+ MyWindow window = mWindow;
+ if (session == null || window == null) {
+ // Guess we got detached, that sucks
+ return;
+ }
+ if (mRTLastReportedPosition.left == left
+ && mRTLastReportedPosition.top == top
+ && mRTLastReportedPosition.right == right
+ && mRTLastReportedPosition.bottom == bottom) {
+ return;
+ }
+ try {
+ if (DEBUG) {
+ Log.d(TAG, String.format("updateWindowPosition RT, frameNr = %d, " +
+ "postion = [%d, %d, %d, %d]", frameNumber, left, top,
+ right, bottom));
}
+ // Just using mRTLastReportedPosition as a dummy rect here
+ session.repositionChild(window, left, top, right, bottom, frameNumber,
+ mRTLastReportedPosition);
+ // Now overwrite mRTLastReportedPosition with our values
+ mRTLastReportedPosition.set(left, top, right, bottom);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Exception from repositionChild", ex);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4a0a0b0dbeb7..127157b11a91 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4506,9 +4506,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
break;
case R.styleable.View_pointerShape:
- final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED);
- if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) {
- setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape));
+ final int resourceId = a.getResourceId(attr, 0);
+ if (resourceId != 0) {
+ setPointerIcon(PointerIcon.loadCustomIcon(
+ context.getResources(), resourceId));
+ } else {
+ final int pointerShape = a.getInt(attr, PointerIcon.STYLE_NOT_SPECIFIED);
+ if (pointerShape != PointerIcon.STYLE_NOT_SPECIFIED) {
+ setPointerIcon(PointerIcon.getSystemIcon(context, pointerShape));
+ }
}
break;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 98e32891e033..96853e0fa775 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1811,7 +1811,9 @@ public final class ViewRootImpl implements ViewParent,
final boolean dragResizing = freeformResizing || dockedResizing;
if (mDragResizing != dragResizing) {
if (dragResizing) {
- startDragResizing(mPendingBackDropFrame);
+ startDragResizing(mPendingBackDropFrame,
+ mWinFrame.equals(mPendingBackDropFrame), mPendingVisibleInsets,
+ mPendingStableInsets);
mResizeMode = freeformResizing
? RESIZE_MODE_FREEFORM
: RESIZE_MODE_DOCKED_DIVIDER;
@@ -5845,9 +5847,11 @@ public final class ViewRootImpl implements ViewParent,
// Tell all listeners that we are resizing the window so that the chrome can get
// updated as fast as possible on a separate thread,
if (mDragResizing) {
+ boolean fullscreen = frame.equals(backDropFrame);
synchronized (mWindowCallbacks) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame);
+ mWindowCallbacks.get(i).onWindowSizeIsChanging(backDropFrame, fullscreen,
+ visibleInsets, stableInsets);
}
}
}
@@ -6815,20 +6819,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
- long getNextFrameNumber() {
- long frameNumber = -1;
- if (mSurfaceHolder != null) {
- mSurfaceHolder.mSurfaceLock.lock();
- }
- if (mSurface.isValid()) {
- frameNumber = mSurface.getNextFrameNumber();
- }
- if (mSurfaceHolder != null) {
- mSurfaceHolder.mSurfaceLock.unlock();
- }
- return frameNumber;
- }
-
class TakenSurfaceHolder extends BaseSurfaceHolder {
@Override
public boolean onAllowLockCanvas() {
@@ -7060,12 +7050,14 @@ public final class ViewRootImpl implements ViewParent,
/**
* Start a drag resizing which will inform all listeners that a window resize is taking place.
*/
- private void startDragResizing(Rect initialBounds) {
+ private void startDragResizing(Rect initialBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets) {
if (!mDragResizing) {
mDragResizing = true;
synchronized (mWindowCallbacks) {
for (int i = mWindowCallbacks.size() - 1; i >= 0; i--) {
- mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds);
+ mWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds, fullscreen,
+ systemInsets, stableInsets);
}
}
mFullRedrawNeeded = true;
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
index def02365dfed..d2bfca7e1c30 100644
--- a/core/java/android/view/WindowCallbacks.java
+++ b/core/java/android/view/WindowCallbacks.java
@@ -28,20 +28,30 @@ import android.graphics.Rect;
public interface WindowCallbacks {
/**
* Called by the system when the window got changed by the user, before the layouter got called.
- * It can be used to perform a "quick and dirty" resize which should never take more then 4ms to
- * complete.
+ * It also gets called when the insets changed, or when the window switched between a fullscreen
+ * layout or a non-fullscreen layout. It can be used to perform a "quick and dirty" resize which
+ * should never take more then 4ms to complete.
*
* <p>At the time the layouting has not happened yet.
*
* @param newBounds The new window frame bounds.
+ * @param fullscreen Whether the window is currently drawing in fullscreen.
+ * @param systemInsets The current visible system insets for the window.
+ * @param stableInsets The stable insets for the window.
*/
- void onWindowSizeIsChanging(Rect newBounds);
+ void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets);
/**
* Called when a drag resize starts.
+ *
* @param initialBounds The initial bounds where the window will be.
+ * @param fullscreen Whether the window is currently drawing in fullscreen.
+ * @param systemInsets The current visible system insets for the window.
+ * @param stableInsets The stable insets for the window.
*/
- void onWindowDragResizeStart(Rect initialBounds);
+ void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets);
/**
* Called when a drag resize ends.
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 89b1eb933025..c22d60d94818 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -268,4 +268,9 @@ public abstract class WindowManagerInternal {
/** Returns true if the stack with the input Id is currently visible. */
public abstract boolean isStackVisible(int stackId);
+
+ /**
+ * @return True if and only if the docked divider is currently in resize mode.
+ */
+ public abstract boolean isDockedDividerResizing();
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 4ca8971b34ab..9a6859387bdf 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -955,7 +955,7 @@ public abstract class AbsSeekBar extends ProgressBar {
if (!canUserSetProgress()) {
return false;
}
- int increment = Math.max(1, Math.round((float) getMax() / 5));
+ int increment = Math.max(1, Math.round((float) getMax() / 20));
if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
increment = -increment;
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index ee73092b3fb5..1321221eb89f 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2404,7 +2404,7 @@ public class GridView extends AbsListView {
}
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
- final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+ final boolean isHeading = lp != null && lp.viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
final boolean isSelected = isItemChecked(position);
final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
row, 1, column, 1, isHeading, isSelected);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index cf13a13cafb7..b0fb93b89052 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -761,6 +761,7 @@ public class ChooserActivity extends ResolverActivity {
public static final int TARGET_STANDARD = 2;
private static final int MAX_SERVICE_TARGETS = 8;
+ private static final int MAX_TARGETS_PER_SERVICE = 4;
private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
private final List<TargetInfo> mCallerTargets = new ArrayList<>();
@@ -925,7 +926,7 @@ public class ChooserActivity extends ResolverActivity {
final float parentScore = getScore(origTarget);
Collections.sort(targets, mBaseTargetComparator);
float lastScore = 0;
- for (int i = 0, N = targets.size(); i < N; i++) {
+ for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) {
final ChooserTarget target = targets.get(i);
float targetScore = target.getScore();
targetScore *= parentScore;
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index ec53a2ec6366..74fe94f96ddb 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -124,4 +124,5 @@ interface IBatteryStats {
void noteBleScanStarted(in WorkSource ws);
void noteBleScanStopped(in WorkSource ws);
+ void noteResetBleScan();
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 53e329d090cf..3fb768f68ee6 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -52,6 +52,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PatternMatcher;
import android.os.RemoteException;
+import android.os.StrictMode;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
@@ -173,6 +174,10 @@ public class ResolverActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
+ // We're dispatching intents that might be coming from legacy apps, so
+ // don't kill ourselves.
+ StrictMode.disableDeathOnFileUriExposure();
+
// Use a specialized prompt when we're handling the 'Home' app startActivity()
final Intent intent = makeMyIntent();
final Set<String> categories = intent.getCategories();
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 0ae21c61112f..03a3a3821f6a 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -52,7 +52,7 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12;
- private static final float RECENCY_MULTIPLIER = 3.f;
+ private static final float RECENCY_MULTIPLIER = 2.f;
private final Collator mCollator;
private final boolean mHttp;
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 049d3eb26409..d92e59691fe9 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -44,6 +44,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
public long wakeLockTimeMs;
public long cameraTimeMs;
public long flashlightTimeMs;
+ public long bluetoothRunningTimeMs;
public long mobileRxPackets;
public long mobileTxPackets;
@@ -56,6 +57,8 @@ public class BatterySipper implements Comparable<BatterySipper> {
public long mobileTxBytes;
public long wifiRxBytes;
public long wifiTxBytes;
+ public long btRxBytes;
+ public long btTxBytes;
public double percent;
public double noCoveragePercent;
public String[] mPackages;
@@ -71,6 +74,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
public double sensorPowerMah;
public double cameraPowerMah;
public double flashlightPowerMah;
+ public double bluetoothPowerMah;
public enum DrainType {
IDLE,
@@ -142,6 +146,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
wakeLockTimeMs += other.wakeLockTimeMs;
cameraTimeMs += other.cameraTimeMs;
flashlightTimeMs += other.flashlightTimeMs;
+ bluetoothRunningTimeMs += other.bluetoothRunningTimeMs;
mobileRxPackets += other.mobileRxPackets;
mobileTxPackets += other.mobileTxPackets;
mobileActive += other.mobileActive;
@@ -152,6 +157,8 @@ public class BatterySipper implements Comparable<BatterySipper> {
mobileTxBytes += other.mobileTxBytes;
wifiRxBytes += other.wifiRxBytes;
wifiTxBytes += other.wifiTxBytes;
+ btRxBytes += other.btRxBytes;
+ btTxBytes += other.btTxBytes;
wifiPowerMah += other.wifiPowerMah;
gpsPowerMah += other.gpsPowerMah;
cpuPowerMah += other.cpuPowerMah;
@@ -160,6 +167,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
wakeLockPowerMah += other.wakeLockPowerMah;
cameraPowerMah += other.cameraPowerMah;
flashlightPowerMah += other.flashlightPowerMah;
+ bluetoothPowerMah += other.bluetoothPowerMah;
}
/**
@@ -169,6 +177,6 @@ public class BatterySipper implements Comparable<BatterySipper> {
public double sumPower() {
return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
- flashlightPowerMah;
+ flashlightPowerMah + bluetoothPowerMah;
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e2ccaae1e87f..648b1a54927d 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -107,7 +107,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 140 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 141 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -186,8 +186,13 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public interface ExternalStatsSync {
- void scheduleSync(String reason);
- void scheduleWifiSync(String reason);
+ public static final int UPDATE_CPU = 0x01;
+ public static final int UPDATE_WIFI = 0x02;
+ public static final int UPDATE_RADIO = 0x04;
+ public static final int UPDATE_BT = 0x08;
+ public static final int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT;
+
+ void scheduleSync(String reason, int flags);
void scheduleCpuSyncDueToRemovedUid(int uid);
}
@@ -224,6 +229,7 @@ public final class BatteryStatsImpl extends BatteryStats {
final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mFlashlightTurnedOnTimers = new ArrayList<>();
final ArrayList<StopwatchTimer> mCameraTurnedOnTimers = new ArrayList<>();
+ final ArrayList<StopwatchTimer> mBluetoothScanOnTimers = new ArrayList<>();
// Last partial timers we use for distributing CPU usage.
final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<>();
@@ -435,6 +441,9 @@ public final class BatteryStatsImpl extends BatteryStats {
final StopwatchTimer[] mWifiSignalStrengthsTimer =
new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
+ int mBluetoothScanNesting;
+ StopwatchTimer mBluetoothScanTimer;
+
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTime;
StopwatchTimer mMobileRadioActiveTimer;
@@ -3714,7 +3723,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = true;
mWifiOnTimer.startRunningLocked(elapsedRealtime);
- scheduleSyncExternalWifiStatsLocked("wifi-off");
+ scheduleSyncExternalStatsLocked("wifi-off", ExternalStatsSync.UPDATE_WIFI);
}
}
@@ -3728,7 +3737,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(elapsedRealtime);
- scheduleSyncExternalWifiStatsLocked("wifi-on");
+ scheduleSyncExternalStatsLocked("wifi-on", ExternalStatsSync.UPDATE_WIFI);
}
}
@@ -3946,6 +3955,65 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ private void noteBluetoothScanStartedLocked(int uid) {
+ uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ if (mBluetoothScanNesting == 0) {
+ mHistoryCur.states2 |= HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan started for: "
+ + Integer.toHexString(mHistoryCur.states2));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ mBluetoothScanNesting++;
+ getUidStatsLocked(uid).noteBluetoothScanStartedLocked(elapsedRealtime);
+ }
+
+ public void noteBluetoothScanStartedFromSourceLocked(WorkSource ws) {
+ final int N = ws.size();
+ for (int i = 0; i < N; i++) {
+ noteBluetoothScanStartedLocked(ws.get(i));
+ }
+ }
+
+ private void noteBluetoothScanStoppedLocked(int uid) {
+ uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mBluetoothScanNesting--;
+ if (mBluetoothScanNesting == 0) {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "BLE scan stopped for: "
+ + Integer.toHexString(mHistoryCur.states2));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ }
+ getUidStatsLocked(uid).noteBluetoothScanStoppedLocked(elapsedRealtime);
+ }
+
+ public void noteBluetoothScanStoppedFromSourceLocked(WorkSource ws) {
+ final int N = ws.size();
+ for (int i = 0; i < N; i++) {
+ noteBluetoothScanStoppedLocked(ws.get(i));
+ }
+ }
+
+ public void noteResetBluetoothScanLocked() {
+ if (mBluetoothScanNesting > 0) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ mBluetoothScanNesting = 0;
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_BLUETOOTH_SCAN_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "BLE can stopped for: "
+ + Integer.toHexString(mHistoryCur.states2));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtime);
+ for (int i=0; i<mUidStats.size(); i++) {
+ BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+ uid.noteResetBluetoothScanLocked(elapsedRealtime);
+ }
+ }
+ }
+
public void noteWifiRadioPowerState(int powerState, long timestampNs) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
@@ -3980,7 +4048,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
- scheduleSyncExternalWifiStatsLocked("wifi-running");
+ scheduleSyncExternalStatsLocked("wifi-running", ExternalStatsSync.UPDATE_WIFI);
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
@@ -4019,7 +4087,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
- scheduleSyncExternalWifiStatsLocked("wifi-stopped");
+ scheduleSyncExternalStatsLocked("wifi-stopped", ExternalStatsSync.UPDATE_WIFI);
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
@@ -4034,7 +4102,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
- scheduleSyncExternalWifiStatsLocked("wifi-state");
+ scheduleSyncExternalStatsLocked("wifi-state", ExternalStatsSync.UPDATE_WIFI);
}
}
@@ -4530,6 +4598,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
+ public long getBluetoothScanTime(long elapsedRealtimeUs, int which) {
+ return mBluetoothScanTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+ }
+
+ @Override
public long getNetworkActivityBytes(int type, int which) {
if (type >= 0 && type < mNetworkByteActivityCounters.length) {
return mNetworkByteActivityCounters[type].getCountLocked(which);
@@ -4603,9 +4676,8 @@ public final class BatteryStatsImpl extends BatteryStats {
StopwatchTimer mVideoTurnedOnTimer;
StopwatchTimer mFlashlightTurnedOnTimer;
StopwatchTimer mCameraTurnedOnTimer;
-
-
StopwatchTimer mForegroundActivityTimer;
+ StopwatchTimer mBluetoothScanTimer;
int mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
StopwatchTimer[] mProcessStateTimer;
@@ -4997,6 +5069,30 @@ public final class BatteryStatsImpl extends BatteryStats {
return mForegroundActivityTimer;
}
+ public StopwatchTimer createBluetoothScanTimerLocked() {
+ if (mBluetoothScanTimer == null) {
+ mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
+ mBluetoothScanOnTimers, mOnBatteryTimeBase);
+ }
+ return mBluetoothScanTimer;
+ }
+
+ public void noteBluetoothScanStartedLocked(long elapsedRealtimeMs) {
+ createBluetoothScanTimerLocked().startRunningLocked(elapsedRealtimeMs);
+ }
+
+ public void noteBluetoothScanStoppedLocked(long elapsedRealtimeMs) {
+ if (mBluetoothScanTimer != null) {
+ mBluetoothScanTimer.stopRunningLocked(elapsedRealtimeMs);
+ }
+ }
+
+ public void noteResetBluetoothScanLocked(long elapsedRealtimeMs) {
+ if (mBluetoothScanTimer != null) {
+ mBluetoothScanTimer.stopAllRunningLocked(elapsedRealtimeMs);
+ }
+ }
+
@Override
public void noteActivityResumedLocked(long elapsedRealtimeMs) {
// We always start, since we want multiple foreground PIDs to nest
@@ -5110,6 +5206,11 @@ public final class BatteryStatsImpl extends BatteryStats {
return mForegroundActivityTimer;
}
+ @Override
+ public Timer getBluetoothScanTimer() {
+ return mBluetoothScanTimer;
+ }
+
void makeProcessState(int i, Parcel in) {
if (i < 0 || i >= NUM_PROCESS_STATE) return;
@@ -5335,6 +5436,9 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mForegroundActivityTimer != null) {
active |= !mForegroundActivityTimer.reset(false);
}
+ if (mBluetoothScanTimer != null) {
+ active |= !mBluetoothScanTimer.reset(false);
+ }
if (mProcessStateTimer != null) {
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (mProcessStateTimer[i] != null) {
@@ -5509,6 +5613,10 @@ public final class BatteryStatsImpl extends BatteryStats {
mForegroundActivityTimer.detach();
mForegroundActivityTimer = null;
}
+ if (mBluetoothScanTimer != null) {
+ mBluetoothScanTimer.detach();
+ mBluetoothScanTimer = null;
+ }
if (mUserActivityCounters != null) {
for (int i=0; i<NUM_USER_ACTIVITY_TYPES; i++) {
mUserActivityCounters[i].detach();
@@ -5669,6 +5777,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
+ if (mBluetoothScanTimer != null) {
+ out.writeInt(1);
+ mBluetoothScanTimer.writeToParcel(out, elapsedRealtimeUs);
+ } else {
+ out.writeInt(0);
+ }
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (mProcessStateTimer[i] != null) {
out.writeInt(1);
@@ -5874,6 +5988,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
mForegroundActivityTimer = null;
}
+ if (in.readInt() != 0) {
+ mBluetoothScanTimer = new StopwatchTimer(Uid.this, BLUETOOTH_SCAN_ON,
+ mBluetoothScanOnTimers, mOnBatteryTimeBase, in);
+ } else {
+ mBluetoothScanTimer = null;
+ }
mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
for (int i = 0; i < NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
@@ -7133,6 +7253,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase);
+ mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase);
mOnBattery = mOnBatteryInternal = false;
long uptime = SystemClock.uptimeMillis() * 1000;
long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -7732,6 +7853,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mVideoOnTimer.reset(false);
mFlashlightOnTimer.reset(false);
mCameraOnTimer.reset(false);
+ mBluetoothScanTimer.reset(false);
for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
mPhoneSignalStrengthsTimer[i].reset(false);
}
@@ -8264,41 +8386,168 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.d(TAG, "Updating bluetooth stats: " + info);
}
- if (info != null && mOnBatteryInternal) {
- mHasBluetoothReporting = true;
- mBluetoothActivity.getRxTimeCounter().addCountLocked(
- info.getControllerRxTimeMillis());
- mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
- info.getControllerTxTimeMillis());
- mBluetoothActivity.getIdleTimeCounter().addCountLocked(
- info.getControllerIdleTimeMillis());
+ if (info == null || !mOnBatteryInternal) {
+ return;
+ }
- // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
- final double opVolt = mPowerProfile.getAveragePower(
- PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
- if (opVolt != 0) {
- // We store the power drain as mAms.
- mBluetoothActivity.getPowerCounter().addCountLocked(
- (long) (info.getControllerEnergyUsed() / opVolt));
+ mHasBluetoothReporting = true;
+
+ final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+ final long rxTimeMs = info.getControllerRxTimeMillis();
+ final long txTimeMs = info.getControllerTxTimeMillis();
+
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "------ BEGIN BLE power blaming ------");
+ Slog.d(TAG, " Tx Time: " + txTimeMs + " ms");
+ Slog.d(TAG, " Rx Time: " + rxTimeMs + " ms");
+ Slog.d(TAG, " Idle Time: " + info.getControllerIdleTimeMillis() + " ms");
+ }
+
+ long totalScanTimeMs = 0;
+
+ final int uidCount = mUidStats.size();
+ for (int i = 0; i < uidCount; i++) {
+ final Uid u = mUidStats.valueAt(i);
+ if (u.mBluetoothScanTimer == null) {
+ continue;
}
- final UidTraffic[] uidTraffic = info.getUidTraffic();
- final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+ totalScanTimeMs += u.mBluetoothScanTimer.getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ }
+
+ final boolean normalizeScanRxTime = (totalScanTimeMs > rxTimeMs);
+ final boolean normalizeScanTxTime = (totalScanTimeMs > txTimeMs);
+
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "Normalizing scan power for RX=" + normalizeScanRxTime
+ + " TX=" + normalizeScanTxTime);
+ }
+
+ long leftOverRxTimeMs = rxTimeMs;
+ long leftOverTxTimeMs = txTimeMs;
+
+ for (int i = 0; i < uidCount; i++) {
+ final Uid u = mUidStats.valueAt(i);
+ if (u.mBluetoothScanTimer == null) {
+ continue;
+ }
+
+ long scanTimeSinceMarkMs = u.mBluetoothScanTimer.getTimeSinceMarkLocked(
+ elapsedRealtimeMs * 1000) / 1000;
+ if (scanTimeSinceMarkMs > 0) {
+ // Set the new mark so that next time we get new data since this point.
+ u.mBluetoothScanTimer.setMark(elapsedRealtimeMs);
+
+ long scanTimeRxSinceMarkMs = scanTimeSinceMarkMs;
+ long scanTimeTxSinceMarkMs = scanTimeSinceMarkMs;
+
+ if (normalizeScanRxTime) {
+ // Scan time is longer than the total rx time in the controller,
+ // so distribute the scan time proportionately. This means regular traffic
+ // will not blamed, but scans are more expensive anyways.
+ scanTimeRxSinceMarkMs = (rxTimeMs * scanTimeRxSinceMarkMs) / totalScanTimeMs;
+ }
+
+ if (normalizeScanTxTime) {
+ // Scan time is longer than the total tx time in the controller,
+ // so distribute the scan time proportionately. This means regular traffic
+ // will not blamed, but scans are more expensive anyways.
+ scanTimeTxSinceMarkMs = (txTimeMs * scanTimeTxSinceMarkMs) / totalScanTimeMs;
+ }
+
+ final ControllerActivityCounterImpl counter =
+ u.getOrCreateBluetoothControllerActivityLocked();
+ counter.getRxTimeCounter().addCountLocked(scanTimeRxSinceMarkMs);
+ counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
+
+ leftOverRxTimeMs -= scanTimeRxSinceMarkMs;
+ leftOverTxTimeMs -= scanTimeTxSinceMarkMs;
+ }
+ }
+
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "Left over time for traffic RX=" + leftOverRxTimeMs
+ + " TX=" + leftOverTxTimeMs);
+ }
+
+ //
+ // Now distribute blame to apps that did bluetooth traffic.
+ //
+
+ long totalTxBytes = 0;
+ long totalRxBytes = 0;
+
+ final UidTraffic[] uidTraffic = info.getUidTraffic();
+ final int numUids = uidTraffic != null ? uidTraffic.length : 0;
+ for (int i = 0; i < numUids; i++) {
+ final UidTraffic traffic = uidTraffic[i];
+
+ // Add to the global counters.
+ mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
+ traffic.getRxBytes());
+ mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
+ traffic.getTxBytes());
+
+ // Add to the UID counters.
+ final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
+ u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
+ u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
+
+ // Calculate the total traffic.
+ totalTxBytes += traffic.getTxBytes();
+ totalRxBytes += traffic.getRxBytes();
+ }
+
+ if ((totalTxBytes != 0 || totalRxBytes != 0) &&
+ (leftOverRxTimeMs != 0 || leftOverTxTimeMs != 0)) {
for (int i = 0; i < numUids; i++) {
final UidTraffic traffic = uidTraffic[i];
- // Add to the global counters.
- mNetworkByteActivityCounters[NETWORK_BT_RX_DATA].addCountLocked(
- traffic.getRxBytes());
- mNetworkByteActivityCounters[NETWORK_BT_TX_DATA].addCountLocked(
- traffic.getTxBytes());
-
- // Add to the UID counters.
final Uid u = getUidStatsLocked(mapUid(traffic.getUid()));
- u.noteNetworkActivityLocked(NETWORK_BT_RX_DATA, traffic.getRxBytes(), 0);
- u.noteNetworkActivityLocked(NETWORK_BT_TX_DATA, traffic.getTxBytes(), 0);
+ final ControllerActivityCounterImpl counter =
+ u.getOrCreateBluetoothControllerActivityLocked();
+
+ if (totalRxBytes > 0 && traffic.getRxBytes() > 0) {
+ final long timeRxMs = (leftOverRxTimeMs * traffic.getRxBytes()) / totalRxBytes;
+
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "UID=" + traffic.getUid() + " rx_bytes=" + traffic.getRxBytes()
+ + " rx_time=" + timeRxMs);
+ }
+ counter.getRxTimeCounter().addCountLocked(timeRxMs);
+ leftOverRxTimeMs -= timeRxMs;
+ }
+
+ if (totalTxBytes > 0 && traffic.getTxBytes() > 0) {
+ final long timeTxMs = (leftOverTxTimeMs * traffic.getTxBytes()) / totalTxBytes;
+
+ if (DEBUG_ENERGY) {
+ Slog.d(TAG, "UID=" + traffic.getUid() + " tx_bytes=" + traffic.getTxBytes()
+ + " tx_time=" + timeTxMs);
+ }
+
+ counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
+ leftOverTxTimeMs -= timeTxMs;
+ }
}
}
+
+ mBluetoothActivity.getRxTimeCounter().addCountLocked(
+ info.getControllerRxTimeMillis());
+ mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(
+ info.getControllerTxTimeMillis());
+ mBluetoothActivity.getIdleTimeCounter().addCountLocked(
+ info.getControllerIdleTimeMillis());
+
+ // POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
+ final double opVolt = mPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE) / 1000.0;
+ if (opVolt != 0) {
+ // We store the power drain as mAms.
+ mBluetoothActivity.getPowerCounter().addCountLocked(
+ (long) (info.getControllerEnergyUsed() / opVolt));
+ }
}
/**
@@ -8739,15 +8988,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- private void scheduleSyncExternalStatsLocked(String reason) {
- if (mExternalSync != null) {
- mExternalSync.scheduleSync(reason);
- }
- }
-
- private void scheduleSyncExternalWifiStatsLocked(String reason) {
+ private void scheduleSyncExternalStatsLocked(String reason, int updateFlags) {
if (mExternalSync != null) {
- mExternalSync.scheduleWifiSync(reason);
+ mExternalSync.scheduleSync(reason, updateFlags);
}
}
@@ -8815,7 +9058,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
// which will pull external stats.
- scheduleSyncExternalStatsLocked("battery-level");
+ scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL);
}
if (mHistoryCur.batteryStatus != status) {
mHistoryCur.batteryStatus = (byte)status;
@@ -9596,6 +9839,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mFlashlightOnTimer.readSummaryFromParcelLocked(in);
mCameraOnNesting = 0;
mCameraOnTimer.readSummaryFromParcelLocked(in);
+ mBluetoothScanNesting = 0;
+ mBluetoothScanTimer.readSummaryFromParcelLocked(in);
int NKW = in.readInt();
if (NKW > 10000) {
@@ -9666,6 +9911,9 @@ public final class BatteryStatsImpl extends BatteryStats {
if (in.readInt() != 0) {
u.createForegroundActivityTimerLocked().readSummaryFromParcelLocked(in);
}
+ if (in.readInt() != 0) {
+ u.createBluetoothScanTimerLocked().readSummaryFromParcelLocked(in);
+ }
u.mProcessState = ActivityManager.PROCESS_STATE_NONEXISTENT;
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (in.readInt() != 0) {
@@ -9928,6 +10176,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mNumConnectivityChange);
mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
mCameraOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
@@ -10021,6 +10270,12 @@ public final class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
+ if (u.mBluetoothScanTimer != null) {
+ out.writeInt(1);
+ u.mBluetoothScanTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+ } else {
+ out.writeInt(0);
+ }
for (int i = 0; i < Uid.NUM_PROCESS_STATE; i++) {
if (u.mProcessStateTimer[i] != null) {
out.writeInt(1);
@@ -10289,6 +10544,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
mCameraOnNesting = 0;
mCameraOnTimer = new StopwatchTimer(null, -13, null, mOnBatteryTimeBase, in);
+ mBluetoothScanNesting = 0;
+ mBluetoothScanTimer = new StopwatchTimer(null, -14, null, mOnBatteryTimeBase, in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
@@ -10436,6 +10693,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mUnpluggedNumConnectivityChange);
mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
mCameraOnTimer.writeToParcel(out, uSecRealtime);
+ mBluetoothScanTimer.writeToParcel(out, uSecRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
out.writeInt(mDischargeCurrentLevel);
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 531d1fac9991..2f383eacbac0 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -24,6 +24,8 @@ public class BluetoothPowerCalculator extends PowerCalculator {
private final double mIdleMa;
private final double mRxMa;
private final double mTxMa;
+ private double mAppTotalPowerMah = 0;
+ private long mAppTotalTimeMs = 0;
public BluetoothPowerCalculator(PowerProfile profile) {
mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
@@ -34,7 +36,31 @@ public class BluetoothPowerCalculator extends PowerCalculator {
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
- // No per-app distribution yet.
+
+ final BatteryStats.ControllerActivityCounter counter = u.getBluetoothControllerActivity();
+ if (counter == null) {
+ return;
+ }
+
+ final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
+ final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
+ final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
+ final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
+ double powerMah = counter.getPowerCounter().getCountLocked(statsType)
+ / (double)(1000*60*60);
+
+ if (powerMah == 0) {
+ powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
+ / (1000*60*60);
+ }
+
+ app.bluetoothPowerMah = powerMah;
+ app.bluetoothRunningTimeMs = totalTimeMs;
+ app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
+ app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
+
+ mAppTotalPowerMah += powerMah;
+ mAppTotalTimeMs += totalTimeMs;
}
@Override
@@ -56,12 +82,21 @@ public class BluetoothPowerCalculator extends PowerCalculator {
/ (1000*60*60);
}
+ // Subtract what the apps used, but clamp to 0.
+ powerMah = Math.max(0, powerMah - mAppTotalPowerMah);
+
if (DEBUG && powerMah != 0) {
Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs)
+ " power=" + BatteryStatsHelper.makemAh(powerMah));
}
- app.usagePowerMah = powerMah;
- app.usageTimeMs = totalTimeMs;
+ app.bluetoothPowerMah = powerMah;
+ app.bluetoothRunningTimeMs = Math.max(0, totalTimeMs - mAppTotalTimeMs);
+ }
+
+ @Override
+ public void reset() {
+ mAppTotalPowerMah = 0;
+ mAppTotalTimeMs = 0;
}
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 2a27f70ff05d..b4470397c67b 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -29,6 +29,7 @@ public class WifiPowerCalculator extends PowerCalculator {
private final double mTxCurrentMa;
private final double mRxCurrentMa;
private double mTotalAppPowerDrain = 0;
+ private long mTotalAppRunningTime = 0;
public WifiPowerCalculator(PowerProfile profile) {
mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
@@ -48,6 +49,8 @@ public class WifiPowerCalculator extends PowerCalculator {
final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
app.wifiRunningTimeMs = idleTime + rxTime + txTime;
+ mTotalAppRunningTime += app.wifiRunningTimeMs;
+
app.wifiPowerMah =
((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
/ (1000*60*60);
@@ -76,7 +79,9 @@ public class WifiPowerCalculator extends PowerCalculator {
final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
- app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs;
+
+ app.wifiRunningTimeMs = Math.max(0,
+ (idleTimeMs + rxTimeMs + txTimeMs) - mTotalAppRunningTime);
double powerDrainMah = counter.getPowerCounter().getCountLocked(statsType)
/ (double)(1000*60*60);
@@ -95,5 +100,6 @@ public class WifiPowerCalculator extends PowerCalculator {
@Override
public void reset() {
mTotalAppPowerDrain = 0;
+ mTotalAppRunningTime = 0;
}
}
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 5047c4c11889..69311938c5ad 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -24,7 +24,6 @@ import android.view.Choreographer;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import android.view.ThreadedRenderer;
-import android.view.View;
/**
* The thread which draws a fill in background while the app is resizing in areas where the app
@@ -49,6 +48,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
private final Rect mOldTargetRect = new Rect();
private final Rect mNewTargetRect = new Rect();
+
private Choreographer mChoreographer;
// Cached size values from the last render for the case that the view hierarchy is gone
@@ -66,15 +66,23 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
private Drawable mUserCaptionBackgroundDrawable;
private Drawable mResizingBackgroundDrawable;
private ColorDrawable mStatusBarColor;
+ private ColorDrawable mNavigationBarColor;
+ private boolean mOldFullscreen;
+ private boolean mFullscreen;
+ private final Rect mOldSystemInsets = new Rect();
+ private final Rect mOldStableInsets = new Rect();
+ private final Rect mSystemInsets = new Rect();
+ private final Rect mStableInsets = new Rect();
public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
- Drawable userCaptionBackgroundDrawable, int statusBarColor) {
+ Drawable userCaptionBackgroundDrawable, int statusBarColor, int navigationBarColor,
+ boolean fullscreen, Rect systemInsets, Rect stableInsets) {
setName("ResizeFrame");
mRenderer = renderer;
onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable,
- userCaptionBackgroundDrawable, statusBarColor);
+ userCaptionBackgroundDrawable, statusBarColor, navigationBarColor);
// Create a render node for the content and frame backdrop
// which can be resized independently from the content.
@@ -84,8 +92,14 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
// Set the initial bounds and draw once so that we do not get a broken frame.
mTargetRect.set(initialBounds);
+ mFullscreen = fullscreen;
+ mOldFullscreen = fullscreen;
+ mSystemInsets.set(systemInsets);
+ mStableInsets.set(stableInsets);
+ mOldSystemInsets.set(systemInsets);
+ mOldStableInsets.set(stableInsets);
synchronized (this) {
- changeWindowSizeLocked(initialBounds);
+ redrawLocked(initialBounds, fullscreen, mSystemInsets, mStableInsets);
}
// Kick off our draw thread.
@@ -94,7 +108,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable,
- int statusBarColor) {
+ int statusBarColor, int navigationBarColor) {
mDecorView = decorView;
mResizingBackgroundDrawable = resizingBackgroundDrawable;
mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
@@ -108,6 +122,12 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
} else {
mStatusBarColor = null;
}
+ if (navigationBarColor != 0) {
+ mNavigationBarColor = new ColorDrawable(navigationBarColor);
+ addSystemBarNodeIfNeeded();
+ } else {
+ mNavigationBarColor = null;
+ }
}
private void addSystemBarNodeIfNeeded() {
@@ -119,13 +139,22 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
}
/**
- * Call this function asynchronously when the window size has been changed. The change will
- * be picked up once per frame and the frame will be re-rendered accordingly.
+ * Call this function asynchronously when the window size has been changed or when the insets
+ * have changed or whether window switched between a fullscreen or non-fullscreen layout.
+ * The change will be picked up once per frame and the frame will be re-rendered accordingly.
+ *
* @param newTargetBounds The new target bounds.
+ * @param fullscreen Whether the window is currently drawing in fullscreen.
+ * @param systemInsets The current visible system insets for the window.
+ * @param stableInsets The stable insets for the window.
*/
- public void setTargetRect(Rect newTargetBounds) {
+ public void setTargetRect(Rect newTargetBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets) {
synchronized (this) {
+ mFullscreen = fullscreen;
mTargetRect.set(newTargetBounds);
+ mSystemInsets.set(systemInsets);
+ mStableInsets.set(stableInsets);
// Notify of a bounds change.
pingRenderLocked();
}
@@ -204,16 +233,23 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
return;
}
mNewTargetRect.set(mTargetRect);
- if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) {
+ if (!mNewTargetRect.equals(mOldTargetRect)
+ || mOldFullscreen != mFullscreen
+ || !mStableInsets.equals(mOldStableInsets)
+ || !mSystemInsets.equals(mOldSystemInsets)
+ || mReportNextDraw) {
+ mOldFullscreen = mFullscreen;
mOldTargetRect.set(mNewTargetRect);
- changeWindowSizeLocked(mNewTargetRect);
+ mOldSystemInsets.set(mSystemInsets);
+ mOldStableInsets.set(mStableInsets);
+ redrawLocked(mNewTargetRect, mFullscreen, mSystemInsets, mStableInsets);
}
}
}
/**
* The content is about to be drawn and we got the location of where it will be shown.
- * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call
+ * If a "redrawLocked" call has already been processed, we will re-issue the call
* if the previous call was ignored since the size was unknown.
* @param xOffset The x offset where the content is drawn to.
* @param yOffset The y offset where the content is drawn to.
@@ -235,8 +271,8 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
mLastYOffset,
mLastXOffset + mLastContentWidth,
mLastYOffset + mLastCaptionHeight + mLastContentHeight);
- // If this was the first call and changeWindowSizeLocked got already called prior
- // to us, we should re-issue a changeWindowSizeLocked now.
+ // If this was the first call and redrawLocked got already called prior
+ // to us, we should re-issue a redrawLocked now.
return firstCall
&& (mLastCaptionHeight != 0 || !mDecorView.isShowingCaption());
}
@@ -251,16 +287,20 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
}
/**
- * Resizing the frame to fit the new window size.
+ * Redraws the background, the caption and the system inset backgrounds if something changed.
+ *
* @param newBounds The window bounds which needs to be drawn.
+ * @param fullscreen Whether the window is currently drawing in fullscreen.
+ * @param systemInsets The current visible system insets for the window.
+ * @param stableInsets The stable insets for the window.
*/
- private void changeWindowSizeLocked(Rect newBounds) {
+ private void redrawLocked(Rect newBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets) {
// While a configuration change is taking place the view hierarchy might become
// inaccessible. For that case we remember the previous metrics to avoid flashes.
// Note that even when there is no visible caption, the caption child will exist.
final int captionHeight = mDecorView.getCaptionHeight();
- final int statusBarHeight = mDecorView.getStatusBarHeight();
// The caption height will probably never dynamically change while we are resizing.
// Once set to something other then 0 it should be kept that way.
@@ -302,14 +342,7 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
}
mFrameAndBackdropNode.end(canvas);
- if (mSystemBarBackgroundNode != null && mStatusBarColor != null) {
- canvas = mSystemBarBackgroundNode.start(width, height);
- mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
- mStatusBarColor.setBounds(0, 0, left + width, statusBarHeight);
- mStatusBarColor.draw(canvas);
- mSystemBarBackgroundNode.end(canvas);
- mRenderer.drawRenderNode(mSystemBarBackgroundNode);
- }
+ drawColorViews(left, top, width, height, fullscreen, systemInsets, stableInsets);
// We need to render the node explicitly
mRenderer.drawRenderNode(mFrameAndBackdropNode);
@@ -317,6 +350,39 @@ public class BackdropFrameRenderer extends Thread implements Choreographer.Frame
reportDrawIfNeeded();
}
+ private void drawColorViews(int left, int top, int width, int height,
+ boolean fullscreen, Rect systemInsets, Rect stableInsets) {
+ if (mSystemBarBackgroundNode == null) {
+ return;
+ }
+ DisplayListCanvas canvas = mSystemBarBackgroundNode.start(width, height);
+ mSystemBarBackgroundNode.setLeftTopRightBottom(left, top, left + width, top + height);
+ final int topInset = DecorView.getColorViewTopInset(mStableInsets.top, mSystemInsets.top);
+ final int bottomInset = DecorView.getColorViewBottomInset(stableInsets.bottom,
+ systemInsets.bottom);
+ final int rightInset = DecorView.getColorViewRightInset(stableInsets.right,
+ systemInsets.right);
+ if (mStatusBarColor != null) {
+ mStatusBarColor.setBounds(0, 0, left + width, topInset);
+ mStatusBarColor.draw(canvas);
+ }
+
+ // We only want to draw the navigation bar if our window is currently fullscreen because we
+ // don't want the navigation bar background be moving around when resizing in docked mode.
+ // However, we need it for the transitions into/out of docked mode.
+ if (mNavigationBarColor != null && fullscreen) {
+ final int size = DecorView.getNavBarSize(bottomInset, rightInset);
+ if (DecorView.isNavBarToRightEdge(bottomInset, rightInset)) {
+ mNavigationBarColor.setBounds(width - size, 0, width, height);
+ } else {
+ mNavigationBarColor.setBounds(0, height - size, width, height);
+ }
+ mNavigationBarColor.draw(canvas);
+ }
+ mSystemBarBackgroundNode.end(canvas);
+ mRenderer.drawRenderNode(mSystemBarBackgroundNode);
+ }
+
/** Notify view root that a frame has been drawn by us, if it has requested so. */
private void reportDrawIfNeeded() {
if (mReportNextDraw) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1a20e5ce5793..d4ada957a14a 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -922,6 +922,26 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return false;
}
+ static int getColorViewTopInset(int stableTop, int systemTop) {
+ return Math.min(stableTop, systemTop);
+ }
+
+ static int getColorViewBottomInset(int stableBottom, int systemBottom) {
+ return Math.min(stableBottom, systemBottom);
+ }
+
+ static int getColorViewRightInset(int stableRight, int systemRight) {
+ return Math.min(stableRight, systemRight);
+ }
+
+ static boolean isNavBarToRightEdge(int bottomInset, int rightInset) {
+ return bottomInset == 0 && rightInset > 0;
+ }
+
+ static int getNavBarSize(int bottomInset, int rightInset) {
+ return isNavBarToRightEdge(bottomInset, rightInset) ? rightInset : bottomInset;
+ }
+
WindowInsets updateColorViews(WindowInsets insets, boolean animate) {
WindowManager.LayoutParams attrs = mWindow.getAttributes();
int sysUiVisibility = attrs.systemUiVisibility | getWindowSystemUiVisibility();
@@ -933,11 +953,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
mLastWindowFlags = attrs.flags;
if (insets != null) {
- mLastTopInset = Math.min(insets.getStableInsetTop(),
+ mLastTopInset = getColorViewTopInset(insets.getStableInsetTop(),
insets.getSystemWindowInsetTop());
- mLastBottomInset = Math.min(insets.getStableInsetBottom(),
+ mLastBottomInset = getColorViewBottomInset(insets.getStableInsetBottom(),
insets.getSystemWindowInsetBottom());
- mLastRightInset = Math.min(insets.getStableInsetRight(),
+ mLastRightInset = getColorViewRightInset(insets.getStableInsetRight(),
insets.getSystemWindowInsetRight());
// Don't animate if the presence of stable insets has changed, because that
@@ -956,8 +976,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
mLastHasRightStableInset = hasRightStableInset;
}
- boolean navBarToRightEdge = mLastBottomInset == 0 && mLastRightInset > 0;
- int navBarSize = navBarToRightEdge ? mLastRightInset : mLastBottomInset;
+ boolean navBarToRightEdge = isNavBarToRightEdge(mLastBottomInset, mLastRightInset);
+ int navBarSize = getNavBarSize(mLastBottomInset, mLastRightInset);
updateColorViewInt(mNavigationColorViewState, sysUiVisibility,
mWindow.mNavigationBarColor, navBarSize, navBarToRightEdge,
0 /* rightInset */, animate && !disallowAnimate, false /* force */);
@@ -1041,14 +1061,14 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
*/
private void updateColorViewInt(final ColorViewState state, int sysUiVis, int color,
int size, boolean verticalBar, int rightMargin, boolean animate, boolean force) {
- state.present = size > 0 && (sysUiVis & state.systemUiHideFlag) == 0
+ state.present = (sysUiVis & state.systemUiHideFlag) == 0
&& (mWindow.getAttributes().flags & state.hideWindowFlag) == 0
&& ((mWindow.getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
|| force);
boolean show = state.present
&& (color & Color.BLACK) != 0
&& ((mWindow.getAttributes().flags & state.translucentFlag) == 0 || force);
- boolean showView = show && !isResizing();
+ boolean showView = show && !isResizing() && size > 0;
boolean visibilityChanged = false;
View view = state.view;
@@ -1672,7 +1692,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
- mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
+ mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
+ getCurrentColor(mNavigationColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
@@ -1854,14 +1875,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
@Override
- public void onWindowSizeIsChanging(Rect newBounds) {
+ public void onWindowSizeIsChanging(Rect newBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets) {
if (mBackdropFrameRenderer != null) {
- mBackdropFrameRenderer.setTargetRect(newBounds);
+ mBackdropFrameRenderer.setTargetRect(newBounds, fullscreen, systemInsets, stableInsets);
}
}
@Override
- public void onWindowDragResizeStart(Rect initialBounds) {
+ public void onWindowDragResizeStart(Rect initialBounds, boolean fullscreen, Rect systemInsets,
+ Rect stableInsets) {
if (mWindow.isDestroyed()) {
// If the owner's window is gone, we should not be able to come here anymore.
releaseThreadedRenderer();
@@ -1875,7 +1898,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
loadBackgroundDrawablesIfNeeded();
mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
- mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
+ mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState),
+ getCurrentColor(mNavigationColorViewState), fullscreen, systemInsets,
+ stableInsets);
// Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
// If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1971,10 +1996,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return isShowingCaption() ? mDecorCaptionView.getCaptionHeight() : 0;
}
- int getStatusBarHeight() {
- return mStatusColorViewState.view != null ? mStatusColorViewState.view.getHeight() : 0;
- }
-
/**
* Converts a DIP measure into physical pixels.
* @param dip The dip value.
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 3d5091a78687..bd01c73adf80 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -746,10 +746,12 @@ void RecyclingClippingPixelAllocator::copyIfNecessary() {
if (mNeedsCopy) {
SkPixelRef* recycledPixels = mRecycledBitmap->refPixelRef();
void* dst = recycledPixels->pixels();
- size_t dstRowBytes = mRecycledBitmap->rowBytes();
- size_t bytesToCopy = SkTMin(mRecycledBitmap->info().minRowBytes(),
+ const size_t dstRowBytes = mRecycledBitmap->rowBytes();
+ const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(),
mSkiaBitmap->info().minRowBytes());
- for (int y = 0; y < mRecycledBitmap->info().height(); y++) {
+ const int rowsToCopy = std::min(mRecycledBitmap->info().height(),
+ mSkiaBitmap->info().height());
+ for (int y = 0; y < rowsToCopy; y++) {
memcpy(dst, mSkiaBitmap->getAddr(0, y), bytesToCopy);
dst = SkTAddOffset<void>(dst, dstRowBytes);
}
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 35b5016e1b07..cf73316d494b 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -510,7 +510,7 @@ public:
size_t glyphCount = end - start;
- if (CC_UNLIKELY(canvas->isHighContrastText())) {
+ if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) {
// high contrast draw path
int color = paint.getColor();
int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color);
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index e88287644555..7314fbcd92d2 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -138,11 +138,6 @@ static jlong createGroup(JNIEnv*, jobject, jlong srcGroupPtr) {
return reinterpret_cast<jlong>(newGroup);
}
-static void deleteNode(JNIEnv*, jobject, jlong nodePtr) {
- VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
- delete node;
-}
-
static void setNodeName(JNIEnv* env, jobject, jlong nodePtr, jstring nameStr) {
VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
const char* nodeName = env->GetStringUTFChars(nameStr, NULL);
@@ -346,7 +341,6 @@ static const JNINativeMethod gMethods[] = {
{"nCreateClipPath", "!(J)J", (void*)createClipPath},
{"nCreateGroup", "!()J", (void*)createEmptyGroup},
{"nCreateGroup", "!(J)J", (void*)createGroup},
- {"nDestroy", "!(J)V", (void*)deleteNode},
{"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
{"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 4842e1bfa10f..e39bb1cb1a5a 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -205,8 +205,8 @@ nativeGetSensorAtIndex(JNIEnv *env, jclass clazz, jlong sensorManager, jobject s
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
Sensor const* const* sensorList;
- size_t count = mgr->getSensorList(&sensorList);
- if (size_t(index) >= count) {
+ ssize_t count = mgr->getSensorList(&sensorList);
+ if (ssize_t(index) >= count) {
return false;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index b1d4e2646ba4..a9003c1888d2 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "OpenGLRenderer"
+#define ATRACE_TAG ATRACE_TAG_VIEW
#include <EGL/egl.h>
@@ -24,7 +25,10 @@
#include <android_runtime/AndroidRuntime.h>
#include <Animator.h>
+#include <DamageAccumulator.h>
+#include <Matrix.h>
#include <RenderNode.h>
+#include <TreeInfo.h>
#include <Paint.h>
#include "core_jni_helpers.h"
@@ -462,6 +466,69 @@ static void android_view_RenderNode_endAllAnimators(JNIEnv* env, jobject clazz,
}
// ----------------------------------------------------------------------------
+// SurfaceView position callback
+// ----------------------------------------------------------------------------
+
+jmethodID gSurfaceViewPositionUpdateMethod;
+
+static void android_view_RenderNode_requestPositionUpdates(JNIEnv* env, jobject,
+ jlong renderNodePtr, jobject surfaceview) {
+ class SurfaceViewPositionUpdater : public RenderNode::PositionListener {
+ public:
+ SurfaceViewPositionUpdater(JNIEnv* env, jobject surfaceview) {
+ env->GetJavaVM(&mVm);
+ mWeakRef = env->NewWeakGlobalRef(surfaceview);
+ }
+
+ virtual ~SurfaceViewPositionUpdater() {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ }
+
+ virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
+ if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
+ ATRACE_NAME("Update SurfaceView position");
+
+ JNIEnv* env = jnienv();
+ jobject localref = env->NewLocalRef(mWeakRef);
+ if (CC_UNLIKELY(!localref)) {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ return;
+ }
+ Matrix4 transform;
+ info.damageAccumulator->computeCurrentTransform(&transform);
+ const RenderProperties& props = node.properties();
+ uirenderer::Rect bounds(props.getWidth(), props.getHeight());
+ transform.mapRect(bounds);
+ bounds.left -= info.windowInsetLeft;
+ bounds.right -= info.windowInsetLeft;
+ bounds.top -= info.windowInsetTop;
+ bounds.bottom -= info.windowInsetTop;
+ env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+ (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
+ (jint) bounds.right, (jint) bounds.bottom);
+ env->DeleteLocalRef(localref);
+ }
+
+ private:
+ JNIEnv* jnienv() {
+ JNIEnv* env;
+ if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm);
+ }
+ return env;
+ }
+
+ JavaVM* mVm;
+ jobject mWeakRef;
+ };
+
+ RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+ renderNode->setPositionListener(new SurfaceViewPositionUpdater(env, surfaceview));
+}
+
+// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -539,9 +606,14 @@ static const JNINativeMethod gMethods[] = {
{ "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator },
{ "nEndAllAnimators", "(J)V", (void*) android_view_RenderNode_endAllAnimators },
+
+ { "nRequestPositionUpdates", "(JLandroid/view/SurfaceView;)V", (void*) android_view_RenderNode_requestPositionUpdates },
};
int register_android_view_RenderNode(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
+ gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
+ "updateWindowPositionRT", "(JIIII)V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 8c907dd35a1e..acd0501362b5 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -134,7 +134,14 @@ public:
virtual void prepareTree(TreeInfo& info) {
info.errorHandler = this;
+ // TODO: This is hacky
+ info.windowInsetLeft = -stagingProperties().getLeft();
+ info.windowInsetTop = -stagingProperties().getTop();
+ info.updateWindowPositions = true;
RenderNode::prepareTree(info);
+ info.updateWindowPositions = false;
+ info.windowInsetLeft = 0;
+ info.windowInsetTop = 0;
info.errorHandler = NULL;
}
@@ -369,28 +376,28 @@ static void android_view_ThreadedRenderer_setName(JNIEnv* env, jobject clazz,
static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
- proxy->initialize(window);
+ sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
+ proxy->initialize(surface);
}
static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<ANativeWindow> window;
+ sp<Surface> surface;
if (jsurface) {
- window = android_view_Surface_getNativeWindow(env, jsurface);
+ surface = android_view_Surface_getSurface(env, jsurface);
}
- proxy->updateSurface(window);
+ proxy->updateSurface(surface);
}
static jboolean android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- sp<ANativeWindow> window;
+ sp<Surface> surface;
if (jsurface) {
- window = android_view_Surface_getNativeWindow(env, jsurface);
+ surface = android_view_Surface_getSurface(env, jsurface);
}
- return proxy->pauseSurface(window);
+ return proxy->pauseSurface(surface);
}
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cc489022345c..4cddb6c1bac4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2739,6 +2739,7 @@
android.service.notification.NotificationAssistantService},
to ensure that only the system can bind to it.
<p>Protection level: signature
+ @hide This is not a third-party API (intended for system apps). -->
-->
<permission android:name="android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE"
android:protectionLevel="signature" />
diff --git a/core/res/res/drawable/ic_close.xml b/core/res/res/drawable/ic_close.xml
new file mode 100644
index 000000000000..708695994ab6
--- /dev/null
+++ b/core/res/res/drawable/ic_close.xml
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FF000000"/>
+</vector>
diff --git a/core/res/res/drawable/ic_feedback.xml b/core/res/res/drawable/ic_feedback.xml
new file mode 100644
index 000000000000..b2d1cb80c9c1
--- /dev/null
+++ b/core/res/res/drawable/ic_feedback.xml
@@ -0,0 +1,27 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M0 0h24v24H0z"
+ android:fillColor="#00000000"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20.0,2.0L4.0,2.0c-1.1,0.0 -1.9,0.9 -1.99,2.0L2.0,22.0l4.0,-4.0l14.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L22.0,4.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0zm-7.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0zm0.0,-4.0l-2.0,0.0L11.0,6.0l2.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_refresh.xml b/core/res/res/drawable/ic_refresh.xml
new file mode 100644
index 000000000000..1f671684861f
--- /dev/null
+++ b/core/res/res/drawable/ic_refresh.xml
@@ -0,0 +1,27 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17.65,6.35C16.2,4.9 14.21,4.0 12.0,4.0c-4.42,0.0 -7.99,3.58 -7.99,8.0s3.57,8.0 7.99,8.0c3.73,0.0 6.84,-2.55 7.73,-6.0l-2.08,0.0c-0.82,2.33 -3.04,4.0 -5.65,4.0 -3.31,0.0 -6.0,-2.69 -6.0,-6.0s2.69,-6.0 6.0,-6.0c1.66,0.0 3.1,0.69 4.22,1.78L13.0,11.0l7.0,0.0L20.0,4.0l-2.35,2.35z"/>
+ <path
+ android:pathData="M0 0h24v24H0z"
+ android:fillColor="#00000000"/>
+</vector>
diff --git a/core/res/res/drawable/ic_schedule.xml b/core/res/res/drawable/ic_schedule.xml
new file mode 100644
index 000000000000..899dc821844e
--- /dev/null
+++ b/core/res/res/drawable/ic_schedule.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11.99,2.0C6.47,2.0 2.0,6.48 2.0,12.0s4.47,10.0 9.99,10.0C17.52,22.0 22.0,17.52 22.0,12.0S17.52,2.0 11.99,2.0zM12.0,20.0c-4.42,0.0 -8.0,-3.58 -8.0,-8.0s3.58,-8.0 8.0,-8.0 8.0,3.58 8.0,8.0 -3.58,8.0 -8.0,8.0z"/>
+ <path
+ android:pathData="M0 0h24v24H0z"
+ android:fillColor="#00000000"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12.5,7.0L11.0,7.0l0.0,6.0l5.25,3.1 0.75,-1.23 -4.5,-2.67z"/>
+</vector>
diff --git a/core/res/res/layout/app_anr_dialog.xml b/core/res/res/layout/app_anr_dialog.xml
index e8169ee1bc86..8bef116fa89e 100644
--- a/core/res/res/layout/app_anr_dialog.xml
+++ b/core/res/res/layout/app_anr_dialog.xml
@@ -18,28 +18,31 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="@dimen/dialog_list_padding_vertical_material"
+ android:paddingTop="@dimen/aerr_padding_list_top"
android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
- <TextView
+ <Button
android:id="@+id/aerr_close"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_close_app"
+ android:drawableStart="@drawable/ic_close"
style="@style/aerr_list_item" />
- <TextView
+ <Button
android:id="@+id/aerr_wait"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_wait"
+ android:drawableStart="@drawable/ic_schedule"
style="@style/aerr_list_item" />
- <TextView
+ <Button
android:id="@+id/aerr_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_report"
+ android:drawableStart="@drawable/ic_feedback"
style="@style/aerr_list_item" />
</LinearLayout>
diff --git a/core/res/res/layout/app_error_dialog.xml b/core/res/res/layout/app_error_dialog.xml
index 46a2b2af1a28..824f97f6585a 100644
--- a/core/res/res/layout/app_error_dialog.xml
+++ b/core/res/res/layout/app_error_dialog.xml
@@ -21,9 +21,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingTop="@dimen/dialog_list_padding_vertical_material"
- android:paddingBottom="@dimen/dialog_list_padding_vertical_material"
->
+ android:paddingTop="@dimen/aerr_padding_list_top"
+ android:paddingBottom="@dimen/dialog_list_padding_vertical_material">
<Button
@@ -31,6 +30,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_restart"
+ android:drawableStart="@drawable/ic_refresh"
style="@style/aerr_list_item"
/>
@@ -39,6 +39,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_reset"
+ android:drawableStart="@drawable/ic_refresh"
style="@style/aerr_list_item"
/>
@@ -47,6 +48,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_report"
+ android:drawableStart="@drawable/ic_feedback"
style="@style/aerr_list_item"
/>
@@ -55,6 +57,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_close"
+ android:drawableStart="@drawable/ic_close"
style="@style/aerr_list_item"
/>
@@ -63,6 +66,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/aerr_mute"
+ android:drawableStart="@drawable/ic_close"
style="@style/aerr_list_item"
/>
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 0a7ac776744a..305c8b0a0c0f 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -25,6 +25,7 @@
android:gravity="center"
android:paddingTop="8dp"
android:paddingBottom="8dp"
+ android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless">
<FrameLayout android:layout_width="wrap_content"
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index dd18544783a5..7399fa9d58ce 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -48,8 +48,6 @@
<color name="primary_text_default_material_light">#de000000</color>
<!-- 54% black -->
<color name="secondary_text_default_material_light">#8a000000</color>
- <!-- 38% black -->
- <color name="tertiary_text_default_material_light">#61000000</color>
<!-- 100% white -->
<color name="primary_text_default_material_dark">#ffffffff</color>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 7c6f3389c5d0..8e86f78e02fd 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -449,5 +449,7 @@
<item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+ <item type="dimen" name="aerr_padding_list_top">15dp</item>
+
<item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f0960c78d418..86b9f1d1b7d5 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1403,8 +1403,12 @@ please see styles_device_defaults.xml.
<item name="textAppearance">?attr/textAppearanceListItemSmall</item>
<item name="textColor">?attr/textColorAlertDialogListItem</item>
<item name="gravity">center_vertical</item>
- <item name="paddingStart">?attr/listPreferredItemPaddingStart</item>
- <item name="paddingEnd">?attr/listPreferredItemPaddingEnd</item>
+ <item name="paddingStart">?attr/dialogPreferredPadding</item>
+ <item name="paddingEnd">?attr/dialogPreferredPadding</item>
+ <item name="background">?attr/selectableItemBackground</item>
+ <item name="drawablePadding">32dp</item>
+ <item name="drawableTint">@color/accent_material_light</item>
+ <item name="drawableTintMode">src_atop</item>
</style>
<!-- Wifi dialog styles -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 0a52f41e3603..9efcfdace11b 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -444,7 +444,7 @@ please see styles_device_defaults.xml.
</style>
<style name="TextAppearance.Material.Notification.Info">
- <item name="textColor">@color/tertiary_text_default_material_light</item>
+ <item name="textColor">@color/secondary_text_default_material_light</item>
<item name="textSize">@dimen/notification_subtext_size</item>
</style>
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index 19ce44a90815..3feb0e905f1a 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -141,7 +141,7 @@ public abstract class BasePrintTest extends InstrumentationTestCase {
// Set to US locale.
Resources resources = getInstrumentation().getTargetContext().getResources();
Configuration oldConfiguration = resources.getConfiguration();
- if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) {
+ if (!oldConfiguration.getLocales().get(0).equals(Locale.US)) {
mOldLocale = oldConfiguration.getLocales();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
Configuration newConfiguration = new Configuration(oldConfiguration);
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index d2bd10613ded..de741b376d16 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -89,10 +89,7 @@ $(eval include $(BUILD_PREBUILT))
endef
font_src_files := \
- Clockopia.ttf \
- AndroidClock.ttf \
- AndroidClock_Highlight.ttf \
- AndroidClock_Solid.ttf
+ AndroidClock.ttf
$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
diff --git a/data/fonts/AndroidClock_Highlight.ttf b/data/fonts/AndroidClock_Highlight.ttf
deleted file mode 100644
index 923bb30a2328..000000000000
--- a/data/fonts/AndroidClock_Highlight.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/AndroidClock_Solid.ttf b/data/fonts/AndroidClock_Solid.ttf
deleted file mode 100644
index 923bb30a2328..000000000000
--- a/data/fonts/AndroidClock_Solid.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/Clockopia.ttf b/data/fonts/Clockopia.ttf
deleted file mode 100644
index 3f7b6aaa8c08..000000000000
--- a/data/fonts/Clockopia.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/MTLc3m.ttf b/data/fonts/MTLc3m.ttf
deleted file mode 100644
index e9018f62825e..000000000000
--- a/data/fonts/MTLc3m.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/MTLmr3m.ttf b/data/fonts/MTLmr3m.ttf
deleted file mode 100644
index 14f27d4f1847..000000000000
--- a/data/fonts/MTLmr3m.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 597a12245c11..acd785ede249 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -20,7 +20,4 @@ PRODUCT_COPY_FILES := \
PRODUCT_PACKAGES := \
DroidSansFallback.ttf \
DroidSansMono.ttf \
- Clockopia.ttf \
AndroidClock.ttf \
- AndroidClock_Highlight.ttf \
- AndroidClock_Solid.ttf \
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 961d0ebec7e4..dc302c719af7 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -344,6 +344,9 @@
<family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmoji.ttf</font>
</family>
+ <family>
+ <font weight="400" style="normal">DroidSansFallback.ttf</font>
+ </family>
<!--
Tai Le and Mongolian are intentionally kept last, to make sure they don't override
the East Asian punctuation for Chinese.
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index dfb8bb86f1e5..534121a2e361 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -459,7 +459,7 @@ public class Paint {
// setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
// ? HINTING_OFF : HINTING_ON);
mCompatScaling = mInvCompatScaling = 1;
- setTextLocales(LocaleList.getDefault());
+ setTextLocales(LocaleList.getAdjustedDefault());
}
/**
@@ -500,7 +500,7 @@ public class Paint {
mInvCompatScaling = 1;
mBidiFlags = BIDI_DEFAULT_LTR;
- setTextLocales(LocaleList.getDefault());
+ setTextLocales(LocaleList.getAdjustedDefault());
setElegantTextHeight(false);
mFontFeatureSettings = null;
}
@@ -1292,7 +1292,7 @@ public class Paint {
*/
@NonNull
public Locale getTextLocale() {
- return mLocales.getPrimary();
+ return mLocales.get(0);
}
/**
@@ -1317,7 +1317,7 @@ public class Paint {
if (locale == null) {
throw new IllegalArgumentException("locale cannot be null");
}
- if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.getPrimary())) {
+ if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.get(0))) {
return;
}
mLocales = new LocaleList(locale);
@@ -1340,8 +1340,8 @@ public class Paint {
* each language.
*
* By default, the text locale list is initialized to a one-member list just containing the
- * system locale (as returned by {@link LocaleList#getDefault()}). This assumes that the text to
- * be rendered will most likely be in the user's preferred language.
+ * system locales. This assumes that the text to be rendered will most likely be in the user's
+ * preferred language.
*
* If the actual language or languages of the text is/are known, then they can be provided to
* the text renderer using this method. The text renderer may attempt to guess the
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 40dbe2770e01..0cde0b990456 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -335,6 +335,21 @@ public final class Rect implements Parcelable {
}
/**
+ * Insets the rectangle on all sides specified by the insets.
+ * @hide
+ * @param left The amount to add from the rectangle's left
+ * @param top The amount to add from the rectangle's top
+ * @param right The amount to subtract from the rectangle's right
+ * @param bottom The amount to subtract from the rectangle's bottom
+ */
+ public void inset(int left, int top, int right, int bottom) {
+ this.left += left;
+ this.top += top;
+ this.right -= right;
+ this.bottom -= bottom;
+ }
+
+ /**
* Returns true if (x,y) is inside the rectangle. The left and top are
* considered to be inside, while the right and bottom are not. This means
* that for a x,y to be contained: left <= x < right and top <= y < bottom.
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 21ed7dd0099e..af8ccf5018b9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -25,6 +25,8 @@ import android.animation.ValueAnimator;
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
+import android.app.Application;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -35,6 +37,7 @@ import android.graphics.Insets;
import android.graphics.Outline;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
@@ -200,6 +203,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
mMutated = false;
}
+ /**
+ * In order to avoid breaking old apps, we only throw exception on invalid VectorDrawable
+ * animations * for apps targeting N and later. For older apps, we ignore (i.e. quietly skip)
+ * these animations.
+ *
+ * @return whether invalid animations for vector drawable should be ignored.
+ */
+ private static boolean shouldIgnoreInvalidAnimation() {
+ Application app = ActivityThread.currentApplication();
+ if (app == null || app.getApplicationInfo() == null) {
+ return true;
+ }
+ if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ return true;
+ }
+ return false;
+ }
+
@Override
public ConstantState getConstantState() {
mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations();
@@ -763,6 +784,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
private boolean mInitialized = false;
private boolean mAnimationPending = false;
private boolean mIsReversible = false;
+ // This needs to be set before parsing starts.
+ private boolean mShouldIgnoreInvalidAnim;
// TODO: Consider using NativeAllocationRegistery to track native allocation
private final VirtualRefBasePtr mSetRefBasePtr;
private WeakReference<RenderNode> mTarget = null;
@@ -782,6 +805,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
"re-initialized");
}
+ mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
parseAnimatorSet(set, 0);
mInitialized = true;
@@ -841,7 +865,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
} else if (target instanceof VectorDrawable.VFullPath) {
createRTAnimatorForFullPath(animator, (VectorDrawable.VFullPath) target,
startTime);
- } else {
+ } else if (!mShouldIgnoreInvalidAnim) {
throw new IllegalArgumentException("ClipPath only supports PathData " +
"property");
}
@@ -850,10 +874,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
} else if (target instanceof VectorDrawable.VectorDrawableState) {
createRTAnimatorForRootGroup(values, animator,
(VectorDrawable.VectorDrawableState) target, startTime);
- } else {
+ } else if (!mShouldIgnoreInvalidAnim) {
// Should never get here
- throw new UnsupportedOperationException("Target should be group, path or vector. " +
- target == null ? "Null target" : target.getClass() + " is not supported");
+ throw new UnsupportedOperationException("Target should be either VGroup, VPath, " +
+ "or ConstantState, " + target == null ? "Null target" : target.getClass() +
+ " is not supported");
}
}
@@ -912,8 +937,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
long nativePtr = target.getNativePtr();
if (mTmpValues.type == Float.class || mTmpValues.type == float.class) {
if (propertyId < 0) {
- throw new IllegalArgumentException("Property: " + mTmpValues
- .propertyName + " is not supported for FullPath");
+ if (mShouldIgnoreInvalidAnim) {
+ return;
+ } else {
+ throw new IllegalArgumentException("Property: " + mTmpValues.propertyName
+ + " is not supported for FullPath");
+ }
}
propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId,
(Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
@@ -922,9 +951,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId,
(Integer) mTmpValues.startValue, (Integer) mTmpValues.endValue);
} else {
- throw new UnsupportedOperationException("Unsupported type: " +
- mTmpValues.type + ". Only float, int or PathData value is " +
- "supported for Paths.");
+ if (mShouldIgnoreInvalidAnim) {
+ return;
+ } else {
+ throw new UnsupportedOperationException("Unsupported type: " +
+ mTmpValues.type + ". Only float, int or PathData value is " +
+ "supported for Paths.");
+ }
}
if (mTmpValues.dataSource != null) {
float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator
@@ -939,8 +972,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
long startTime) {
long nativePtr = target.getNativeRenderer();
if (!animator.getPropertyName().equals("alpha")) {
- throw new UnsupportedOperationException("Only alpha is supported for root " +
- "group");
+ if (mShouldIgnoreInvalidAnim) {
+ return;
+ } else {
+ throw new UnsupportedOperationException("Only alpha is supported for root "
+ + "group");
+ }
}
Float startValue = null;
Float endValue = null;
@@ -953,7 +990,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
}
}
if (startValue == null && endValue == null) {
- throw new UnsupportedOperationException("No alpha values are specified");
+ if (mShouldIgnoreInvalidAnim) {
+ return;
+ } else {
+ throw new UnsupportedOperationException("No alpha values are specified");
+ }
}
long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue);
createNativeChildAnimator(propertyPtr, startTime, animator);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f4bbc8c43d08..bdbf3c04b000 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -924,8 +924,11 @@ public class VectorDrawable extends Drawable {
private int mChangingConfigurations;
private int[] mThemeAttrs;
private String mGroupName = null;
- private long mNativePtr = 0;
+ // The native object will be created in the constructor and will be destroyed in native
+ // when the neither java nor native has ref to the tree. This pointer should be valid
+ // throughout this VGroup Java object's life.
+ private final long mNativePtr;
public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) {
mIsStateful = copy.mIsStateful;
@@ -1065,16 +1068,6 @@ public class VectorDrawable extends Drawable {
}
@Override
- protected void finalize() throws Throwable {
- if (mNativePtr != 0) {
- nDestroy(mNativePtr);
- mNativePtr = 0;
- }
- super.finalize();
- }
-
-
- @Override
public void applyTheme(Theme t) {
if (mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs,
@@ -1208,10 +1201,10 @@ public class VectorDrawable extends Drawable {
* Clip path, which only has name and pathData.
*/
private static class VClipPath extends VPath {
- long mNativePtr = 0;
+ private final long mNativePtr;
+
public VClipPath() {
mNativePtr = nCreateClipPath();
- // Empty constructor.
}
public VClipPath(VClipPath copy) {
@@ -1225,14 +1218,6 @@ public class VectorDrawable extends Drawable {
}
@Override
- protected void finalize() throws Throwable {
- if (mNativePtr != 0) {
- nDestroy(mNativePtr);
- mNativePtr = 0;
- }
- super.finalize();
- }
- @Override
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.VectorDrawableClipPath);
@@ -1317,10 +1302,9 @@ public class VectorDrawable extends Drawable {
ComplexColor mStrokeColors = null;
ComplexColor mFillColors = null;
- private long mNativePtr = 0;
+ private final long mNativePtr;
public VFullPath() {
- // Empty constructor.
mNativePtr = nCreateFullPath();
}
@@ -1384,15 +1368,6 @@ public class VectorDrawable extends Drawable {
a.recycle();
}
- @Override
- protected void finalize() throws Throwable {
- if (mNativePtr != 0) {
- nDestroy(mNativePtr);
- mNativePtr = 0;
- }
- super.finalize();
- }
-
private void updateStateFromTypedArray(TypedArray a) {
int byteCount = TOTAL_PROPERTY_COUNT * 4;
if (mPropertyData == null) {
@@ -1647,7 +1622,7 @@ public class VectorDrawable extends Drawable {
private static native void nDraw(long rendererPtr, long canvasWrapperPtr,
long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
private static native long nCreateFullPath();
- private static native long nCreateFullPath(long mNativeFullPathPtr);
+ private static native long nCreateFullPath(long nativeFullPathPtr);
private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
int length);
@@ -1663,7 +1638,6 @@ public class VectorDrawable extends Drawable {
private static native long nCreateGroup();
private static native long nCreateGroup(long groupPtr);
- private static native void nDestroy(long nodePtr);
private static native void nSetName(long nodePtr, String name);
private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
int length);
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index 7cf4b04cc996..d72688079d0e 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -269,7 +269,7 @@ public class KeyInfo implements KeySpec {
/**
* Returns {@code true} if the requirement that this key can only be used if the user has been
- * authenticated if enforced by secure hardware (e.g., Trusted Execution Environment (TEE) or
+ * authenticated is enforced by secure hardware (e.g., Trusted Execution Environment (TEE) or
* Secure Element (SE)).
*
* @see #isUserAuthenticationRequired()
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index c232bd1101a3..7b43947bc1e0 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -252,7 +252,8 @@ LOCAL_SRC_FILES += \
tests/unit/SkiaBehaviorTests.cpp \
tests/unit/StringUtilsTests.cpp \
tests/unit/TextDropShadowCacheTests.cpp \
- tests/unit/VectorDrawableTests.cpp
+ tests/unit/VectorDrawableTests.cpp \
+ tests/unit/GradientCacheTests.cpp
ifeq (true, $(HWUI_NEW_OPS))
LOCAL_SRC_FILES += \
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index e44fc20feaa8..250296ecc89f 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -57,7 +57,7 @@ public:
// Returns the current dirty area, *NOT* transformed by pushed transforms
void peekAtDirty(SkRect* dest) const;
- void computeCurrentTransform(Matrix4* outMatrix) const;
+ ANDROID_API void computeCurrentTransform(Matrix4* outMatrix) const;
void finish(SkRect* totalDirty);
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 044c7cb65718..11293d61211b 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -153,10 +153,13 @@ Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
texture->blend = info.hasAlpha;
texture->generation = 1;
- // Asume the cache is always big enough
+ // Assume the cache is always big enough
const uint32_t size = info.width * 2 * bytesPerPixel();
while (getSize() + size > mMaxSize) {
- mCache.removeOldest();
+ LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
+ "Ran out of things to remove from the cache? getSize() = %" PRIu32
+ ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
+ getSize(), size, mMaxSize, info.width);
}
generateTexture(colors, positions, info.width, 2, texture);
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index d4588edea207..bade216b3b21 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -381,6 +381,10 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
willHaveFunctor, functorsNeedLayer);
+ if (CC_UNLIKELY(mPositionListener.get())) {
+ mPositionListener->onPositionUpdated(*this, info);
+ }
+
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 8e4a3df271f5..f248de54acba 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -209,6 +209,19 @@ public:
OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
#endif
+ class ANDROID_API PositionListener {
+ public:
+ virtual ~PositionListener() {}
+ virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) = 0;
+ };
+
+ // Note this is not thread safe, this needs to be called
+ // before the RenderNode is used for drawing.
+ // RenderNode takes ownership of the pointer
+ ANDROID_API void setPositionListener(PositionListener* listener) {
+ mPositionListener.reset(listener);
+ }
+
private:
typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
@@ -317,6 +330,8 @@ private:
// This is *NOT* thread-safe, and should therefore only be tracking
// mDisplayList, not mStagingDisplayList.
uint32_t mParentCount;
+
+ std::unique_ptr<PositionListener> mPositionListener;
}; // class RenderNode
} /* namespace uirenderer */
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index be25516c587a..accd3038cb9c 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -86,6 +86,12 @@ public:
#endif
ErrorHandler* errorHandler = nullptr;
+ // Frame number for use with synchronized surfaceview position updating
+ int64_t frameNumber = -1;
+ int32_t windowInsetLeft = 0;
+ int32_t windowInsetTop = 0;
+ bool updateWindowPositions = false;
+
struct Out {
bool hasFunctors = false;
// This is only updated if evaluateAnimations is true
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 541c799f0149..2e3856fafb60 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -324,7 +324,7 @@ void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scale
// Save the current clip information, which is local to this group.
outCanvas->save();
// Draw the group tree in the same order as the XML file.
- for (Node* child : mChildren) {
+ for (auto& child : mChildren) {
child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
}
// Restore the previous clip information.
@@ -361,7 +361,7 @@ void Group::getLocalMatrix(SkMatrix* outMatrix) {
}
void Group::addChild(Node* child) {
- mChildren.push_back(child);
+ mChildren.emplace_back(child);
}
bool Group::getProperties(float* outProperties, int length) {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index f8f1ea62a624..36a8aebeaa33 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -316,7 +316,7 @@ private:
// Count of the properties, must be at the end.
Count,
};
- std::vector<Node*> mChildren;
+ std::vector< std::unique_ptr<Node> > mChildren;
Properties mProperties;
};
@@ -360,7 +360,7 @@ private:
float mViewportHeight = 0;
float mRootAlpha = 1.0f;
- Group* mRootNode;
+ std::unique_ptr<Group> mRootNode;
SkRect mBounds;
SkMatrix mCanvasMatrix;
SkPaint mPaint;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d4116218e5e1..ea702c01694e 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -92,18 +92,18 @@ void CanvasContext::destroy() {
}
}
-void CanvasContext::setSurface(ANativeWindow* window) {
+void CanvasContext::setSurface(Surface* surface) {
ATRACE_CALL();
- mNativeWindow = window;
+ mNativeSurface = surface;
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
}
- if (window) {
- mEglSurface = mEglManager.createSurface(window);
+ if (surface) {
+ mEglSurface = mEglManager.createSurface(surface);
}
if (mEglSurface != EGL_NO_SURFACE) {
@@ -127,8 +127,8 @@ void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
mSwapBehavior = swapBehavior;
}
-void CanvasContext::initialize(ANativeWindow* window) {
- setSurface(window);
+void CanvasContext::initialize(Surface* surface) {
+ setSurface(surface);
#if !HWUI_NEW_OPS
if (mCanvas) return;
mCanvas = new OpenGLRenderer(mRenderThread.renderState());
@@ -136,11 +136,11 @@ void CanvasContext::initialize(ANativeWindow* window) {
#endif
}
-void CanvasContext::updateSurface(ANativeWindow* window) {
- setSurface(window);
+void CanvasContext::updateSurface(Surface* surface) {
+ setSurface(surface);
}
-bool CanvasContext::pauseSurface(ANativeWindow* window) {
+bool CanvasContext::pauseSurface(Surface* surface) {
return mRenderThread.removeFrameCallback(this);
}
@@ -204,6 +204,10 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
info.renderer = mCanvas;
#endif
+ if (CC_LIKELY(mNativeSurface.get())) {
+ info.frameNumber = static_cast<int64_t>(mNativeSurface->getNextFrameNumber());
+ }
+
mAnimationContext->startFrame(info.mode);
for (const sp<RenderNode>& node : mRenderNodes) {
// Only the primary target node will be drawn full - all other nodes would get drawn in
@@ -219,7 +223,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
freePrefetechedLayers();
GL_CHECKPOINT(MODERATE);
- if (CC_UNLIKELY(!mNativeWindow.get())) {
+ if (CC_UNLIKELY(!mNativeSurface.get())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
return;
@@ -242,8 +246,9 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
} else {
// We're maybe behind? Find out for sure
int runningBehind = 0;
- mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+ // TODO: Have this method be on Surface, too, not just ANativeWindow...
+ ANativeWindow* window = mNativeSurface.get();
+ window->query(window, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
info.out.canDrawThisFrame = !runningBehind;
}
} else {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 63a7977f0cc9..168166ef5b23 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -39,6 +39,7 @@
#include <SkBitmap.h>
#include <SkRect.h>
#include <utils/Functor.h>
+#include <gui/Surface.h>
#include <set>
#include <string>
@@ -75,10 +76,10 @@ public:
// Won't take effect until next EGLSurface creation
void setSwapBehavior(SwapBehavior swapBehavior);
- void initialize(ANativeWindow* window);
- void updateSurface(ANativeWindow* window);
- bool pauseSurface(ANativeWindow* window);
- bool hasSurface() { return mNativeWindow.get(); }
+ void initialize(Surface* surface);
+ void updateSurface(Surface* surface);
+ bool pauseSurface(Surface* surface);
+ bool hasSurface() { return mNativeSurface.get(); }
void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
@@ -172,7 +173,7 @@ private:
// lifecycle tracking
friend class android::uirenderer::RenderState;
- void setSurface(ANativeWindow* window);
+ void setSurface(Surface* window);
void requireSurface();
void freePrefetechedLayers();
@@ -182,7 +183,7 @@ private:
RenderThread& mRenderThread;
EglManager& mEglManager;
- sp<ANativeWindow> mNativeWindow;
+ sp<Surface> mNativeSurface;
EGLSurface mEglSurface = EGL_NO_SURFACE;
bool mBufferPreserved = false;
SwapBehavior mSwapBehavior = kSwap_default;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 466fef9def09..364d4dda1e7f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -228,6 +228,13 @@ EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Failed to create EGLSurface for window %p, eglErr = %s",
(void*) window, egl_error_str());
+
+ if (mSwapBehavior != SwapBehavior::Preserved) {
+ LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) == EGL_FALSE,
+ "Failed to set swap behavior to destroyed for window %p, eglErr = %s",
+ (void*) window, egl_error_str());
+ }
+
return surface;
}
@@ -337,8 +344,8 @@ bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
// For some reason our surface was destroyed out from under us
// This really shouldn't happen, but if it does we can recover easily
// by just not trying to use the surface anymore
- ALOGW("swapBuffers encountered EGL_BAD_SURFACE on %p, halting rendering...",
- frame.mSurface);
+ ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...",
+ err, frame.mSurface);
return false;
}
LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering",
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 1d1b144bd47e..7c6cd7e014ef 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -139,38 +139,38 @@ void RenderProxy::setName(const char* name) {
postAndWait(task); // block since name/value pointers owned by caller
}
-CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
- args->context->initialize(args->window);
+CREATE_BRIDGE2(initialize, CanvasContext* context, Surface* surface) {
+ args->context->initialize(args->surface);
return nullptr;
}
-void RenderProxy::initialize(const sp<ANativeWindow>& window) {
+void RenderProxy::initialize(const sp<Surface>& surface) {
SETUP_TASK(initialize);
args->context = mContext;
- args->window = window.get();
+ args->surface = surface.get();
post(task);
}
-CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
- args->context->updateSurface(args->window);
+CREATE_BRIDGE2(updateSurface, CanvasContext* context, Surface* surface) {
+ args->context->updateSurface(args->surface);
return nullptr;
}
-void RenderProxy::updateSurface(const sp<ANativeWindow>& window) {
+void RenderProxy::updateSurface(const sp<Surface>& surface) {
SETUP_TASK(updateSurface);
args->context = mContext;
- args->window = window.get();
+ args->surface = surface.get();
postAndWait(task);
}
-CREATE_BRIDGE2(pauseSurface, CanvasContext* context, ANativeWindow* window) {
- return (void*) args->context->pauseSurface(args->window);
+CREATE_BRIDGE2(pauseSurface, CanvasContext* context, Surface* surface) {
+ return (void*) args->context->pauseSurface(args->surface);
}
-bool RenderProxy::pauseSurface(const sp<ANativeWindow>& window) {
+bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
SETUP_TASK(pauseSurface);
args->context = mContext;
- args->window = window.get();
+ args->surface = surface.get();
return (bool) postAndWait(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 4180d8020179..178724a85d04 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,9 +67,9 @@ public:
ANDROID_API bool loadSystemProperties();
ANDROID_API void setName(const char* name);
- ANDROID_API void initialize(const sp<ANativeWindow>& window);
- ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
- ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
+ ANDROID_API void initialize(const sp<Surface>& surface);
+ ANDROID_API void updateSurface(const sp<Surface>& surface);
+ ANDROID_API bool pauseSurface(const sp<Surface>& surface);
ANDROID_API void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp
new file mode 100644
index 000000000000..5ee17054183c
--- /dev/null
+++ b/libs/hwui/tests/unit/GradientCacheTests.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Extensions.h"
+#include "GradientCache.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+RENDERTHREAD_TEST(GradientCache, addRemove) {
+ Extensions extensions;
+ GradientCache cache(extensions);
+ cache.setMaxSize(5000);
+
+ SkColor colors[] = { 0xFF00FF00, 0xFFFF0000, 0xFF0000FF };
+ float positions[] = { 1, 2, 3 };
+ Texture* texture = cache.get(colors, positions, 3);
+ ASSERT_TRUE(texture);
+ ASSERT_FALSE(texture->cleanup);
+ ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
+ ASSERT_TRUE(cache.getSize());
+ cache.clear();
+ ASSERT_EQ(cache.getSize(), 0u);
+}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 3007d86afebc..b26b310a904b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1784,9 +1784,9 @@ public class AudioTrack implements AudioRouting
* Note that the actual playback of this data might occur after this function returns.
*
* @param audioData the array that holds the data to play.
- * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
+ * @param offsetInBytes the offset expressed in bytes in audioData where the data to write
* starts.
- * @param sizeInBytes the number of bytes to read in audioData after the offset.
+ * @param sizeInBytes the number of bytes to write in audioData after the offset.
* @return zero or the positive number of bytes that were written, or
* {@link #ERROR_INVALID_OPERATION}
* if the track isn't properly initialized, or {@link #ERROR_BAD_VALUE} if
@@ -1821,9 +1821,9 @@ public class AudioTrack implements AudioRouting
* Note that the actual playback of this data might occur after this function returns.
*
* @param audioData the array that holds the data to play.
- * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
+ * @param offsetInBytes the offset expressed in bytes in audioData where the data to write
* starts.
- * @param sizeInBytes the number of bytes to read in audioData after the offset.
+ * @param sizeInBytes the number of bytes to write in audioData after the offset.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
* <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -1920,8 +1920,8 @@ public class AudioTrack implements AudioRouting
* In static buffer mode, copies the data to the buffer starting at offset 0.
* Note that the actual playback of this data might occur after this function returns.
*
- * @param audioData the array that holds the data to play.
- * @param offsetInShorts the offset expressed in shorts in audioData where the data to play
+ * @param audioData the array that holds the data to write.
+ * @param offsetInShorts the offset expressed in shorts in audioData where the data to write
* starts.
* @param sizeInShorts the number of shorts to read in audioData after the offset.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
@@ -1987,7 +1987,7 @@ public class AudioTrack implements AudioRouting
* and the write mode is ignored.
* Note that the actual playback of this data might occur after this function returns.
*
- * @param audioData the array that holds the data to play.
+ * @param audioData the array that holds the data to write.
* The implementation does not clip for sample values within the nominal range
* [-1.0f, 1.0f], provided that all gains in the audio pipeline are
* less than or equal to unity (1.0f), and in the absence of post-processing effects
@@ -1998,8 +1998,8 @@ public class AudioTrack implements AudioRouting
* and later processing in the audio path. Therefore applications are encouraged
* to provide samples values within the nominal range.
* @param offsetInFloats the offset, expressed as a number of floats,
- * in audioData where the data to play starts.
- * @param sizeInFloats the number of floats to read in audioData after the offset.
+ * in audioData where the data to write starts.
+ * @param sizeInFloats the number of floats to write in audioData after the offset.
* @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
* effect in static mode.
* <br>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
@@ -2070,7 +2070,7 @@ public class AudioTrack implements AudioRouting
* and the write mode is ignored.
* Note that the actual playback of this data might occur after this function returns.
*
- * @param audioData the buffer that holds the data to play, starting at the position reported
+ * @param audioData the buffer that holds the data to write, starting at the position reported
* by <code>audioData.position()</code>.
* <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
* have been advanced to reflect the amount of data that was successfully written to
@@ -2137,7 +2137,7 @@ public class AudioTrack implements AudioRouting
/**
* Writes the audio data to the audio sink for playback in streaming mode on a HW_AV_SYNC track.
* The blocking behavior will depend on the write mode.
- * @param audioData the buffer that holds the data to play, starting at the position reported
+ * @param audioData the buffer that holds the data to write, starting at the position reported
* by <code>audioData.position()</code>.
* <BR>Note that upon return, the buffer position (<code>audioData.position()</code>) will
* have been advanced to reflect the amount of data that was successfully written to
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index f9fdd8daa89a..54543ec43f89 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -428,8 +428,17 @@ public class AudioMixingRule {
}
}
// rule didn't exist, add it
- // FIXME doesn't work with RULE_MATCH_UID yet
- mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ mCriteria.add(new AttributeMatchCriterion(attrToMatch, rule));
+ break;
+ case RULE_MATCH_UID:
+ mCriteria.add(new AttributeMatchCriterion(intProp, rule));
+ break;
+ default:
+ throw new IllegalStateException("Unreachable code in addRuleInternal()");
+ }
}
return this;
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 80b3ffc23e31..56b25144d948 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -117,6 +117,9 @@ public final class MediaBrowser {
* to the media browse service when connecting and retrieving the root id
* for browsing, or null if none. The contents of this bundle may affect
* the information returned when browsing.
+ * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
+ * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
+ * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
*/
public MediaBrowser(Context context, ComponentName serviceComponent,
ConnectionCallback callback, Bundle rootHints) {
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 0393c943784d..3372524d138c 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -351,6 +351,9 @@ public abstract class MediaBrowserService extends Service {
* root id for browsing, or null if none. The contents of this
* bundle may affect the information returned when browsing.
* @return The {@link BrowserRoot} for accessing this app's content or null.
+ * @see BrowserRoot#EXTRA_RECENT
+ * @see BrowserRoot#EXTRA_OFFLINE
+ * @see BrowserRoot#EXTRA_SUGGESTED
*/
public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
int clientUid, @Nullable Bundle rootHints);
@@ -667,6 +670,57 @@ public abstract class MediaBrowserService extends Service {
* when first connected.
*/
public static final class BrowserRoot {
+ /**
+ * The lookup key for a boolean that indicates whether the browser service should return a
+ * browser root for recently played media items.
+ *
+ * <p>When creating a media browser for a given media browser service, this key can be
+ * supplied as a root hint for retrieving media items that are recently played.
+ * If the media browser service can provide such media items, the implementation must return
+ * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+ *
+ * <p>The root hint may contain multiple keys.
+ *
+ * @see #EXTRA_OFFLINE
+ * @see #EXTRA_SUGGESTED
+ */
+ public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+
+ /**
+ * The lookup key for a boolean that indicates whether the browser service should return a
+ * browser root for offline media items.
+ *
+ * <p>When creating a media browser for a given media browser service, this key can be
+ * supplied as a root hint for retrieving media items that are can be played without an
+ * internet connection.
+ * If the media browser service can provide such media items, the implementation must return
+ * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+ *
+ * <p>The root hint may contain multiple keys.
+ *
+ * @see #EXTRA_RECENT
+ * @see #EXTRA_SUGGESTED
+ */
+ public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+
+ /**
+ * The lookup key for a boolean that indicates whether the browser service should return a
+ * browser root for suggested media items.
+ *
+ * <p>When creating a media browser for a given media browser service, this key can be
+ * supplied as a root hint for retrieving the media items suggested by the media browser
+ * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
+ * is considered ordered by relevance, first being the top suggestion.
+ * If the media browser service can provide such media items, the implementation must return
+ * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
+ *
+ * <p>The root hint may contain multiple keys.
+ *
+ * @see #EXTRA_RECENT
+ * @see #EXTRA_OFFLINE
+ */
+ public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+
final private String mRootId;
final private Bundle mExtras;
diff --git a/packages/DocumentsUI/res/drawable/cabinet.png b/packages/DocumentsUI/res/drawable/cabinet.png
deleted file mode 100644
index da440239cd0f..000000000000
--- a/packages/DocumentsUI/res/drawable/cabinet.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/cabinet.xml b/packages/DocumentsUI/res/drawable/cabinet.xml
new file mode 100644
index 000000000000..843ffc74e593
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/cabinet.xml
@@ -0,0 +1,81 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="672dp"
+ android:height="921dp"
+ android:viewportWidth="672.0"
+ android:viewportHeight="921.0">
+ <path
+ android:pathData="M286,0c5,0,10,0,15,0c0.1,1.8,1.5,1.8,2.8,2.1c11.1,2,22.1,4,33.2,6.1c31.8,6.1,63.7,12.3,95.5,18.5 c16.1,3.1,32.1,6.2,48.2,9.3c26,4.9,52.1,9.3,78,14.6c10.8,2.2,21.6,4.6,32.3,6.5c11.3,2,22.6,4.7,34,6c7.9,0.9,7.9,1.1,7.9,9.2 c0,237.3,0,474.5,0,711.8c-1.5,0.9,-3,2,-4.6,2.8c-18.3,8.3,-36.6,16.6,-54.8,25c-29.3,13.4,-58.5,26.8,-87.8,40.3 c-23.5,10.9,-47,21.8,-70.4,32.8c-2.1,1,-4.2,1.5,-6.3,1.1c-6.8,-1.3,-13.6,-2.5,-20.1,-4.9c5.9,-0.3,11.4,1.9,17.1,2.9c5.9,1.1,5.9,1,5.9,-4.9 c0,-17.1,0.1,-34.3,0,-51.4c-0.3,-68.9,-0.7,-137.8,-1,-206.7c0,-35.8,0,-71.6,0.1,-107.4c0,-3.8,-0.6,-5.2,-4.7,-3.7c-7.9,2.9,-16,5.4,-24.1,7.8 c-14.1,4.3,-27.8,10,-42.2,13.2c0,-64,0,-127.9,-0.1,-191.9c0,-4.1,1.3,-5.9,5.1,-7c21,-6.6,42,-13.4,63,-20.2c2.3,-0.8,4.4,-1.8,4,-4.9 c0,-59.3,0,-118.7,0,-178c0,-1.3,-0.7,-2,-2,-2c-2.6,-0.4,-5.2,-0.7,-7.8,-1.2c-30.2,-5.3,-60.5,-10.6,-90.7,-16c-31.9,-5.6,-63.7,-11.3,-95.6,-16.9 c-24.9,-4.4,-49.8,-8.7,-74.6,-13.1C117.1,75.6,93.1,71.3,69,67c-0.3,-0.3,-0.7,-0.7,-1,-1c17.4,-5.3,34.8,-10.7,52.3,-15.9 c29.4,-8.7,58.8,-17.2,88.2,-25.8c24.3,-7.1,48.6,-14.2,72.9,-21.4C283.1,2.4,285.6,2.7,286,0z"
+ android:fillColor="#EFEFEE"/>
+ <path
+ android:pathData="M412,307c0.4,3,-1.7,4.1,-4,4.9c-21,6.8,-42,13.6,-63,20.2c-3.8,1.2,-5.1,3,-5.1,7C340,403.1,340,467,340,531 c-11.8,-1.2,-23.3,-4.5,-34.9,-6.5c-10,-1.7,-19.9,-4.6,-30.1,-5.5c-0.7,-0.3,-1.4,-0.9,-2.2,-1c-19.8,-4,-39.5,-8,-59.3,-12c-12.2,-2.4,-24.3,-4.7,-36.5,-7 c-0.9,-0.3,-1.8,-0.8,-2.8,-1c-24.5,-4.9,-48.9,-9.9,-73.5,-14.6C89.3,481.3,78,477.1,66,478c-0.7,-1.6,-2.1,-1.8,-3.6,-2.1 c-11.1,-2.2,-22.2,-4.7,-33.3,-6.7c-9.7,-1.7,-19.1,-4.9,-29.1,-5.3c0,-64.3,0,-128.7,0,-193c0.8,-0.2,1.6,-0.4,2.4,-0.7c19,-7.8,37.9,-15.9,57.1,-23.4 c5.4,-2.1,6.7,-4.8,6.6,-10.2c-0.2,-55.1,-0.1,-110.2,-0.1,-165.4c0,-1.9,-1.4,-4.6,1.9,-5.4c0.3,0.3,0.7,0.7,1,1c-1.3,4.9,-1,9.9,-1,14.9 c0,51.1,0,102.3,0,153.4c0,1.2,0,2.3,0,3.5c0.1,3.5,1.2,5.9,5.3,6.5c7,1.1,14,2.6,21,3.9c22.1,4.3,44.1,8.6,66.2,12.8 c27.3,5.2,54.6,10.1,81.9,15.3c21.8,4.1,43.5,8.5,65.2,12.6c28.1,5.4,56.2,10.8,84.3,15.8C398.4,306.8,405.1,310.5,412,307z M105,329c0,3.3,0,6.7,-0.1,10c-0.1,2.5,0.4,3.6,3.4,4.2c30,5.3,59.9,10.9,89.8,16.5c3.4,0.6,5.1,0.2,4.9,-3.7 c-0.2,-3.3,-0.1,-6.7,-0.1,-10c0.5,-3.6,-0.1,-6.3,-4.7,-6.1c-1.1,0.1,-2.2,-0.6,-3.4,-0.8c-28.3,-5,-56.6,-9.9,-84.9,-14.9 C105.6,323.4,104.5,325.2,105,329z M65.9,280.8c13.7,2.5,27.4,4.9,41.1,7.4c32.6,5.9,65.2,11.8,97.8,17.8 c41.4,7.6,82.8,15.2,124.2,22.8c6.8,1.2,13.3,1.4,20,-1.3c9.3,-3.6,18.9,-6.3,28.4,-9.4c6.4,-2.1,12.8,-4.2,19.2,-6.4 c-4.2,-2,-8.3,-3,-12.4,-3.8c-22.6,-4.2,-45.3,-8,-67.9,-12.6c-14.6,-3,-29.2,-5.6,-43.8,-8.5c-24,-4.6,-48,-9.2,-72,-13.7c-15.9,-3,-31.8,-6.2,-47.8,-9.2 c-19,-3.6,-38,-7.3,-57,-10.6c-9.9,-1.7,-19.6,-4.5,-29.7,-5.2C48,255.6,30.1,263,12.2,270.4c0,0.4,0,0.7,0,1.1 C30.1,274.6,48,277.7,65.9,280.8z"
+ android:fillColor="#EAEAEA"/>
+ <path
+ android:pathData="M672,782c-6,0.9,-11.1,4.3,-16.4,6.9c-30.8,15,-61.5,30.3,-92.3,45.4c-34.8,17.1,-69.5,34.3,-104.5,51.1 c-13,6.3,-26,12.8,-39,19.1c-1.5,0.7,-3.7,1,-3.9,3.4c-3.7,0,-7.3,0,-11,0c-0.4,-3,-3.1,-2.3,-4.7,-2.7c-19.3,-4.8,-38.6,-9.5,-57.9,-14.1 c-27.5,-6.5,-55.2,-12.7,-82.6,-19.4c-30.9,-7.5,-61.8,-15,-92.7,-22.1c-24.8,-5.8,-49.5,-12,-74.3,-18C70.8,826.5,48.9,821.3,27,816 c-1.1,-0.3,-2.3,-0.5,-3.3,-1c-3.2,-1.3,-3.5,-3.3,-0.7,-5.4c0.9,-0.7,2,-1.2,3.1,-1.7c12,-5.3,24,-10.7,36,-16c0.4,-0.2,0.9,-0.2,1.9,-0.3 c0,3.6,0,7,0,10.5c0,1.6,-0.5,3.5,2,3.9c0.7,2.8,3.2,2.5,5.2,3c39.3,9,78.7,18.1,118.1,27c43.9,10,87.7,20,131.6,29.9 c9.7,2.2,19.2,4.9,29.1,6c1.1,1.5,2.6,0.9,4,1l0,0c4.1,2,8.5,2.6,13,3l0,0c7.2,2.4,14.4,4.3,22,5l0,0c6.5,2.5,13.3,3.6,20.1,4.9 c2.1,0.4,4.2,-0.1,6.3,-1.1c23.5,-11,46.9,-21.9,70.4,-32.8c29.2,-13.5,58.5,-26.9,87.8,-40.3c18.3,-8.4,36.6,-16.6,54.8,-25 c1.6,-0.7,3.1,-1.9,4.6,-2.8c2,-2.9,1.1,-6.2,0.9,-9.2c-0.3,-4.7,1.9,-5.5,5.7,-4.7c10.8,2.2,21.6,4.6,32.5,6.9C672,778.7,672,780.3,672,782z "
+ android:fillColor="#E6E4E4"/>
+ <path
+ android:pathData="M350,872c-9.9,-1.1,-19.4,-3.9,-29.1,-6C277,856,233.1,846,189.2,836c-39.4,-9,-78.7,-18,-118.1,-27 c-2,-0.4,-4.5,-0.2,-5.2,-3c0,-85.7,0,-171.4,0.1,-257.1c6.5,0.1,12.7,2.3,19,3.6c26.4,5.4,52.8,10.9,79.2,16.5c25.9,5.4,51.8,11,77.7,16.4 c26.2,5.5,52.5,11,78.7,16.5c30.1,6.3,60.2,12.6,90.3,19c0.3,68.9,0.7,137.8,1,206.7c0.1,17.1,0,34.3,0,51.4c0,5.9,0,6,-5.9,4.9 c-5.7,-1.1,-11.2,-3.2,-17.1,-2.9c0,0,0,0,0,0c-7,-3.1,-14.2,-5.4,-22,-5c0,0,0,0,0,0c-3.9,-2.9,-8.4,-2.9,-13,-3c0,0,0,0,0,0 C352.9,871.5,351.4,872.1,350,872z M177,687c0,3.2,0.1,6.3,0,9.5c-0.1,2.7,0.7,4,3.8,4.6c29.7,5.8,59.3,11.7,89,17.7 c2.4,0.5,4.7,0.1,4.9,-2.6c0.4,-3.7,1.2,-7.6,-0.6,-11.2c1,-3,1.2,-5.3,-3,-6c-29.6,-5.4,-59.2,-10.8,-88.7,-16.5C177.7,681.6,176.5,682.8,177,687 z"
+ android:fillColor="#E5E5E5"/>
+ <path
+ android:pathData="M411,621c-30.1,-6.3,-60.2,-12.6,-90.3,-19c-26.2,-5.5,-52.5,-11,-78.7,-16.5c-25.9,-5.5,-51.8,-11,-77.7,-16.4 c-26.4,-5.5,-52.8,-11.1,-79.2,-16.5c-6.3,-1.3,-12.5,-3.5,-19,-3.6c0,-23.6,0,-47.3,0,-70.9c12,-0.9,23.2,3.3,34.7,5.5c24.5,4.6,49,9.7,73.5,14.6 c1,0.2,1.9,0.6,2.8,1c0,3.3,0.7,6.7,0.7,9.9c0,5.6,2.4,7.5,7.5,8.4c15.3,2.7,30.5,5.8,45.8,8.7c12,2.3,24,4.4,36.1,6.6 c1.9,0.3,4.8,1.5,4.7,-1.4c-0.2,-4.6,1.7,-8.2,3.3,-12.1c10.2,0.9,20,3.8,30.1,5.5c11.7,2,23.1,5.3,34.9,6.5 c14.5,-3.2,28.1,-8.9,42.2,-13.2c8.1,-2.5,16.2,-5,24.1,-7.8c4.1,-1.5,4.8,-0.1,4.7,3.7C411,549.4,411,585.2,411,621z"
+ android:fillColor="#D9D9D9"/>
+ <path
+ android:pathData="M412,307c-6.9,3.5,-13.6,-0.2,-20.1,-1.3c-28.2,-5,-56.2,-10.4,-84.3,-15.8c-21.8,-4.1,-43.5,-8.5,-65.2,-12.6 c-27.3,-5.2,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.5,-66.2,-12.8c-7,-1.3,-13.9,-2.9,-21,-3.9c-4.1,-0.6,-5.2,-3,-5.3,-6.5c0,-1.2,0,-2.3,0,-3.5 c0,-51.1,0,-102.3,0,-153.4c0,-5,-0.3,-10,1,-14.9c24.1,4.3,48.1,8.6,72.2,12.8c24.9,4.4,49.8,8.7,74.6,13.1c31.9,5.6,63.7,11.3,95.6,16.9 c30.2,5.3,60.5,10.6,90.7,16c2.6,0.5,5.2,0.8,7.8,1.2c0,1.3,0.7,2,2,2C412,188.3,412,247.7,412,307z M409,217.4c0,-25.5,0,-51,0,-76.5 c0,-10.9,0.1,-11.2,-10.7,-13.2c-23.4,-4.4,-46.8,-8.5,-70.3,-12.6c-24.1,-4.3,-48.2,-8.4,-72.3,-12.6c-17.7,-3.1,-35.5,-6.3,-53.2,-9.4 c-22.1,-3.9,-44.3,-7.6,-66.4,-11.5c-20,-3.5,-40,-7.1,-60.1,-10.5c-6,-1,-6.1,-0.8,-6.1,5.6c0,53,0,105.9,0,158.9c0,1,0,2,0,3 c0.2,2.6,1,4.1,4,4.6c10.1,1.7,20.1,3.9,30.2,5.8c27.3,5.1,54.6,10.1,81.9,15.2c22.1,4.2,44.1,8.6,66.2,12.8 c27.3,5.2,54.6,10.2,81.9,15.3c22.7,4.3,45.5,8.6,68.2,12.8c6.5,1.2,6.5,1.1,6.5,-5.7C409,272,409,244.7,409,217.4z"
+ android:fillColor="#E8E8E8"/>
+ <path
+ android:pathData="M412,129c-1.3,0,-2,-0.7,-2,-2C411.3,127,412,127.7,412,129z"
+ android:fillColor="#EAEAEA"/>
+ <path
+ android:pathData="M65.8,248.3c10.1,0.7,19.8,3.5,29.7,5.2c19,3.3,38,7,57,10.6c15.9,3,31.8,6.2,47.8,9.2 c24,4.6,48,9.1,72,13.7c14.6,2.8,29.3,5.5,43.8,8.5c22.5,4.6,45.3,8.4,67.9,12.6c4.1,0.8,8.2,1.8,12.4,3.8 c-6.4,2.1,-12.8,4.3,-19.2,6.4c-9.5,3.1,-19.1,5.8,-28.4,9.4c-6.7,2.6,-13.3,2.5,-20,1.3c-41.4,-7.6,-82.8,-15.2,-124.2,-22.8 c-32.6,-6,-65.2,-11.9,-97.8,-17.8c-13.7,-2.5,-27.4,-4.9,-41.1,-7.4C65.9,270,65.9,259.1,65.8,248.3z"
+ android:fillColor="#E6A3A3"/>
+ <path
+ android:pathData="M275,519c-1.5,3.9,-3.5,7.5,-3.3,12.1c0.1,2.9,-2.8,1.7,-4.7,1.4c-12,-2.2,-24.1,-4.3,-36.1,-6.6 c-15.3,-2.9,-30.5,-6,-45.8,-8.7c-5.1,-0.9,-7.5,-2.8,-7.5,-8.4c0,-3.2,-0.8,-6.5,-0.7,-9.9c12.2,2.3,24.4,4.6,36.5,7c19.8,3.9,39.5,8,59.3,12 C273.6,518.2,274.3,518.7,275,519z"
+ android:fillColor="#CBCBCA"/>
+ <path
+ android:pathData="M202.9,345.9c0,3.3,-0.1,6.7,0.1,10c0.2,3.9,-1.4,4.3,-4.9,3.7c-29.9,-5.6,-59.8,-11.2,-89.8,-16.5 c-3,-0.5,-3.5,-1.7,-3.4,-4.2c0.1,-3.3,0.1,-6.7,0.1,-10c21.7,3.9,43.4,7.9,65.2,11.6C181.1,342.4,191.8,345.3,202.9,345.9z"
+ android:fillColor="#CFCFCE"/>
+ <path
+ android:pathData="M65.8,248.3c0,10.9,0,21.7,0,32.6c-17.9,-3.1,-35.8,-6.2,-53.7,-9.3c0,-0.4,0,-0.7,0,-1.1 C30.1,263,48,255.6,65.8,248.3z"
+ android:fillColor="#E57474"/>
+ <path
+ android:pathData="M202.9,345.9c-11.1,-0.6,-21.8,-3.5,-32.6,-5.4c-21.8,-3.7,-43.5,-7.7,-65.2,-11.6c-0.6,-3.8,0.6,-5.6,4.8,-4.8 c28.3,5,56.6,9.9,84.9,14.9c1.1,0.2,2.3,0.8,3.4,0.8C202.8,339.6,203.4,342.3,202.9,345.9z"
+ android:fillColor="#BDBDBD"/>
+ <path
+ android:pathData="M367,876c7.8,-0.4,15,1.9,22,5C381.4,880.3,374.2,878.4,367,876z"
+ android:fillColor="#EFEFEE"/>
+ <path
+ android:pathData="M354,873c4.5,0.1,9.1,0.1,13,3C362.5,875.6,358.1,875,354,873z"
+ android:fillColor="#EFEFEE"/>
+ <path
+ android:pathData="M350,872c1.4,0.1,3,-0.5,4,1C352.6,872.9,351,873.5,350,872z"
+ android:fillColor="#EFEFEE"/>
+ <path
+ android:pathData="M274.1,705c1.9,3.6,1,7.5,0.6,11.2c-0.3,2.8,-2.5,3.1,-4.9,2.6c-29.7,-5.9,-59.3,-11.9,-89,-17.7 c-3.1,-0.6,-3.9,-1.9,-3.8,-4.6c0.1,-3.2,0,-6.3,0,-9.5c1.2,0,2.4,-0.1,3.5,0.1c19.2,3.8,38.4,7.7,57.6,11.4 C250.1,700.8,261.9,703.8,274.1,705z"
+ android:fillColor="#D6D6D5"/>
+ <path
+ android:pathData="M274.1,705c-12.1,-1.2,-24,-4.2,-35.9,-6.5c-19.2,-3.7,-38.4,-7.6,-57.6,-11.4c-1.1,-0.2,-2.3,-0.1,-3.5,-0.1 c-0.5,-4.2,0.7,-5.4,5.3,-4.5c29.5,5.7,59.1,11.1,88.7,16.5C275.3,699.7,275.1,702,274.1,705z"
+ android:fillColor="#C9C9C8"/>
+ <path
+ android:pathData="M409,217.4c0,27.3,0,54.6,0,82c0,6.8,0,6.9,-6.5,5.7c-22.7,-4.2,-45.5,-8.6,-68.2,-12.8 c-27.3,-5.1,-54.6,-10.1,-81.9,-15.3c-22.1,-4.2,-44.1,-8.6,-66.2,-12.8c-27.3,-5.2,-54.6,-10.1,-81.9,-15.2c-10.1,-1.9,-20.1,-4.1,-30.2,-5.8 c-3,-0.5,-3.9,-2.1,-4,-4.6c-0.1,-1,0,-2,0,-3c0,-53,0,-105.9,0,-158.9c0,-6.4,0,-6.6,6.1,-5.6c20,3.4,40,7,60.1,10.5c22.1,3.9,44.3,7.6,66.4,11.5 c17.7,3.1,35.5,6.3,53.2,9.4c24.1,4.2,48.2,8.4,72.3,12.6c23.4,4.1,46.9,8.2,70.3,12.6c10.8,2,10.7,2.3,10.7,13.2 C409,166.4,409,191.9,409,217.4z M283.9,146.9c0.4,-3.2,-0.2,-5.3,-4,-6c-29.7,-5,-59.4,-9.9,-89,-15.3c-4.8,-0.9,-5.2,0.7,-4.8,4.4 c0,3.5,-0.1,7,0,10.5c0,1.3,-0.4,3.2,1.4,3.3c2.9,0.1,5.3,1.8,8.1,2.3c13.8,2.4,27.6,4.9,41.4,7.4c13.3,2.4,26.5,5.1,39.8,7.4 c6.6,1.2,7.3,0.4,7.3,-6.5C284,151.9,283.9,149.4,283.9,146.9z"
+ android:fillColor="#E8E7E7"/>
+ <path
+ android:pathData="M283.9,146.9c0,2.5,0.1,5,0.1,7.5c0,6.9,-0.7,7.7,-7.3,6.5c-13.3,-2.4,-26.5,-5,-39.8,-7.4 c-13.8,-2.5,-27.6,-5.1,-41.4,-7.4c-2.8,-0.5,-5.2,-2.2,-8.1,-2.3c-1.8,-0.1,-1.4,-2,-1.4,-3.3c0,-3.5,0,-7,0,-10.5c1.9,0.3,3.9,0.7,5.8,1 c21.6,4,43.1,8.1,64.7,11.8C265.6,144.4,274.5,147.1,283.9,146.9z"
+ android:fillColor="#CFCFCE"/>
+ <path
+ android:pathData="M283.9,146.9c-9.3,0.2,-18.3,-2.5,-27.3,-4.1c-21.6,-3.7,-43.1,-7.8,-64.7,-11.8c-1.9,-0.4,-3.9,-0.7,-5.8,-1 c-0.4,-3.6,-0.1,-5.2,4.8,-4.4c29.6,5.4,59.3,10.4,89,15.3C283.7,141.6,284.3,143.7,283.9,146.9z"
+ android:fillColor="#BDBDBD"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/hourglass.xml b/packages/DocumentsUI/res/drawable/hourglass.xml
new file mode 100644
index 000000000000..9b8d0e2946ba
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/hourglass.xml
@@ -0,0 +1,168 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="421dp"
+ android:height="909dp"
+ android:viewportWidth="421.0"
+ android:viewportHeight="909.0">
+ <path
+ android:pathData="M36,122.9c-2.8,-2.6,-5.7,-5.1,-8.3,-7.8c-5.6,-6,-9.2,-12.9,-8.8,-21.5c0.3,-7.5,0.6,-15,-0.1,-22.5 c-1.2,-14.1,5.5,-23.9,16,-31.9c16.7,-12.8,36.1,-19.6,56.1,-25.1c23.8,-6.5,48,-10.2,72.5,-12.3C168.6,1.3,174,2.2,179,0 c19.3,0,38.7,0,58,0c6,2.1,12.4,1.3,18.6,1.8c30.2,2.7,59.9,7.6,88.5,17.5c16.5,5.7,32.6,12.6,45.2,25.4c6.5,6.6,10.3,14,9.8,23.6 c-0.4,7.8,-0.5,15.7,0,23.4c0.6,10.3,-3.4,18.4,-10.6,25.2c-2.2,2,-4.4,4,-6.6,6c-3,2,-6.1,4,-9.1,5.9c-9.2,4.5,-18.5,9,-28.2,12.3 c-42.4,14.5,-86.3,18.8,-130.8,19.6c-10.9,0.2,-21.9,-0.4,-32.9,-0.7c-4.6,-0.4,-9.2,-0.8,-13.9,-1.1c-18.9,-1.1,-37.5,-3.9,-56,-7.6 c-15.3,-3.1,-30.2,-7.6,-44.9,-12.6c-7.6,-3.7,-15.3,-7.4,-22.9,-11.1C41.1,125.8,38.6,124.3,36,122.9z M41,72c2.9,6.9,7.1,12.6,13.1,17.2 c13,10,27.9,15.8,43.4,20.6c28.2,8.8,57.2,12.8,86.5,14c31.8,1.2,63.7,0.8,95.3,-4.6c25.3,-4.4,50.1,-10,72.9,-22.2 c10.8,-5.8,20,-13.1,24.7,-24.9c2.3,-11,-2.3,-19.5,-10.2,-26.4c-10.5,-9.2,-23.1,-14.9,-36.2,-19.6C295.2,13.4,258.4,9.7,221.2,8.1 c-11.1,-0.5,-22.2,0,-33.4,0.6c-21.4,1,-42.6,3.1,-63.6,7.3c-22.2,4.5,-44.1,10.3,-63.4,22.6C48.9,46.3,38.4,55.4,41,72z"
+ android:fillColor="#9F9F9F"/>
+ <path
+ android:pathData="M0,829c3.7,-2.8,4.7,-7.6,7.8,-10.9c2.6,-2.8,4.9,-5.7,9.2,-7.6c0,3.4,-0.1,6.5,0,9.5c0,1.5,-0.7,3.5,1.7,4 c0.4,3.3,1.4,6.4,2.9,9.4c3.8,7.7,10,13,16.8,17.9c9.2,6.7,19.7,10.8,29.8,15.5c-0.7,2.4,1.3,0.7,1.8,1.1l0,0c1.5,2.1,3.7,2.2,6,2 l0,0c0.8,0.6,1.5,1.4,2.4,1.7c9.5,2.7,18.9,5.8,28.7,7.4c3.6,0.6,7,3.5,10.9,1.1c2.4,0.4,4.8,0.8,7.1,1.2c0.2,1.5,1.3,1.6,2.5,1.8 c6.6,0.9,13.3,2.4,19.9,2.8c5.1,0.3,10.3,2.9,15.4,0.3c0.4,0,0.8,0.1,1.1,0.1c0.3,2.2,2.1,1.8,3.5,1.8c3.8,0,7.6,0,11.5,0 c1.1,1.4,2.7,1,4.1,1c17.2,0,34.5,0,51.7,0c1.4,0,3,0.4,4.1,-1c3.8,0,7.6,0,11.5,0c1.4,0,3.2,0.4,3.5,-1.8c9.4,-1,18.7,-2.1,28.1,-3.1 c6,1.3,11.6,0.4,16.9,-2.8c21.2,-4.2,42.1,-9.3,61.8,-18.4c15.8,-7.3,30.8,-15.8,38,-33.1c2.4,-2,1.9,-4.8,2.2,-7.4c0.3,-3,0,-6,0.1,-9 c0,-1,-0.3,-2.1,0.7,-2.7c1.1,-0.7,1.7,0.5,2.5,1c7.2,5,12.1,11.7,14.8,20c0.4,1.2,0.6,2.2,2.1,2.3c0,3.3,0,6.7,0,10 c-1.5,0,-1.8,1.1,-2.2,2.2c-3.8,10.2,-11.2,17.5,-20.1,23.3c-20.8,13.6,-44.1,21.2,-68.1,26.7c-29.2,6.7,-58.7,11,-88.7,11.7 c-1.6,0,-3.5,-0.5,-3.9,2c-18.7,0,-37.3,0,-56,0c-0.3,-2.5,-2.3,-1.9,-3.9,-2c-5.6,-0.1,-11.2,-0.5,-16.9,-0.8c-18.5,-1.2,-36.8,-3.8,-55,-7.3 C79.9,893.9,54,887,30.2,874C19,867.9,8.5,860.9,2.5,849C2,848,1.4,847,0,847C0,841,0,835,0,829z"
+ android:fillColor="#E6E4E4"/>
+ <path
+ android:pathData="M372.9,128.9c3,-2,6.1,-4,9.1,-5.9c-0.2,2.7,0.2,5.4,1,8c-1.5,1.6,-0.3,1.8,1,2c0.3,1,0.7,2,1,3 c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1.5,1.6,-0.3,1.8,1,2c0.3,1.7,0.7,3.3,1,5c-1,2.3,-0.6,4.1,2,5c4.9,23.8,9,47.6,8,72 c-3.5,1.5,-2.1,3.8,-1,6c-1,6,-2,12,-3,18c-1.3,1,-1.3,2,0,3c0,0.7,0,1.3,0,2c-2.1,0.4,-2.6,1.3,-1,3c0,0.3,0,0.7,0,1 c-1.3,0.2,-2.5,0.4,-1,2c0.4,2.1,-0.7,4,-1,6c-1.3,0.2,-2.5,0.4,-1,2c-3.7,9.3,-7.3,18.7,-11,28c-2.7,1.2,-4.2,2.9,-3,6 c-3.4,6.9,-7.8,13.3,-12.2,19.5c-6.1,8.6,-12.4,17.3,-19.4,25.2c-7.3,8.3,-15.5,15.8,-23.9,23c-11.9,10.3,-24.9,19.3,-38.1,27.7 c-12.2,7.8,-25.4,14.1,-38.4,20.5c-12.1,6,-18.5,15.8,-21,28.6c-1.5,7.8,-0.5,15.4,2,22.8c1.2,3.5,3.7,6.1,5.6,9.2 c5.4,8.6,14.8,10.5,22.6,15c15.3,9,30.8,17.7,45.3,28.1c14.4,10.4,28.2,21.5,40.5,34.1c10.1,10.4,18.5,22.2,26.8,34.3 c6.5,9.5,11.3,19.6,16.1,29.8c-1.5,1.6,-0.3,1.8,1,2c0.7,2,1.3,4,2,6c-1,2.3,-0.6,4.1,2,5c0.7,1.2,1.2,2.5,1,4c-1,2.3,-0.6,4.1,2,5 c1.2,12.3,4.6,24.1,5.7,36.5c0.8,8.4,1.4,16.8,1,25.1c-0.3,5.9,-1.1,12,-1.9,18c-1.2,8.7,-2.3,17.4,-4.2,25.9 c-1.5,6.6,-3.7,13.1,-5.6,19.6c-1.8,3.1,-2.9,6.5,-3.9,9.9c-3.4,6.4,-5.6,13.6,-11.9,18.2c-0.1,-3.8,1.6,-7.1,3,-10.4 c8.7,-20.9,13,-42.8,14.7,-65.1c1,-12.9,0.2,-25.8,-1.7,-38.7c-2.7,-18.5,-7.8,-36.2,-15.8,-53.1c-7.3,-15.4,-16.8,-29.3,-27.7,-42.4 c-2.7,-3.2,-6.3,-5.7,-9.6,-8.6c0.4,0.8,0.7,1.4,1,1.9c0.7,1.1,1.5,2.2,2.3,3.3c16.5,21.5,28.5,45.2,34.2,71.7c0.7,3.3,3.1,6.9,0.3,10.4 c-1,-1.9,-2.1,-3.7,-3.1,-5.6c-3.3,-6.3,-6.1,-12.9,-11.7,-17.6c-0.4,-0.9,-0.8,-1.8,-1.3,-2.6c-4,-6.3,-10.4,-10.4,-14.8,-16.2c0,-5.4,-2.7,-9.9,-4.8,-14.5 c-8.4,-18.6,-20.4,-34.9,-32.9,-50.8c-8.4,-10.8,-15.5,-22.8,-28.7,-28.8c-5.3,-2.4,-10,-6,-15.1,-8.6c-5.1,-2.6,-9.9,-6.4,-16.3,-5.2 c-5.2,1,-10.4,2.1,-15.3,4.1c-29.3,11.9,-48.4,34.1,-61.8,61.9c-0.3,0.3,-0.7,0.6,-1,1c-7.1,0.8,-13.9,2.9,-20.7,5.1 c-32.6,10.6,-61,27.4,-82.3,54.9c-9.2,11.6,-15.4,24.7,-18.9,39c-1.5,-1.1,-1.1,-2.7,-1.1,-4.1c-0.1,-9.6,0.3,-19.2,1.8,-28.7 c3.7,-22.6,11.8,-43.5,24,-62.8c12.6,-20,28.6,-36.9,47,-51.7c21.3,-17.3,44.6,-31.3,69.3,-42.9c14.5,-6.8,20,-18.8,21.8,-33.1 c1.8,-13.3,-4.9,-24.1,-12.2,-34.4c-3.6,-5,-7.4,-9.8,-13.2,-12.5c-5.8,-2.8,-11.6,-5.7,-17.4,-8.7c-22,-11.6,-42.6,-25.1,-61.1,-41.7 c-20.7,-18.6,-37.9,-40,-48.8,-65.9c-6.7,-15.7,-10.9,-32.1,-12,-49c-1.8,-27.1,2.1,-53.6,11.7,-79.1c3.8,-10.1,7.1,-20.4,13.3,-29.4 c14.7,5,29.6,9.5,44.9,12.6c18.5,3.7,37.2,6.5,56,7.6c4.6,0.3,9.3,0.7,13.9,1.1c0.2,3.6,-1.5,6.8,-2.6,10 c-11.9,33.6,-17.8,68.2,-17.2,103.8c0.2,9.7,1.3,19.4,2.7,29.1c3.8,24.6,11.4,47.7,26,68.1c12.2,17.1,28.4,28.6,49,33.4 c4.7,1.1,9.5,2.2,14.5,-0.5c18.7,-10.2,36.8,-21.2,53.7,-34.2c15.4,-11.9,29.4,-25.3,41.5,-40.5c12.9,-16.2,23.4,-33.8,30.4,-53.4 c6.4,-17.6,10.3,-35.6,10.9,-54.3c0.5,-15.9,0.2,-31.9,-3,-47.6C383.8,158.7,380.1,143.3,372.9,128.9z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M383,780c1.1,-3.4,2.1,-6.8,3.9,-9.9c7.8,7.1,12.8,15.2,12.2,26.4c-0.6,10.7,-0.3,21.5,-0.5,32.3 c-7.2,17.3,-22.2,25.8,-38,33.1c-19.7,9.1,-40.6,14.1,-61.8,18.4c-5.6,0.9,-11.3,1.9,-16.9,2.8c-9.4,1,-18.7,2.1,-28.1,3.1 c-5,0.3,-9.9,0.7,-14.9,1c-20,1.2,-40,0.9,-60,0c-5,-0.3,-9.9,-0.7,-14.9,-1c-0.4,0,-0.8,-0.1,-1.1,-0.1c-12.6,-1.6,-25.2,-3.2,-37.9,-4.8 c-2.4,-0.4,-4.8,-0.8,-7.1,-1.2c-2.6,-0.6,-5.1,-1.3,-7.7,-1.8c-11.6,-2,-22.6,-6.3,-34.2,-8.4c0,0,0,0,0,0c-1.7,-1.6,-3.7,-2.2,-6,-2c0,0,0,0,0,0 c-0.2,-1,-1.1,-0.9,-1.8,-1.1c-10.2,-4.7,-20.6,-8.8,-29.8,-15.5c-6.8,-4.9,-13,-10.2,-16.8,-17.9c-1.5,-3,-2.4,-6.1,-2.9,-9.4 c0.1,-10.3,0,-20.6,0.2,-30.9c0.1,-8.3,3.5,-15,10,-20.2c2,3.5,3.4,7.1,4.1,11c-1.1,0.8,-1,2,-1.1,3.1c-0.6,8.2,2.9,14.9,8.3,20.6 c8.9,9.6,20.4,15.4,32.3,20.2c17.9,7.2,36.5,11.9,55.4,15.4c20.1,3.7,40.3,5.7,60.6,6.5c21.4,0.8,42.8,0.4,64.2,-1.6 c19.8,-1.9,39.4,-4.6,58.7,-9.3c19.9,-4.8,39.3,-11.2,56.4,-22.9c7.8,-5.3,15.2,-11.3,17.4,-21C386.4,790.1,388.3,784.3,383,780z"
+ android:fillColor="#9F9F9F"/>
+ <path
+ android:pathData="M378,305c-1.2,-3.1,0.3,-4.8,3,-6C380.6,301.3,379.7,303.3,378,305z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M399,234c-1.1,-2.2,-2.5,-4.5,1,-6C399.7,230,400.8,232.2,399,234z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M392,156c-2.6,-0.9,-3,-2.7,-2,-5C391.4,152.4,391.6,154.2,392,156z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M389,636c-2.6,-0.9,-3,-2.7,-2,-5C388.4,632.4,388.6,634.2,389,636z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M392,645c-2.6,-0.9,-3,-2.7,-2,-5C391.4,641.4,391.6,643.2,392,645z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M396,255c-1.3,-1,-1.3,-2,0,-3C397.3,253,397.3,254,396,255z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M395,260c-1.6,-1.7,-1.1,-2.6,1,-3C395.7,258,395.3,259,395,260z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M384,133c-1.3,-0.2,-2.5,-0.4,-1,-2C383.8,131.4,384,132.2,384,133z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M385,625c-1.3,-0.2,-2.5,-0.4,-1,-2C384.8,623.4,385,624.2,385,625z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M392,271c-1.5,-1.6,-0.3,-1.8,1,-2C393,269.8,392.8,270.6,392,271z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M394,263c-1.5,-1.6,-0.3,-1.8,1,-2C395,261.8,394.8,262.6,394,263z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M386,138c-1.3,-0.2,-2.5,-0.4,-1,-2C385.8,136.4,386,137.2,386,138z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M389,146c-1.3,-0.2,-2.5,-0.4,-1,-2C388.8,144.4,389,145.2,389,146z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M33.1,783.9c-0.8,-3.9,-2.2,-7.6,-4.1,-11c-3.7,-11.7,-7.2,-23.5,-9.2,-35.5c-1.3,-7.6,-1.9,-15.4,-2.7,-23.2 c-0.6,-6.2,-0.9,-12.4,-1,-18.5c-0.2,-7.9,1.9,-15.7,2.3,-23.4c0.5,-10.1,2.9,-19.5,5.5,-29c6.3,-23.1,17.3,-43.9,31.5,-62.8 c23.4,-31.1,53.3,-54.7,86.9,-74.1c10.1,-5.8,20.3,-11.6,30.9,-16.2c11.7,-5.2,16.3,-14.9,18.8,-26.3c3.2,-14.9,-2.8,-26.6,-12.7,-37.1 c-1.8,-1.9,-3.9,-3.1,-6.2,-4.2c-23.7,-11.4,-46.4,-24.4,-67.2,-40.7c-16.2,-12.6,-31.3,-26.5,-44.2,-42.6c-16.2,-20.3,-28.8,-42.5,-36.2,-67.5 c-3.1,-10.6,-5.4,-21.3,-6.2,-32.4c-0.7,-9.6,-3.2,-19.3,-2,-28.8c0.8,-6.6,1.5,-13.4,1.9,-20c1,-15.2,4.9,-29.6,9.2,-44c1.7,-5.7,4,-11.3,6.4,-16.8 c0.9,-2.2,1.3,-4.4,1.3,-6.8c2.6,1.4,5.1,2.9,7.2,4.9c-0.6,0.8,-1.4,1.4,-1.8,2.3c-11.2,26.2,-16.2,53.8,-17.4,82.2 c-0.4,8.8,1,17.5,1.9,26.2c2,19.7,7.4,38.4,15.6,56.3c17.9,39.2,46.6,69.1,81.3,93.6c18.5,13.1,38.1,24.3,58.5,34.1 c3.3,1.6,6,3.7,8.1,6.5c8,10.6,12.6,22.1,9.6,35.7c-2.1,9.4,-6.5,17.9,-14.8,22.7c-8.2,4.7,-16.9,8.5,-25.3,12.9 c-22.5,12,-43.8,25.8,-62.6,43c-21.9,19.9,-40.8,42.1,-53.7,69.2C26.3,646.5,20.6,682,24.1,719c1.8,18.7,7,36.7,12.7,54.6 c5.9,18.7,18.2,30.9,35.3,38.9c15.4,7.2,31.5,12.2,48.1,15.8c1.6,0.4,4.3,-0.3,4.8,2.6c-18,-2.8,-35.4,-7.5,-52.3,-14.5 c-12.2,-5.1,-23.4,-11.4,-32.4,-21.4C37.2,791.7,36.5,787,33.1,783.9z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M372.9,128.9c7.2,14.3,10.9,29.8,14.1,45.4c3.2,15.7,3.5,31.6,3,47.6c-0.6,18.7,-4.6,36.7,-10.9,54.3 c-7.1,19.6,-17.6,37.2,-30.4,53.4c-12.1,15.2,-26.1,28.6,-41.5,40.5c-16.9,13,-35,24,-53.7,34.2c-5,2.7,-9.8,1.6,-14.5,0.5 c-20.6,-4.8,-36.8,-16.3,-49,-33.4c-14.6,-20.4,-22.3,-43.5,-26,-68.1c-1.5,-9.7,-2.6,-19.4,-2.7,-29.1c-0.6,-35.6,5.4,-70.2,17.2,-103.8 c1.2,-3.3,2.8,-6.4,2.6,-10c11,0.2,21.9,0.9,32.9,0.7c44.4,-0.8,88.4,-5.2,130.8,-19.6C354.4,137.9,363.7,133.5,372.9,128.9z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M377,72c-4.6,11.9,-13.9,19.1,-24.7,24.9c-22.9,12.2,-47.6,17.9,-72.9,22.2c-31.6,5.4,-63.5,5.9,-95.3,4.6 c-29.3,-1.1,-58.3,-5.1,-86.5,-14C82.1,105,67.2,99.1,54.2,89.2C48.2,84.6,43.9,78.8,41,72c3.9,-1.8,4.6,-6.2,7.3,-9 c10.3,-10.5,22.9,-16.9,36.5,-21.8c19.7,-7.1,40,-11.5,60.7,-14.5c19.4,-2.8,38.9,-3.9,58.4,-4.5c17.9,-0.6,35.8,0.8,53.6,2.8 c15,1.6,29.9,3.5,44.5,7.1c20,4.9,39.7,10.7,57.2,22.1C366.5,58.8,371.5,65.5,377,72z"
+ android:fillColor="#8D8E8E"/>
+ <path
+ android:pathData="M125,831c-0.4,-2.9,-3.2,-2.3,-4.8,-2.6c-16.6,-3.7,-32.7,-8.7,-48.1,-15.8c-17.1,-8,-29.4,-20.2,-35.3,-38.9 c-5.7,-17.9,-10.9,-35.9,-12.7,-54.6c-3.6,-37.1,2.1,-72.5,18.4,-106.4c13,-27.1,31.9,-49.3,53.7,-69.2c18.8,-17.1,40.2,-30.9,62.6,-43 c8.4,-4.5,17.1,-8.2,25.3,-12.9c8.4,-4.8,12.7,-13.3,14.8,-22.7c3.1,-13.6,-1.6,-25.1,-9.6,-35.7c-2.1,-2.8,-4.8,-4.9,-8.1,-6.5 c-20.4,-9.9,-40,-21.1,-58.5,-34.1c-34.7,-24.6,-63.4,-54.5,-81.3,-93.6c-8.2,-17.9,-13.6,-36.6,-15.6,-56.3c-0.9,-8.7,-2.3,-17.5,-1.9,-26.2 c1.2,-28.3,6.2,-55.9,17.4,-82.2c0.4,-0.9,1.2,-1.5,1.8,-2.3c7.6,3.7,15.3,7.4,22.9,11.1c-6.2,9,-9.5,19.3,-13.3,29.4 c-9.6,25.5,-13.5,52,-11.7,79.1c1.1,16.9,5.4,33.3,12,49c11,25.9,28.1,47.4,48.8,65.9c18.5,16.6,39.1,30.2,61.1,41.7 c5.7,3,11.5,5.9,17.4,8.7c5.8,2.8,9.7,7.6,13.2,12.5c7.3,10.3,14,21.1,12.2,34.4c-1.9,14.3,-7.4,26.3,-21.8,33.1 c-24.7,11.6,-48,25.7,-69.3,42.9c-18.3,14.9,-34.3,31.7,-47,51.7c-12.2,19.3,-20.3,40.2,-24,62.8c-1.6,9.6,-2,19.1,-1.8,28.7 c0,1.4,-0.4,3.1,1.1,4.1c-0.6,14.9,0.1,29.8,3,44.5c4.2,21.4,9.1,42.6,26,58.4c-0.2,2.3,0.9,4.1,2.2,5.9c8.8,12.3,22,18.6,35.3,24.1 c26.4,10.9,54.2,16.1,82.4,19.1c1.7,0.2,3,0.4,3,2.4c-4.5,0.7,-9,0.9,-13.4,0.5c-13.2,-1,-26.5,-1.9,-39.6,-4.1c-0.6,-2.4,-1.7,-2.3,-3.1,-0.6 c-1.3,-0.1,-2.6,-0.3,-3.9,-0.4c-0.6,-2.3,-1.6,-2.4,-3.1,-0.7c-0.6,-0.1,-1.3,-0.2,-1.9,-0.3c-0.6,-2.4,-1.7,-2.4,-3.1,-0.6 C126.2,831.2,125.6,831.1,125,831z"
+ android:fillColor="#E8E8E7"/>
+ <path
+ android:pathData="M377,72c-5.4,-6.4,-10.5,-13.2,-17.7,-17.9C341.7,42.7,322.1,36.9,302,32c-14.6,-3.6,-29.5,-5.5,-44.5,-7.1 c-17.8,-1.9,-35.7,-3.3,-53.6,-2.8c-19.5,0.6,-39,1.7,-58.4,4.5c-20.7,3,-41,7.4,-60.7,14.5C71.3,46.1,58.7,52.4,48.4,63 c-2.7,2.8,-3.5,7.2,-7.3,9c-2.6,-16.6,7.9,-25.6,19.8,-33.3c19.3,-12.3,41.2,-18.2,63.4,-22.6c21,-4.2,42.2,-6.3,63.6,-7.3 c11.1,-0.5,22.3,-1,33.4,-0.6c37.2,1.5,74,5.3,109.4,17.9c13.1,4.6,25.6,10.4,36.2,19.6C374.7,52.5,379.3,61,377,72z"
+ android:fillColor="#808080"/>
+ <path
+ android:pathData="M179,887.2c20,0.9,40,1.2,60,0c0,0.3,0,0.5,0,0.8c-1.1,1.4,-2.7,1,-4.1,1c-17.2,0,-34.5,0,-51.7,0 c-1.4,0,-3,0.4,-4.1,-1C179,887.7,179,887.5,179,887.2z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M76,869.9c11.6,2.2,22.6,6.5,34.2,8.4c2.6,0.4,5.2,1.2,7.7,1.8c-3.9,2.3,-7.3,-0.6,-10.9,-1.1 c-9.8,-1.6,-19.2,-4.7,-28.7,-7.4C77.5,871.3,76.8,870.5,76,869.9z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M125.1,881.3c12.6,1.6,25.2,3.2,37.9,4.8c-5.2,2.6,-10.3,0,-15.4,-0.3c-6.7,-0.4,-13.3,-1.9,-19.9,-2.8 C126.3,882.9,125.2,882.8,125.1,881.3z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M282,883.1c5.6,-0.9,11.3,-1.9,16.9,-2.8C293.7,883.4,288.1,884.4,282,883.1z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M179,887.2c0,0.3,0,0.5,0,0.8c-3.8,0,-7.6,0,-11.5,0c-1.4,0,-3.2,0.4,-3.5,-1.8C169,886.5,174,886.9,179,887.2z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M239,888c0,-0.3,0,-0.5,0,-0.8c5,-0.3,9.9,-0.7,14.9,-1c-0.3,2.2,-2.1,1.8,-3.5,1.8C246.6,888,242.8,888,239,888z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M70,867.9c2.3,-0.2,4.3,0.4,6,2C73.8,870.1,71.6,870,70,867.9z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M68.2,866.8c0.7,0.2,1.6,0.2,1.8,1.1C69.5,867.4,67.6,869.2,68.2,866.8z"
+ android:fillColor="#F4F3F2"/>
+ <path
+ android:pathData="M165,584c0.3,-0.3,0.7,-0.6,1,-1c10.5,-1.3,21,-3.3,31.5,-3.8c20.8,-1.1,41.4,0.7,61.7,5.4 c30.5,7,57.8,20.3,81.8,40.5c4.4,5.9,10.8,10,14.8,16.2c0.5,0.8,0.9,1.7,1.3,2.6c-2.4,4.1,-4.7,8.1,-7.1,12.2c-4,3.7,-6.3,8.9,-11,12 c-1.6,-0.1,-2.8,0.5,-4.1,1.5c-12.6,9.3,-26.7,15.6,-41.5,20.1c-31,9.4,-62.6,13.3,-95.1,11.6c-12.3,-0.6,-24.5,-1.5,-36.5,-3.4 c-4.5,-0.7,-5.3,0.5,-4.8,4.2c-0.5,0,-1,0.1,-1.5,0c-17.8,-3.9,-34.7,-10.3,-50.9,-18.7c-1,-0.5,-1.6,-1.1,-1.6,-2.3c2.3,-0.3,4.1,1.1,6.1,2 c14.2,6.2,28.9,10.6,44.1,13.3c2.5,0.4,3,0.2,2.4,-2.3c-2.5,-9.3,-3.7,-18.7,-4.8,-28.3c-1.5,-13.7,-0.3,-27.1,1.7,-40.5 C154.6,610.8,159.7,597.4,165,584z"
+ android:fillColor="#E57474"/>
+ <path
+ android:pathData="M103,681c0.1,1.1,0.7,1.8,1.6,2.3c16.2,8.4,33.1,14.8,50.9,18.7c0.5,0.1,1,0,1.5,0c0.6,0.4,1.3,0.7,1.9,1.1 c-0.1,2.7,1,5.2,1.9,7.6c6.5,17.8,16.5,33.6,27.5,48.8c12.5,17.1,27.1,32.1,45.1,43.6c6.6,4.2,13.7,7.3,20.5,11 c-15.6,2.8,-31.4,2.5,-47.1,2.4c-9.9,0,-19.9,-0.2,-29.8,-1.1c-18.2,-1.6,-36.2,-3.9,-54,-8.3c-18.1,-4.4,-35.9,-9.5,-51,-21.1 c-16.9,-15.8,-21.8,-37,-26,-58.4c-2.9,-14.7,-3.6,-29.6,-3,-44.5c3.5,-14.4,9.7,-27.4,18.9,-39c3.4,4.8,6.2,10.1,10.3,14.2 c6,6.1,11.6,13,19.7,16.8c0.5,0.8,1.2,1,2.1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1c0,0,0,0,0,0c0.3,0.3,0.7,0.7,1,1l0,0 c1,1.3,2.4,1.8,4,2l0,0C100.7,681.2,101.9,681,103,681L103,681z"
+ android:fillColor="#E6A3A3"/>
+ <path
+ android:pathData="M341,625c-24,-20.1,-51.3,-33.5,-81.8,-40.5c-20.3,-4.7,-41,-6.5,-61.7,-5.4c-10.5,0.6,-21,2.5,-31.5,3.8 c13.4,-27.8,32.5,-49.9,61.8,-61.9c4.9,-2,10.1,-3.1,15.3,-4.1c6.3,-1.2,11.2,2.6,16.3,5.2c5.2,2.6,9.9,6.2,15.1,8.6 c13.3,6,20.3,18,28.7,28.8c12.5,16,24.6,32.2,32.9,50.8C338.3,615.2,341,619.7,341,625z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M91.9,675c-8,-3.8,-13.6,-10.7,-19.7,-16.8c-4.1,-4.1,-6.9,-9.4,-10.3,-14.2c21.3,-27.5,49.8,-44.3,82.3,-54.9 c6.8,-2.2,13.6,-4.3,20.7,-5.1c-5.3,13.4,-10.4,26.9,-12.5,41.2c-2,13.4,-3.2,26.8,-1.7,40.5c1.1,9.6,2.3,19,4.8,28.3 c0.7,2.5,0.1,2.7,-2.4,2.3c-15.2,-2.6,-29.9,-7.1,-44.1,-13.3c-2,-0.9,-3.7,-2.3,-6.1,-2c0,0,0,0,0,0c-0.7,-1.2,-1.9,-1,-3,-1c0,0,0,0,0,0 c-0.3,-2.7,-2.4,-1.8,-4,-2c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0c-0.3,-0.3,-0.7,-0.7,-1,-1c0,0,0,0,0,0 C93.6,675.2,92.8,675,91.9,675z"
+ android:fillColor="#D86868"/>
+ <path
+ android:pathData="M135,832.8c1.3,0.1,2.6,0.3,3.9,0.4c0.9,0.8,2,0.7,3.1,0.6c13.1,2.2,26.4,3,39.6,4.1 c4.5,0.3,9,0.2,13.4,-0.5c3.1,0.3,6.3,0.7,9.4,0.8c22.6,0.4,45.2,-0.9,67.6,-4.1c23.9,-3.3,47.4,-8.2,69.8,-17.6 c10.7,-4.5,21.4,-9.3,29.3,-18.3l0,0.1c6.2,-4.6,8.5,-11.8,11.9,-18.2c5.2,4.3,3.3,10.1,2.2,15c-2.2,9.7,-9.6,15.7,-17.4,21 c-17.1,11.7,-36.5,18.1,-56.4,22.9c-19.3,4.7,-38.9,7.4,-58.7,9.3c-21.4,2,-42.8,2.5,-64.2,1.6c-20.3,-0.8,-40.5,-2.8,-60.6,-6.5 c-19,-3.5,-37.6,-8.2,-55.4,-15.4c-11.9,-4.8,-23.4,-10.6,-32.3,-20.2c-5.3,-5.8,-8.9,-12.4,-8.3,-20.6c0.1,-1.2,0,-2.4,1.1,-3.1 c3.3,3.1,4.1,7.8,7.2,11.1c9,9.9,20.2,16.3,32.4,21.4c16.8,7,34.3,11.7,52.3,14.5c0.6,0.1,1.2,0.2,1.9,0.3c0.9,0.8,2,0.7,3.1,0.6 c0.6,0.1,1.3,0.2,1.9,0.3C132.8,833,133.9,833,135,832.8z"
+ android:fillColor="#999899"/>
+ <path
+ android:pathData="M371.9,667c2.8,-3.5,0.4,-7.1,-0.3,-10.4c-5.7,-26.6,-17.7,-50.3,-34.2,-71.7c-0.8,-1,-1.5,-2.2,-2.3,-3.3 c-0.3,-0.5,-0.6,-1.1,-1,-1.9c3.4,3,6.9,5.4,9.6,8.6c10.8,13.1,20.4,27,27.7,42.4c8,16.9,13.1,34.6,15.8,53.1 c1.9,12.9,2.6,25.8,1.7,38.7c-1.7,22.4,-6,44.3,-14.7,65.1c-1.4,3.3,-3.1,6.6,-3,10.4c0,0,0,-0.1,0,-0.1c-1.8,-0.3,-3.3,0.4,-4.7,1.2 c-6.3,3.7,-12.6,7.3,-19.4,10.2c-24,10.3,-48.8,14.5,-74.7,9.2c-4.2,-0.9,-9.4,-0.2,-12.4,-4.8c13.8,-2,27.6,-4.4,41.1,-8 c10,-2.7,20,-5.4,29,-10.8c1.5,-0.5,3.2,-0.9,4.6,-1.6c10.6,-5.1,19.5,-12.1,25.3,-22.6c4.7,-3.1,8.2,-10.7,6.9,-15c0.3,-1.4,0.6,-2.9,1,-4.3 c5.4,-16.2,7.5,-33.1,9,-50C378,689.7,375.5,678.3,371.9,667z"
+ android:fillColor="#F1F0F0"/>
+ <path
+ android:pathData="M371.9,667c3.6,11.3,6.1,22.7,5.1,34.6c-1.5,16.9,-3.6,33.8,-9,50c-0.5,1.4,-0.7,2.9,-1,4.3 c-2.3,5,-4.6,10,-6.9,15c-5.8,10.5,-14.7,17.5,-25.3,22.6c-1.5,0.7,-3.1,1.1,-4.6,1.6c-0.3,-2.1,0.3,-3.9,1.1,-5.7 c3.4,-7.4,6.4,-14.9,8.9,-22.6c6,-18.1,10,-36.5,12,-55.6c1.2,-11.6,0.9,-23.2,0.6,-34.8c-0.2,-6.8,-0.7,-13.8,-2.8,-20.5 c2.4,-4.1,4.7,-8.1,7.1,-12.2c5.6,4.7,8.4,11.3,11.7,17.6C369.8,663.3,370.8,665.2,371.9,667z"
+ android:fillColor="#E6A3A3"/>
+ <path
+ android:pathData="M260,814c2.9,4.6,8.1,3.9,12.4,4.8c25.9,5.3,50.7,1.1,74.7,-9.2c6.7,-2.9,13.1,-6.4,19.4,-10.2 c1.4,-0.9,2.9,-1.6,4.7,-1.2c-7.9,9.1,-18.6,13.8,-29.3,18.3c-22.3,9.4,-45.9,14.3,-69.8,17.6c-22.4,3.1,-45,4.4,-67.6,4.1 c-3.1,-0.1,-6.3,-0.5,-9.4,-0.8c-0.1,-2,-1.4,-2.2,-3,-2.4c-28.3,-3,-56,-8.2,-82.4,-19.1c-13.4,-5.5,-26.5,-11.8,-35.3,-24.1c-1.3,-1.8,-2.4,-3.6,-2.2,-5.9 c15.1,11.6,32.9,16.7,51,21.1c17.7,4.4,35.8,6.6,54,8.3c10,0.9,20,1.1,29.8,1.1c15.7,0.1,31.5,0.4,47.1,-2.4 C256,814,258,814,260,814z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M130,831.9c-1.1,0.1,-2.2,0.2,-3.1,-0.6C128.3,829.5,129.4,829.5,130,831.9z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M135,832.8c-1.1,0.1,-2.2,0.2,-3.1,-0.7C133.4,830.5,134.4,830.6,135,832.8z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M142,833.8c-1.1,0.1,-2.2,0.2,-3.1,-0.6C140.3,831.5,141.4,831.5,142,833.8z"
+ android:fillColor="#EDECEC"/>
+ <path
+ android:pathData="M260,814c-2,0,-4,0,-6,0c-6.8,-3.7,-13.9,-6.8,-20.5,-11c-18,-11.5,-32.7,-26.4,-45.1,-43.6c-11,-15.2,-21,-31,-27.5,-48.8 c-0.9,-2.5,-2,-4.9,-1.9,-7.7c0.7,0,1.4,-0.1,2,0.1c16.2,4.6,33.1,5.3,49.6,5.3c10,0,20.1,-0.2,30.2,-1.3c19.5,-2,38.7,-5.3,57,-12.4 c15.6,-6,30.1,-13.9,41.3,-26.9c4.7,-3.1,7,-8.3,11,-12c2.1,6.7,2.6,13.7,2.8,20.5c0.3,11.6,0.6,23.1,-0.6,34.8c-2,19,-6,37.5,-12,55.6 c-2.6,7.7,-5.5,15.3,-8.9,22.6c-0.9,1.9,-1.5,3.7,-1.1,5.7c-9,5.4,-19,8.1,-29,10.8C287.6,809.6,273.8,811.9,260,814z"
+ android:fillColor="#E6A3A3"/>
+ <path
+ android:pathData="M339,668c-11.1,13,-25.7,20.8,-41.3,26.9c-18.3,7.1,-37.5,10.4,-57,12.4c-10.1,1,-20.3,1.3,-30.2,1.3 c-16.6,0,-33.4,-0.7,-49.6,-5.3c-0.6,-0.2,-1.3,-0.1,-2,-0.1c-0.6,-0.4,-1.3,-0.7,-1.9,-1.1c-0.4,-3.8,0.3,-5,4.8,-4.2c12.1,2,24.3,2.8,36.5,3.4 c32.4,1.7,64.1,-2.3,95.1,-11.6c14.8,-4.5,29,-10.8,41.5,-20.1C336.3,668.5,337.5,667.9,339,668z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M96,678c1.6,0.2,3.7,-0.7,4,2C98.4,679.8,97,679.3,96,678z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M100,680c1.1,0,2.3,-0.2,3,1C101.9,681,100.7,681.2,100,680z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M91.9,675c0.8,0,1.6,0.2,2.1,1C93.2,676,92.4,675.8,91.9,675z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M94,676c0.3,0.3,0.7,0.7,1,1C94.7,676.7,94.3,676.3,94,676z"
+ android:fillColor="#FFFFFF"/>
+ <path
+ android:pathData="M95,677c0.3,0.3,0.7,0.7,1,1C95.7,677.7,95.3,677.3,95,677z"
+ android:fillColor="#C5C5C5"/>
+ <path
+ android:pathData="M360,771c2.3,-5,4.6,-10,6.9,-15C368.2,760.3,364.7,767.8,360,771z"
+ android:fillColor="#EDECEC"/>
+</vector>
diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml
index 8245e53097cd..2fa09d39bdab 100644
--- a/packages/DocumentsUI/res/layout/directory_cluster.xml
+++ b/packages/DocumentsUI/res/layout/directory_cluster.xml
@@ -25,7 +25,7 @@
android:elevation="8dp"
android:background="@color/material_grey_50"/>
- <com.android.documentsui.DirectoryContainerView
+ <FrameLayout
android:id="@+id/container_directory"
android:layout_width="match_parent"
android:layout_height="0dp"
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index b791ef12b6f3..73571af20134 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -32,23 +32,6 @@
android:imeOptions="actionSearch"
android:visible="false" />
<item
- android:id="@+id/menu_sort"
- android:title="@string/menu_sort"
- android:icon="@drawable/ic_menu_sortby"
- android:showAsAction="always">
- <menu>
- <item
- android:id="@+id/menu_sort_name"
- android:title="@string/sort_name" />
- <item
- android:id="@+id/menu_sort_date"
- android:title="@string/sort_date" />
- <item
- android:id="@+id/menu_sort_size"
- android:title="@string/sort_size" />
- </menu>
- </item>
- <item
android:id="@+id/menu_grid"
android:title="@string/menu_grid"
android:icon="@drawable/ic_menu_view_grid"
@@ -70,7 +53,7 @@
android:title="@string/menu_create_dir"
android:icon="@drawable/ic_menu_new_folder"
android:alphabeticShortcut="e"
- android:showAsAction="always"
+ android:showAsAction="never"
android:visible="false" />
<item
android:id="@+id/menu_paste_from_clipboard"
@@ -80,6 +63,23 @@
android:visible="false" />
<!-- Copy action is defined in mode_directory.xml -->
<item
+ android:id="@+id/menu_sort"
+ android:title="@string/menu_sort"
+ android:icon="@drawable/ic_menu_sortby"
+ android:showAsAction="never">
+ <menu>
+ <item
+ android:id="@+id/menu_sort_name"
+ android:title="@string/sort_name" />
+ <item
+ android:id="@+id/menu_sort_date"
+ android:title="@string/sort_date" />
+ <item
+ android:id="@+id/menu_sort_size"
+ android:title="@string/sort_size" />
+ </menu>
+ </item>
+ <item
android:id="@+id/menu_file_size"
android:showAsAction="never"
android:visible="false" />
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 3c49f167534e..b97918e7b9d1 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -101,7 +101,7 @@
<!-- Toast shown when creating a folder failed with an error [CHAR LIMIT=48] -->
<string name="create_error">Failed to create folder</string>
<!-- Error message shown when querying for a list of documents failed [CHAR LIMIT=48] -->
- <string name="query_error">Failed to query documents</string>
+ <string name="query_error">Can\u2019t load content at the moment</string>
<!-- Title of storage root location that contains recently modified or used documents [CHAR LIMIT=24] -->
<string name="root_recent">Recent</string>
@@ -123,7 +123,7 @@
<string name="no_results">No matches in %1$s</string>
<!-- Toast shown when no app can be found to open the selected document [CHAR LIMIT=48] -->
- <string name="toast_no_application">Can\'t open file</string>
+ <string name="toast_no_application">Can\u2019t open file</string>
<!-- Toast shown when some of the selected documents failed to be deleted [CHAR LIMIT=48] -->
<string name="toast_failed_delete">Unable to delete some documents</string>
@@ -160,27 +160,27 @@
<string name="delete_preparing">Preparing for delete\u2026</string>
<!-- Title of the copy error notification [CHAR LIMIT=48] -->
<plurals name="copy_error_notification_title">
- <item quantity="one">Couldn\'t copy <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
- <item quantity="other">Couldn\'t copy <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
+ <item quantity="one">Couldn\u2019t copy <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
+ <item quantity="other">Couldn\u2019t copy <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
</plurals>
<!-- Title of the move error notification [CHAR LIMIT=48] -->
<plurals name="move_error_notification_title">
- <item quantity="one">Couldn\'t move <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
- <item quantity="other">Couldn\'t move <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
+ <item quantity="one">Couldn\u2019t move <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
+ <item quantity="other">Couldn\u2019t move <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
</plurals>
<!-- Title of the delete error notification [CHAR LIMIT=48] -->
<plurals name="delete_error_notification_title">
- <item quantity="one">Couldn\'t delete <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
- <item quantity="other">Couldn\'t delete <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
+ <item quantity="one">Couldn\u2019t delete <xliff:g id="count" example="1">%1$d</xliff:g> file</item>
+ <item quantity="other">Couldn\u2019t delete <xliff:g id="count" example="2">%1$d</xliff:g> files</item>
</plurals>
<!-- Second line for notifications saying that more information will be shown after touching [CHAR LIMIT=48] -->
<string name="notification_touch_for_details">Tap to view details</string>
<!-- Label of the close dialog button.[CHAR LIMIT=24] -->
<string name="close">Close</string>
<!-- Contents of the copying failure alert dialog. [CHAR LIMIT=48] -->
- <string name="copy_failure_alert_content">These files weren\'t copied: <xliff:g id="list">%1$s</xliff:g></string>
+ <string name="copy_failure_alert_content">These files weren\u2019t copied: <xliff:g id="list">%1$s</xliff:g></string>
<!-- Contents of the moving failure alert dialog. [CHAR LIMIT=48] -->
- <string name="move_failure_alert_content">These files weren\'t moved: <xliff:g id="list">%1$s</xliff:g></string>
+ <string name="move_failure_alert_content">These files weren\u2019t moved: <xliff:g id="list">%1$s</xliff:g></string>
<!-- Contents of the copying warning dialog due to converted files. [CHAR LIMIT=64] -->
<string name="copy_converted_warning_content">These files were converted to another format: <xliff:g id="list" example="Document.pdf, Photo.jpg, Song.ogg">%1$s</xliff:g></string>
<!-- Toast shown when a user copies files to clipboard. -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index e72343e9a9ba..3c21a214b19b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -45,22 +45,16 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Spinner;
-import android.widget.Toolbar;
-import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.SearchManager.SearchManagerListener;
import com.android.documentsui.State.ViewMode;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Preconditions;
-import libcore.io.IoUtils;
-
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -71,6 +65,9 @@ public abstract class BaseActivity extends Activity
static final String EXTRA_STATE = "state";
+ // See comments where this const is referenced for details.
+ private static final int DRAWER_NO_FIDDLE_DELAY = 1500;
+
State mState;
RootsCache mRoots;
SearchManager mSearchManager;
@@ -78,17 +75,21 @@ public abstract class BaseActivity extends Activity
NavigationView mNavigator;
private final String mTag;
+
@LayoutRes
private int mLayoutId;
- private DirectoryContainerView mDirectoryContainer;
+
+ // Track the time we opened the drawer in response to back being pressed.
+ // We use the time gap to figure out whether to close app or reopen the drawer.
+ private long mDrawerLastFiddled;
public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings);
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
abstract void onTaskFinished(Uri... uris);
abstract void refreshDirectory(int anim);
- abstract void saveStackBlocking();
- abstract State buildState();
+ /** Allows sub-classes to include information in a newly created State instance. */
+ abstract void includeState(State initialState);
public BaseActivity(@LayoutRes int layoutId, String tag) {
mLayoutId = layoutId;
@@ -103,9 +104,7 @@ public abstract class BaseActivity extends Activity
setContentView(mLayoutId);
mDrawer = DrawerController.create(this);
- mState = (icicle != null)
- ? icicle.<State>getParcelable(EXTRA_STATE)
- : buildState();
+ mState = getState(icicle);
Metrics.logActivityLaunch(this, mState, getIntent());
mRoots = DocumentsApplication.getRootsCache(this);
@@ -114,11 +113,11 @@ public abstract class BaseActivity extends Activity
new RootsCache.OnCacheUpdateListener() {
@Override
public void onCacheUpdate() {
- new HandleRootsChangedTask().execute(getCurrentRoot());
+ new HandleRootsChangedTask(BaseActivity.this)
+ .execute(getCurrentRoot());
}
});
- mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
mSearchManager = new SearchManager(this);
DocumentsToolbar toolbar = (DocumentsToolbar) findViewById(R.id.toolbar);
@@ -184,7 +183,20 @@ public abstract class BaseActivity extends Activity
super.onDestroy();
}
- State buildDefaultState() {
+ private State getState(@Nullable Bundle icicle) {
+ if (icicle != null) {
+ State state = icicle.<State>getParcelable(EXTRA_STATE);
+ if (DEBUG) Log.d(mTag, "Recovered existing state object: " + state);
+ return state;
+ }
+
+ State state = createSharedState();
+ includeState(state);
+ if (DEBUG) Log.d(mTag, "Created new state object: " + state);
+ return state;
+ }
+
+ private State createSharedState() {
State state = new State();
final Intent intent = getIntent();
@@ -224,22 +236,7 @@ public abstract class BaseActivity extends Activity
if (mRoots.isRecentsRoot(root)) {
refreshCurrentRootAndDirectory(ANIM_NONE);
} else {
- new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory());
- }
- }
-
- void expandMenus(Menu menu) {
- for (int i = 0; i < menu.size(); i++) {
- final MenuItem item = menu.getItem(i);
- switch (item.getItemId()) {
- case R.id.menu_advanced:
- case R.id.menu_file_size:
- case R.id.menu_new_window:
- case R.id.menu_search:
- break;
- default:
- item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- }
+ new PickRootTask(this, root).executeOnExecutor(getExecutorForCurrentDirectory());
}
}
@@ -351,7 +348,6 @@ public abstract class BaseActivity extends Activity
public final void refreshCurrentRootAndDirectory(int anim) {
mSearchManager.cancelSearch();
- mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_ENTER);
refreshDirectory(anim);
final RootsFragment roots = RootsFragment.get(getFragmentManager());
@@ -370,7 +366,6 @@ public abstract class BaseActivity extends Activity
*/
@Override
public void onSearchChanged() {
- mDirectoryContainer.setDrawDisappearingFirst(false);
refreshDirectory(ANIM_NONE);
}
@@ -539,16 +534,35 @@ public abstract class BaseActivity extends Activity
return;
}
- final int size = mState.stack.size();
+ int size = mState.stack.size();
+
+ // Do some "do what a I want" drawer fiddling, but don't
+ // do it if user already hit back recently and we recently
+ // did some fiddling.
+ if ((System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) {
+ // Close drawer if it is open.
+ if (mDrawer.isOpen()) {
+ mDrawer.setOpen(false);
+ mDrawerLastFiddled = System.currentTimeMillis();
+ return;
+ }
+
+ // Open the Close drawer if it is closed and we're at the top of a root.
+ if (size == 1) {
+ mDrawer.setOpen(true);
+ // Remember so we don't just close it again if back is pressed again.
+ mDrawerLastFiddled = System.currentTimeMillis();
+ return;
+ }
+ }
- if (mDrawer.isOpen()) {
- mDrawer.setOpen(false);
- } else if (size > 1) {
+ if (size > 1) {
mState.stack.pop();
refreshCurrentRootAndDirectory(ANIM_LEAVE);
- } else {
- super.onBackPressed();
+ return;
}
+
+ super.onBackPressed();
}
public void onStackPicked(DocumentStack stack) {
@@ -574,115 +588,40 @@ public abstract class BaseActivity extends Activity
}
}
- final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
+ private static final class PickRootTask extends PairedTask<BaseActivity, Void, DocumentInfo> {
private RootInfo mRoot;
- public PickRootTask(RootInfo root) {
+ public PickRootTask(BaseActivity activity, RootInfo root) {
+ super(activity);
mRoot = root;
}
@Override
- protected DocumentInfo doInBackground(Void... params) {
- return getRootDocumentBlocking(mRoot);
+ protected DocumentInfo run(Void... params) {
+ return mOwner.getRootDocumentBlocking(mRoot);
}
@Override
- protected void onPostExecute(DocumentInfo result) {
- if (result != null && !isDestroyed()) {
- openContainerDocument(result);
+ protected void finish(DocumentInfo result) {
+ if (result != null) {
+ mOwner.openContainerDocument(result);
}
}
}
- final class RestoreStackTask extends AsyncTask<Void, Void, Void> {
- private volatile boolean mRestoredStack;
- private volatile boolean mExternal;
-
- @Override
- protected Void doInBackground(Void... params) {
- if (DEBUG && !mState.stack.isEmpty()) {
- Log.w(mTag, "Overwriting existing stack.");
- }
- RootsCache roots = DocumentsApplication.getRootsCache(BaseActivity.this);
-
- // Restore last stack for calling package
- final String packageName = getCallingPackageMaybeExtra();
- final Cursor cursor = getContentResolver()
- .query(RecentsProvider.buildResume(packageName), null, null, null, null);
- try {
- if (cursor.moveToFirst()) {
- mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
- final byte[] rawStack = cursor.getBlob(
- cursor.getColumnIndex(ResumeColumns.STACK));
- DurableUtils.readFromArray(rawStack, mState.stack);
- mRestoredStack = true;
- }
- } catch (IOException e) {
- Log.w(mTag, "Failed to resume: " + e);
- } finally {
- IoUtils.closeQuietly(cursor);
- }
-
- if (mRestoredStack) {
- // Update the restored stack to ensure we have freshest data
- final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(mState);
- try {
- mState.stack.updateRoot(matchingRoots);
- mState.stack.updateDocuments(getContentResolver());
- } catch (FileNotFoundException e) {
- Log.w(mTag, "Failed to restore stack: " + e);
- mState.stack.reset();
- mRestoredStack = false;
- }
- }
-
- return null;
- }
-
- @Override
- protected void onPostExecute(Void result) {
- if (isDestroyed()) return;
- mState.restored = true;
- refreshCurrentRootAndDirectory(ANIM_NONE);
- onStackRestored(mRestoredStack, mExternal);
- }
- }
-
- final class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
- private Uri mRootUri;
-
- public RestoreRootTask(Uri rootUri) {
- mRootUri = rootUri;
- }
-
- @Override
- protected RootInfo doInBackground(Void... params) {
- final String rootId = DocumentsContract.getRootId(mRootUri);
- return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
- }
+ private static final class HandleRootsChangedTask
+ extends PairedTask<BaseActivity, RootInfo, RootInfo> {
+ DocumentInfo mHome;
- @Override
- protected void onPostExecute(RootInfo root) {
- if (isDestroyed()) return;
- mState.restored = true;
-
- if (root != null) {
- onRootPicked(root);
- } else {
- Log.w(mTag, "Failed to find root: " + mRootUri);
- finish();
- }
+ public HandleRootsChangedTask(BaseActivity activity) {
+ super(activity);
}
- }
-
- final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> {
- DocumentInfo mHome;
@Override
- protected RootInfo doInBackground(RootInfo... roots) {
+ protected RootInfo run(RootInfo... roots) {
checkArgument(roots.length == 1);
final RootInfo currentRoot = roots[0];
- final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking();
+ final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
RootInfo homeRoot = null;
for (final RootInfo root : cachedRoots) {
if (root.isHome()) {
@@ -694,17 +633,17 @@ public abstract class BaseActivity extends Activity
}
}
Preconditions.checkNotNull(homeRoot);
- mHome = getRootDocumentBlocking(homeRoot);
+ mHome = mOwner.getRootDocumentBlocking(homeRoot);
return homeRoot;
}
@Override
- protected void onPostExecute(RootInfo homeRoot) {
- if (homeRoot != null && mHome != null && !isDestroyed()) {
+ protected void finish(RootInfo homeRoot) {
+ if (homeRoot != null && mHome != null) {
// Clear entire backstack and start in new root
- mState.onRootChanged(homeRoot);
- mSearchManager.update(homeRoot);
- openContainerDocument(mHome);
+ mOwner.mState.onRootChanged(homeRoot);
+ mOwner.mSearchManager.update(homeRoot);
+ mOwner.openContainerDocument(mHome);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
deleted file mode 100644
index 71ea8a9352f6..000000000000
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryContainerView.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2013 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.documentsui;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import java.util.ArrayList;
-
-public class DirectoryContainerView extends FrameLayout {
- private boolean mDisappearingFirst = false;
-
- public DirectoryContainerView(Context context) {
- super(context);
- }
-
- public DirectoryContainerView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- final ArrayList<View> disappearing = mDisappearingChildren;
- if (mDisappearingFirst && disappearing != null) {
- for (int i = 0; i < disappearing.size(); i++) {
- super.drawChild(canvas, disappearing.get(i), getDrawingTime());
- }
- }
- super.dispatchDraw(canvas);
- }
-
- @Override
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- if (mDisappearingFirst && mDisappearingChildren != null
- && mDisappearingChildren.contains(child)) {
- return false;
- }
- return super.drawChild(canvas, child, drawingTime);
- }
-
- public void setDrawDisappearingFirst(boolean disappearingFirst) {
- mDisappearingFirst = disappearingFirst;
- }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 815ff3db9517..3485fe4446f5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -16,6 +16,7 @@
package com.android.documentsui;
+import static com.android.documentsui.Shared.DEBUG;
import static com.android.documentsui.State.ACTION_CREATE;
import static com.android.documentsui.State.ACTION_GET_CONTENT;
import static com.android.documentsui.State.ACTION_OPEN;
@@ -31,11 +32,12 @@ import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
@@ -52,7 +54,12 @@ import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperationService;
+import libcore.io.IoUtils;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
public class DocumentsActivity extends BaseActivity {
@@ -94,16 +101,14 @@ public class DocumentsActivity extends BaseActivity {
// In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
// talkback from reading aloud the default title, we clear it here.
setTitle("");
- new RestoreStackTask().execute();
+ new RestoreStackTask(this).execute();
} else {
refreshCurrentRootAndDirectory(ANIM_NONE);
}
}
@Override
- State buildState() {
- State state = buildDefaultState();
-
+ void includeState(State state) {
final Intent intent = getIntent();
final String action = intent.getAction();
if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
@@ -134,8 +139,6 @@ public class DocumentsActivity extends BaseActivity {
state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION,
FileOperationService.OPERATION_COPY);
}
-
- return state;
}
@Override
@@ -218,14 +221,6 @@ public class DocumentsActivity extends BaseActivity {
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- boolean showMenu = super.onCreateOptionsMenu(menu);
-
- expandMenus(menu);
- return showMenu;
- }
-
- @Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
@@ -319,11 +314,13 @@ public class DocumentsActivity extends BaseActivity {
}
void onSaveRequested(DocumentInfo replaceTarget) {
- new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
+ new ExistingFinishTask(this, replaceTarget.derivedUri)
+ .executeOnExecutor(getExecutorForCurrentDirectory());
}
void onSaveRequested(String mimeType, String displayName) {
- new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory());
+ new CreateFinishTask(this, mimeType, displayName)
+ .executeOnExecutor(getExecutorForCurrentDirectory());
}
@Override
@@ -343,7 +340,8 @@ public class DocumentsActivity extends BaseActivity {
openContainerDocument(doc);
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
- new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
+ new ExistingFinishTask(this, doc.derivedUri)
+ .executeOnExecutor(getExecutorForCurrentDirectory());
} else if (mState.action == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
@@ -358,7 +356,8 @@ public class DocumentsActivity extends BaseActivity {
for (int i = 0; i < size; i++) {
uris[i] = docs.get(i).derivedUri;
}
- new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory());
+ new ExistingFinishTask(this, uris)
+ .executeOnExecutor(getExecutorForCurrentDirectory());
}
}
@@ -373,11 +372,10 @@ public class DocumentsActivity extends BaseActivity {
// Should not be reached.
throw new IllegalStateException("Invalid mState.action.");
}
- new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory());
+ new PickFinishTask(this, result).executeOnExecutor(getExecutorForCurrentDirectory());
}
- @Override
- void saveStackBlocking() {
+ void writeStackToRecentsBlocking() {
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
@@ -438,69 +436,137 @@ public class DocumentsActivity extends BaseActivity {
finish();
}
+
public static DocumentsActivity get(Fragment fragment) {
return (DocumentsActivity) fragment.getActivity();
}
- private final class PickFinishTask extends AsyncTask<Void, Void, Void> {
+ /**
+ * Restores the stack from Recents for the specified package.
+ */
+ private static final class RestoreStackTask
+ extends PairedTask<DocumentsActivity, Void, Void> {
+
+ private volatile boolean mRestoredStack;
+ private volatile boolean mExternal;
+ private State mState;
+
+ public RestoreStackTask(DocumentsActivity activity) {
+ super(activity);
+ mState = activity.mState;
+ }
+
+ @Override
+ protected Void run(Void... params) {
+ if (DEBUG && !mState.stack.isEmpty()) {
+ Log.w(TAG, "Overwriting existing stack.");
+ }
+ RootsCache roots = DocumentsApplication.getRootsCache(mOwner);
+
+ String packageName = mOwner.getCallingPackageMaybeExtra();
+ Uri resumeUri = RecentsProvider.buildResume(packageName);
+ Cursor cursor = mOwner.getContentResolver().query(resumeUri, null, null, null, null);
+ try {
+ if (cursor.moveToFirst()) {
+ mExternal = cursor.getInt(cursor.getColumnIndex(ResumeColumns.EXTERNAL)) != 0;
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(ResumeColumns.STACK));
+ DurableUtils.readFromArray(rawStack, mState.stack);
+ mRestoredStack = true;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to resume: " + e);
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ if (mRestoredStack) {
+ // Update the restored stack to ensure we have freshest data
+ final Collection<RootInfo> matchingRoots = roots.getMatchingRootsBlocking(mState);
+ try {
+ mState.stack.updateRoot(matchingRoots);
+ mState.stack.updateDocuments(mOwner.getContentResolver());
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed to restore stack for package: " + packageName
+ + " because of error: "+ e);
+ mState.stack.reset();
+ mRestoredStack = false;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void finish(Void result) {
+ mState.restored = true;
+ mOwner.refreshCurrentRootAndDirectory(ANIM_NONE);
+ mOwner.onStackRestored(mRestoredStack, mExternal);
+ }
+ }
+
+ private static final class PickFinishTask extends PairedTask<DocumentsActivity, Void, Void> {
private final Uri mUri;
- public PickFinishTask(Uri uri) {
+ public PickFinishTask(DocumentsActivity activity, Uri uri) {
+ super(activity);
mUri = uri;
}
@Override
- protected Void doInBackground(Void... params) {
- saveStackBlocking();
+ protected Void run(Void... params) {
+ mOwner.writeStackToRecentsBlocking();
return null;
}
@Override
- protected void onPostExecute(Void result) {
- onTaskFinished(mUri);
+ protected void finish(Void result) {
+ mOwner.onTaskFinished(mUri);
}
}
- final class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
+ private static final class ExistingFinishTask extends PairedTask<DocumentsActivity, Void, Void> {
private final Uri[] mUris;
- public ExistingFinishTask(Uri... uris) {
+ public ExistingFinishTask(DocumentsActivity activity, Uri... uris) {
+ super(activity);
mUris = uris;
}
@Override
- protected Void doInBackground(Void... params) {
- saveStackBlocking();
+ protected Void run(Void... params) {
+ mOwner.writeStackToRecentsBlocking();
return null;
}
@Override
- protected void onPostExecute(Void result) {
- onTaskFinished(mUris);
+ protected void finish(Void result) {
+ mOwner.onTaskFinished(mUris);
}
}
/**
* Task that creates a new document in the background.
*/
- final class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
+ private static final class CreateFinishTask extends PairedTask<DocumentsActivity, Void, Uri> {
private final String mMimeType;
private final String mDisplayName;
- public CreateFinishTask(String mimeType, String displayName) {
+ public CreateFinishTask(DocumentsActivity activity, String mimeType, String displayName) {
+ super(activity);
mMimeType = mimeType;
mDisplayName = displayName;
}
@Override
- protected void onPreExecute() {
- setPending(true);
+ protected void prepare() {
+ mOwner.setPending(true);
}
@Override
- protected Uri doInBackground(Void... params) {
- final ContentResolver resolver = getContentResolver();
- final DocumentInfo cwd = getCurrentDirectory();
+ protected Uri run(Void... params) {
+ final ContentResolver resolver = mOwner.getContentResolver();
+ final DocumentInfo cwd = mOwner.getCurrentDirectory();
ContentProviderClient client = null;
Uri childUri = null;
@@ -516,22 +582,22 @@ public class DocumentsActivity extends BaseActivity {
}
if (childUri != null) {
- saveStackBlocking();
+ mOwner.writeStackToRecentsBlocking();
}
return childUri;
}
@Override
- protected void onPostExecute(Uri result) {
+ protected void finish(Uri result) {
if (result != null) {
- onTaskFinished(result);
+ mOwner.onTaskFinished(result);
} else {
Snackbars.makeSnackbar(
- DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show();
+ mOwner, R.string.save_error, Snackbar.LENGTH_SHORT).show();
}
- setPending(false);
+ mOwner.setPending(false);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index 89be9107e077..d589d5e0e237 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -24,8 +24,6 @@ import android.app.Fragment;
import android.app.FragmentManager;
import android.content.ActivityNotFoundException;
import android.content.ClipData;
-import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -37,10 +35,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toolbar;
-import com.android.documentsui.RecentsProvider.ResumeColumns;
import com.android.documentsui.dirlist.DirectoryFragment;
import com.android.documentsui.model.DocumentInfo;
-import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
import com.android.internal.util.Preconditions;
@@ -72,23 +68,19 @@ public class DownloadsActivity extends BaseActivity {
// talkback from reading aloud the default title, we clear it here.
setTitle("");
final Uri rootUri = getIntent().getData();
- new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
+ new RestoreRootTask(this, rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
} else {
refreshCurrentRootAndDirectory(ANIM_NONE);
}
}
@Override
- State buildState() {
- State state = buildDefaultState();
-
+ void includeState(State state) {
state.action = ACTION_MANAGE;
state.acceptMimes = new String[] { "*/*" };
state.allowMultiple = true;
state.showSize = true;
state.excludedAuthorities = getExcludedAuthorities();
-
- return state;
}
@Override
@@ -108,14 +100,12 @@ public class DownloadsActivity extends BaseActivity {
final MenuItem advanced = menu.findItem(R.id.menu_advanced);
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
- final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
advanced.setVisible(false);
createDir.setVisible(false);
pasteFromCb.setEnabled(false);
- newWindow.setEnabled(false);
fileSize.setVisible(false);
Menus.disableHiddenItems(menu);
@@ -170,21 +160,6 @@ public class DownloadsActivity extends BaseActivity {
public void onDocumentsPicked(List<DocumentInfo> docs) {}
@Override
- void saveStackBlocking() {
- final ContentResolver resolver = getContentResolver();
- final ContentValues values = new ContentValues();
-
- final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
-
- // Remember location for next app launch
- final String packageName = getCallingPackageMaybeExtra();
- values.clear();
- values.put(ResumeColumns.STACK, rawStack);
- values.put(ResumeColumns.EXTERNAL, 0);
- resolver.insert(RecentsProvider.buildResume(packageName), values);
- }
-
- @Override
void onTaskFinished(Uri... uris) {
Log.d(TAG, "onFinished() " + Arrays.toString(uris));
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 3aba356793df..c81f342822f6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -30,7 +30,6 @@ import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
@@ -98,19 +97,19 @@ public class FilesActivity extends BaseActivity {
refreshCurrentRootAndDirectory(ANIM_NONE);
} else if (intent.getAction() == Intent.ACTION_VIEW) {
checkArgument(uri != null);
- new OpenUriForViewTask().executeOnExecutor(
+ new OpenUriForViewTask(this).executeOnExecutor(
ProviderExecutor.forAuthority(uri.getAuthority()), uri);
} else if (DocumentsContract.isRootUri(this, uri)) {
if (DEBUG) Log.d(TAG, "Launching with root URI.");
// If we've got a specific root to display, restore that root using a dedicated
// authority. That way a misbehaving provider won't result in an ANR.
- new RestoreRootTask(uri).executeOnExecutor(
+ new RestoreRootTask(this, uri).executeOnExecutor(
ProviderExecutor.forAuthority(uri.getAuthority()));
} else {
if (DEBUG) Log.d(TAG, "Launching into Home directory.");
// If all else fails, try to load "Home" directory.
final Uri homeUri = DocumentsContract.buildHomeUri();
- new RestoreRootTask(homeUri).executeOnExecutor(
+ new RestoreRootTask(this, homeUri).executeOnExecutor(
ProviderExecutor.forAuthority(homeUri.getAuthority()));
}
@@ -134,9 +133,7 @@ public class FilesActivity extends BaseActivity {
}
@Override
- State buildState() {
- State state = buildDefaultState();
-
+ void includeState(State state) {
final Intent intent = getIntent();
state.action = State.ACTION_BROWSE;
@@ -149,8 +146,6 @@ public class FilesActivity extends BaseActivity {
if (stack != null) {
state.stack = stack;
}
-
- return state;
}
@Override
@@ -190,14 +185,6 @@ public class FilesActivity extends BaseActivity {
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- boolean showMenu = super.onCreateOptionsMenu(menu);
-
- expandMenus(menu);
- return showMenu;
- }
-
- @Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
@@ -206,15 +193,13 @@ public class FilesActivity extends BaseActivity {
final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
final MenuItem settings = menu.findItem(R.id.menu_settings);
+ final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
createDir.setVisible(true);
createDir.setEnabled(canCreateDirectory());
pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
settings.setVisible(root.hasSettings());
-
- // TODO: For some reason settings menu item is not
- // honoring the "showAsAction=never" setting in activity.xml.
- settings.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ newWindow.setVisible(true);
Menus.disableHiddenItems(menu, pasteFromCb);
return true;
@@ -363,13 +348,15 @@ public class FilesActivity extends BaseActivity {
}
}
- @Override
- void saveStackBlocking() {
+ // Turns out only DocumentsActivity was ever calling saveStackBlocking.
+ // There may be a case where we want to contribute entries from
+ // Behavior here in FilesActivity, but it isn't yet obvious.
+ // TODO: Contribute to recents, or remove this.
+ void writeStackToRecentsBlocking() {
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
- final byte[] rawStack = DurableUtils.writeToArrayOrNull(
- getDisplayState().stack);
+ final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
// Remember location for next app launch
final String packageName = getCallingPackageMaybeExtra();
@@ -408,12 +395,19 @@ public class FilesActivity extends BaseActivity {
* to know which root to select. Also, the stack doesn't contain intermediate directories.
* It's primarly used for opening ZIP archives from Downloads app.
*/
- final class OpenUriForViewTask extends AsyncTask<Uri, Void, Void> {
+ private static final class OpenUriForViewTask extends PairedTask<FilesActivity, Uri, Void> {
+
+ private final State mState;
+ public OpenUriForViewTask(FilesActivity activity) {
+ super(activity);
+ mState = activity.mState;
+ }
+
@Override
- protected Void doInBackground(Uri... params) {
+ protected Void run(Uri... params) {
final Uri uri = params[0];
- final RootsCache rootsCache = DocumentsApplication.getRootsCache(FilesActivity.this);
+ final RootsCache rootsCache = DocumentsApplication.getRootsCache(mOwner);
final String authority = uri.getAuthority();
final Collection<RootInfo> roots =
@@ -426,20 +420,17 @@ public class FilesActivity extends BaseActivity {
final RootInfo root = roots.iterator().next();
mState.stack.root = root;
try {
- mState.stack.add(DocumentInfo.fromUri(getContentResolver(), uri));
+ mState.stack.add(DocumentInfo.fromUri(mOwner.getContentResolver(), uri));
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri);
}
- mState.stack.add(getRootDocumentBlocking(root));
+ mState.stack.add(mOwner.getRootDocumentBlocking(root));
return null;
}
@Override
- protected void onPostExecute(Void result) {
- if (isDestroyed()) {
- return;
- }
- refreshCurrentRootAndDirectory(ANIM_NONE);
+ protected void finish(Void result) {
+ mOwner.refreshCurrentRootAndDirectory(ANIM_NONE);
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java
new file mode 100644
index 000000000000..b74acb8e38c3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/PairedTask.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package com.android.documentsui;
+
+import android.app.Activity;
+import android.os.AsyncTask;
+
+/**
+ * An {@link AsyncTask} that guards work with checks that a paired {@link Activity}
+ * is still alive. Instances of this class make no progress.
+ *
+ * <p>Use this type of task for greater safety when executing tasks that might complete
+ * after an Activity is destroyed.
+ *
+ * <p>Also useful as tasks can be static, limiting scope, but still have access to
+ * the owning class (by way the A template and the mActivity field).
+ *
+ * @template Owner Activity type.
+ * @template Input input type
+ * @template Output output type
+ */
+abstract class PairedTask<Owner extends Activity, Input, Output>
+ extends AsyncTask<Input, Void, Output> {
+
+ protected final Owner mOwner;
+
+ public PairedTask(Owner owner) {
+ mOwner = owner;
+ }
+
+ /** Called prior to run being executed. Analogous to {@link AsyncTask#onPreExecute} */
+ void prepare() {}
+
+ /** Analogous to {@link AsyncTask#doInBackground} */
+ abstract Output run(Input... input);
+
+ /** Analogous to {@link AsyncTask#onPostExecute} */
+ abstract void finish(Output output);
+
+ @Override
+ final protected void onPreExecute() {
+ if (mOwner.isDestroyed()) {
+ return;
+ }
+ prepare();
+ }
+
+ @Override
+ final protected Output doInBackground(Input... input) {
+ if (mOwner.isDestroyed()) {
+ return null;
+ }
+ return run(input);
+ }
+
+ @Override
+ final protected void onPostExecute(Output result) {
+ if (mOwner.isDestroyed()) {
+ return;
+ }
+ finish(result);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java
new file mode 100644
index 000000000000..9048b9d45ee7
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RestoreRootTask.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package com.android.documentsui;
+
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import com.android.documentsui.model.RootInfo;
+
+final class RestoreRootTask extends PairedTask<BaseActivity, Void, RootInfo> {
+ private static final String TAG = "RestoreRootTask";
+
+ private final Uri mRootUri;
+
+ public RestoreRootTask(BaseActivity activity, Uri rootUri) {
+ super(activity);
+ mRootUri = rootUri;
+ }
+
+ @Override
+ protected RootInfo run(Void... params) {
+ String rootId = DocumentsContract.getRootId(mRootUri);
+ return mOwner.mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+ }
+
+ @Override
+ protected void finish(RootInfo root) {
+ mOwner.mState.restored = true;
+
+ if (root != null) {
+ mOwner.onRootPicked(root);
+ } else {
+ Log.w(TAG, "Failed to find root: " + mRootUri);
+ mOwner.finish();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index 28f743243234..d141de667f2f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -158,9 +158,14 @@ public class State implements android.os.Parcelable {
out.writeInt(mStackTouched ? 1 : 0);
}
- public static final Creator<State> CREATOR = new Creator<State>() {
+ public static final ClassLoaderCreator<State> CREATOR = new ClassLoaderCreator<State>() {
@Override
public State createFromParcel(Parcel in) {
+ return createFromParcel(in, null);
+ }
+
+ @Override
+ public State createFromParcel(Parcel in, ClassLoader loader) {
final State state = new State();
state.action = in.readInt();
state.acceptMimes = in.readStringArray();
@@ -174,9 +179,9 @@ public class State implements android.os.Parcelable {
state.restored = in.readInt() != 0;
DurableUtils.readFromParcel(in, state.stack);
state.currentSearch = in.readString();
- in.readMap(state.dirState, null);
- in.readList(state.selectedDocumentsForCopy, null);
- in.readList(state.excludedAuthorities, null);
+ in.readMap(state.dirState, loader);
+ in.readList(state.selectedDocumentsForCopy, loader);
+ in.readList(state.excludedAuthorities, loader);
state.openableOnly = in.readInt() != 0;
state.mStackTouched = in.readInt() != 0;
return state;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 1e3da6b1ac8a..70bee3cd3c6e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -100,7 +100,6 @@ import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperations;
-
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -854,27 +853,28 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi
}
private void showEmptyDirectory() {
- showEmptyView(R.string.empty);
+ showEmptyView(R.string.empty, R.drawable.cabinet);
}
private void showNoResults(RootInfo root) {
CharSequence msg = getContext().getResources().getText(R.string.no_results);
- showEmptyView(String.format(String.valueOf(msg), root.title));
+ showEmptyView(String.format(String.valueOf(msg), root.title), R.drawable.cabinet);
}
- // Shows an error indicating documents couldn't be queried.
private void showQueryError() {
- showEmptyView(R.string.query_error);
+ showEmptyView(R.string.query_error, R.drawable.hourglass);
}
- private void showEmptyView(@StringRes int id) {
- showEmptyView(getContext().getResources().getText(id));
+ private void showEmptyView(@StringRes int id, int drawable) {
+ showEmptyView(getContext().getResources().getText(id), drawable);
}
- private void showEmptyView(CharSequence msg) {
+ private void showEmptyView(CharSequence msg, int drawable) {
View content = mEmptyView.findViewById(R.id.content);
TextView msgView = (TextView) mEmptyView.findViewById(R.id.message);
+ ImageView imageView = (ImageView) mEmptyView.findViewById(R.id.artwork);
msgView.setText(msg);
+ imageView.setImageResource(drawable);
content.animate().cancel(); // cancel any ongoing animations
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index 1829746bb143..ef1e8e20aaff 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -24,9 +24,11 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
import android.provider.DocumentsContract;
+import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
@@ -56,11 +58,17 @@ class DocumentLoader {
private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
throws IOException {
- final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
+ final ArrayList<MtpObjectInfo> objects = new ArrayList<>();
for (int i = 0; i < handles.length; i++) {
- objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
+ final MtpObjectInfo info = manager.getObjectInfo(deviceId, handles[i]);
+ if (info == null) {
+ Log.e(MtpDocumentsProvider.TAG,
+ "Failed to obtain object info handle=" + handles[i]);
+ continue;
+ }
+ objects.add(info);
}
- return objectInfos;
+ return objects.toArray(new MtpObjectInfo[objects.size()]);
}
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index b44f9af3c3bc..8a3ebefa127f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -577,9 +577,7 @@ class MtpDatabase {
static void getObjectDocumentValues(
ContentValues values, int deviceId, String parentId, MtpObjectInfo info) {
values.clear();
- final String mimeType = info.getFormat() == MtpConstants.FORMAT_ASSOCIATION ?
- DocumentsContract.Document.MIME_TYPE_DIR :
- MediaFile.getMimeTypeForFormatCode(info.getFormat());
+ final String mimeType = getMimeType(info);
int flag = 0;
if (info.getProtectionStatus() == 0) {
flag |= Document.FLAG_SUPPORTS_DELETE |
@@ -608,6 +606,17 @@ class MtpDatabase {
values.put(Document.COLUMN_SIZE, info.getCompressedSize());
}
+ private static String getMimeType(MtpObjectInfo info) {
+ if (info.getFormat() == MtpConstants.FORMAT_ASSOCIATION) {
+ return DocumentsContract.Document.MIME_TYPE_DIR;
+ }
+ final String formatCodeMimeType = MediaFile.getMimeTypeForFormatCode(info.getFormat());
+ if (formatCodeMimeType != null) {
+ return formatCodeMimeType;
+ }
+ return MediaFile.getMimeTypeForFile(info.getName());
+ }
+
static String[] strings(Object... args) {
final String[] results = new String[args.length];
for (int i = 0; i < args.length; i++) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 70a1aae86b95..033845401b4b 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -184,6 +184,9 @@ public class MtpDocumentsProvider extends DocumentsProvider {
public ParcelFileDescriptor openDocument(
String documentId, String mode, CancellationSignal signal)
throws FileNotFoundException {
+ if (DEBUG) {
+ Log.d(TAG, "openDocument: " + documentId);
+ }
final Identifier identifier = mDatabase.createIdentifier(documentId);
try {
openDevice(identifier.mDeviceId);
@@ -270,6 +273,9 @@ public class MtpDocumentsProvider extends DocumentsProvider {
@Override
public String createDocument(String parentDocumentId, String mimeType, String displayName)
throws FileNotFoundException {
+ if (DEBUG) {
+ Log.d(TAG, "createDocument: " + displayName);
+ }
try {
final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
openDevice(parentId.mDeviceId);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 78c530c2b0d7..f8851101abc2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -155,7 +155,7 @@ public class RestrictedLockUtils {
for (UserInfo userInfo : um.getProfiles(userId)) {
final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
if (admins == null) {
- return null;
+ continue;
}
final boolean isSeparateProfileChallengeEnabled =
lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
@@ -209,16 +209,7 @@ public class RestrictedLockUtils {
IPackageManager ipm = AppGlobals.getPackageManager();
try {
if (ipm.getBlockUninstallForUser(packageName, userId)) {
- DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- if (dpm == null) {
- return null;
- }
- ComponentName admin = dpm.getProfileOwner();
- if (admin == null) {
- admin = dpm.getDeviceOwnerComponentOnCallingUser();
- }
- return new EnforcedAdmin(admin, UserHandle.myUserId());
+ return getProfileOrDeviceOwner(context, userId);
}
} catch (RemoteException e) {
// Nothing to do
@@ -238,7 +229,7 @@ public class RestrictedLockUtils {
try {
ApplicationInfo ai = ipm.getApplicationInfo(packageName, 0, userId);
if (ai != null && ((ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0)) {
- return getProfileOrDeviceOwnerOnCallingUser(context);
+ return getProfileOrDeviceOwner(context, userId);
}
} catch (RemoteException e) {
// Nothing to do
@@ -246,6 +237,80 @@ public class RestrictedLockUtils {
return null;
}
+ public static EnforcedAdmin checkIfInputMethodDisallowed(Context context,
+ String packageName, int userId) {
+ DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (dpm == null) {
+ return null;
+ }
+ EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+ boolean permitted = true;
+ if (admin != null) {
+ permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
+ packageName, userId);
+ }
+ int managedProfileId = getManagedProfileId(context, userId);
+ EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+ boolean permittedByProfileAdmin = true;
+ if (profileAdmin != null) {
+ permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component,
+ packageName, managedProfileId);
+ }
+ if (!permitted && !permittedByProfileAdmin) {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ } else if (!permitted) {
+ return admin;
+ } else if (!permittedByProfileAdmin) {
+ return profileAdmin;
+ }
+ return null;
+ }
+
+ public static EnforcedAdmin checkIfAccessibilityServiceDisallowed(Context context,
+ String packageName, int userId) {
+ DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ if (dpm == null) {
+ return null;
+ }
+ EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+ boolean permitted = true;
+ if (admin != null) {
+ permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
+ packageName, userId);
+ }
+ int managedProfileId = getManagedProfileId(context, userId);
+ EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+ boolean permittedByProfileAdmin = true;
+ if (profileAdmin != null) {
+ permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
+ profileAdmin.component, packageName, managedProfileId);
+ }
+ if (!permitted && !permittedByProfileAdmin) {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ } else if (!permitted) {
+ return admin;
+ } else if (!permittedByProfileAdmin) {
+ return profileAdmin;
+ }
+ return null;
+ }
+
+ private static int getManagedProfileId(Context context, int userId) {
+ UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ List<UserInfo> userProfiles = um.getProfiles(userId);
+ for (UserInfo uInfo : userProfiles) {
+ if (uInfo.id == userId) {
+ continue;
+ }
+ if (uInfo.isManagedProfile()) {
+ return uInfo.id;
+ }
+ }
+ return UserHandle.USER_NULL;
+ }
+
/**
* Check if account management for a specific type of account is disabled by admin.
* Only a profile or device owner can disable account management. So, we check if account
@@ -255,7 +320,7 @@ public class RestrictedLockUtils {
* or {@code null} if the account management is not disabled.
*/
public static EnforcedAdmin checkIfAccountManagementDisabled(Context context,
- String accountType) {
+ String accountType, int userId) {
if (accountType == null) {
return null;
}
@@ -265,7 +330,7 @@ public class RestrictedLockUtils {
return null;
}
boolean isAccountTypeDisabled = false;
- String[] disabledTypes = dpm.getAccountTypesWithManagementDisabled();
+ String[] disabledTypes = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
for (String type : disabledTypes) {
if (accountType.equals(type)) {
isAccountTypeDisabled = true;
@@ -275,7 +340,7 @@ public class RestrictedLockUtils {
if (!isAccountTypeDisabled) {
return null;
}
- return getProfileOrDeviceOwnerOnCallingUser(context);
+ return getProfileOrDeviceOwner(context, userId);
}
/**
@@ -296,7 +361,7 @@ public class RestrictedLockUtils {
}
/**
- * Checks if an admin has enforced minimum password quality requirements on the device.
+ * Checks if an admin has enforced minimum password quality requirements on the given user.
*
* @return EnforcedAdmin Object containing the enforced admin component and admin user details,
* or {@code null} if no quality requirements are set. If the requirements are set by
@@ -304,35 +369,73 @@ public class RestrictedLockUtils {
* {@link UserHandle#USER_NULL}.
*
*/
- public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context) {
+ public static EnforcedAdmin checkIfPasswordQualityIsSet(Context context, int userId) {
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (dpm == null) {
return null;
}
- boolean isDisabledByMultipleAdmins = false;
- ComponentName adminComponent = null;
- List<ComponentName> admins = dpm.getActiveAdmins();
- int quality;
- if (admins != null) {
+
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+ EnforcedAdmin enforcedAdmin = null;
+ if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+ // userId is managed profile and has a separate challenge, only consider
+ // the admins in that user.
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
+ if (admins == null) {
+ return null;
+ }
for (ComponentName admin : admins) {
- quality = dpm.getPasswordQuality(admin);
- if (quality >= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
- if (adminComponent == null) {
- adminComponent = admin;
+ if (dpm.getPasswordQuality(admin, userId)
+ > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userId);
} else {
- isDisabledByMultipleAdmins = true;
- break;
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
}
}
- }
- EnforcedAdmin enforcedAdmin = null;
- if (adminComponent != null) {
- if (!isDisabledByMultipleAdmins) {
- enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
- } else {
- enforcedAdmin = new EnforcedAdmin();
+ } else {
+ // Return all admins for this user and the profiles that are visible from this
+ // user that do not use a separate work challenge.
+ final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ for (UserInfo userInfo : um.getProfiles(userId)) {
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+ if (admins == null) {
+ continue;
+ }
+ final boolean isSeparateProfileChallengeEnabled =
+ lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+ for (ComponentName admin : admins) {
+ if (!isSeparateProfileChallengeEnabled) {
+ if (dpm.getPasswordQuality(admin, userInfo.id)
+ > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ // This same admins could have set policies both on the managed profile
+ // and on the parent. So, if the admin has set the policy on the
+ // managed profile here, we don't need to further check if that admin
+ // has set policy on the parent admin.
+ continue;
+ }
+ }
+ if (userInfo.isManagedProfile()) {
+ // If userInfo.id is a managed profile, we also need to look at
+ // the policies set on the parent.
+ DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+ if (parentDpm.getPasswordQuality(admin, userInfo.id)
+ > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ }
+ }
+ }
}
}
return enforcedAdmin;
@@ -352,7 +455,8 @@ public class RestrictedLockUtils {
EnforcedAdmin enforcedAdmin = null;
final int userId = UserHandle.myUserId();
if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
- // If the user has a separate challenge, only consider the admins in that user.
+ // userId is managed profile and has a separate challenge, only consider
+ // the admins in that user.
final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
if (admins == null) {
return null;
@@ -373,7 +477,7 @@ public class RestrictedLockUtils {
for (UserInfo userInfo : um.getProfiles(userId)) {
final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
if (admins == null) {
- return null;
+ continue;
}
final boolean isSeparateProfileChallengeEnabled =
lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
@@ -410,19 +514,24 @@ public class RestrictedLockUtils {
return enforcedAdmin;
}
- public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) {
+ public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ return null;
+ }
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (dpm == null) {
return null;
}
- ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
+ ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
if (adminComponent != null) {
- return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+ return new EnforcedAdmin(adminComponent, userId);
}
- adminComponent = dpm.getProfileOwner();
- if (adminComponent != null) {
- return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+ if (dpm.getDeviceOwnerUserId() == userId) {
+ adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
+ if (adminComponent != null) {
+ return new EnforcedAdmin(adminComponent, userId);
+ }
}
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index f5a2aaec97d7..d368de93e263 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -15,40 +15,19 @@
*/
package com.android.settingslib;
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.SystemProperties;
-import android.os.UserManager;
-import android.provider.Settings;
import android.telephony.CarrierConfigManager;
public class TetherUtil {
- // Extras used for communicating with the TetherService.
- public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
- public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
- public static final String EXTRA_SET_ALARM = "extraSetAlarm";
- /**
- * Tells the service to run a provision check now.
- */
- public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-
public static boolean setWifiTethering(boolean enable, Context context) {
final WifiManager wifiManager =
(WifiManager) context.getSystemService(Context.WIFI_SERVICE);
return wifiManager.setWifiApEnabled(null, enable);
}
- public static boolean isWifiTetherEnabled(Context context) {
- WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
- }
-
private static boolean isEntitlementCheckRequired(Context context) {
final CarrierConfigManager configManager = (CarrierConfigManager) context
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -71,13 +50,4 @@ public class TetherUtil {
}
return (provisionApp.length == 2);
}
-
- public static boolean isTetheringSupported(Context context) {
- final ConnectivityManager cm =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- final boolean isAdminUser =
- UserManager.get(context).isUserAdmin(ActivityManager.getCurrentUser());
- return isAdminUser && cm.isTetheringSupported();
- }
-
}
diff --git a/packages/SystemUI/res/anim/recents_from_app_enter.xml b/packages/SystemUI/res/anim/recents_from_app_enter.xml
deleted file mode 100644
index 10ddce68dcaf..000000000000
--- a/packages/SystemUI/res/anim/recents_from_app_enter.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Recents Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="0"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_from_app_exit.xml b/packages/SystemUI/res/anim/recents_from_app_exit.xml
deleted file mode 100644
index c98ecf43eb65..000000000000
--- a/packages/SystemUI/res/anim/recents_from_app_exit.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-<!-- Incoming Activity -->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
-
- <!-- Animate the view out only after recents is visible -->
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/fast_out_slow_in"
- android:duration="1"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
index b191e625177b..00b3dfda135e 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_enter.xml
@@ -23,6 +23,6 @@
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
android:duration="150"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
index fa6caf295cce..33831b8c0a32 100644
--- a/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_launcher_exit.xml
@@ -23,6 +23,6 @@
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear_out_slow_in"
- android:duration="150"/>
+ android:interpolator="@interpolator/recents_from_launcher_exit_interpolator"
+ android:duration="133"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
index e0e2fc83a816..23cedf85adf6 100644
--- a/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_from_search_launcher_exit.xml
@@ -23,6 +23,6 @@
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear_out_slow_in"
- android:duration="@integer/recents_enter_from_home_transition_duration"/>
+ android:interpolator="@interpolator/recents_from_launcher_exit_interpolator"
+ android:duration="133"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
deleted file mode 100644
index 1135bc097fcf..000000000000
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <!--scale android:fromXScale="2.0" android:toXScale="1.0"
- android:fromYScale="2.0" android:toYScale="1.0"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:duration="250" /-->
-</set>
diff --git a/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml
deleted file mode 100644
index e95e667507f3..000000000000
--- a/packages/SystemUI/res/anim/recents_return_to_launcher_exit.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <!--scale android:fromXScale="1.0" android:toXScale="2.0"
- android:fromYScale="1.0" android:toYScale="2.0"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:pivotX="50%p" android:pivotY="50%p"
- android:duration="250" /-->
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
index b191e625177b..544ec88d2bfa 100644
--- a/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_to_launcher_enter.xml
@@ -23,6 +23,6 @@
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:duration="150"/>
+ android:interpolator="@interpolator/recents_to_launcher_enter_interpolator"
+ android:duration="133"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
index fa6caf295cce..226edb85d049 100644
--- a/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_to_launcher_exit.xml
@@ -24,5 +24,5 @@
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
android:interpolator="@android:interpolator/linear_out_slow_in"
- android:duration="150"/>
+ android:duration="1"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
index ea8283511b96..657b2164d6f2 100644
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_to_search_launcher_enter.xml
@@ -23,6 +23,6 @@
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/linear"
- android:duration="100"/>
+ android:interpolator="@interpolator/recents_to_launcher_enter_interpolator"
+ android:duration="133"/>
</set>
diff --git a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
index a8bdc8e45f59..5182cab29ee4 100644
--- a/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_to_search_launcher_exit.xml
@@ -24,5 +24,5 @@
android:fillEnabled="true"
android:fillBefore="true" android:fillAfter="true"
android:interpolator="@android:interpolator/linear"
- android:duration="100"/>
+ android:duration="1"/>
</set>
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
deleted file mode 100644
index 73ae9f2a25ee..000000000000
--- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <!--scale android:fromXScale="2.0" android:toXScale="1.0"
- android:fromYScale="2.0" android:toYScale="1.0"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:pivotX="50%p" android:pivotY="50%p"
- android:duration="250" /-->
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
-</set>
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
deleted file mode 100644
index 7e257d938e71..000000000000
--- a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, 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.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
-</set>
diff --git a/packages/SystemUI/res/anim/recents_return_to_launcher_enter.xml b/packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml
index efa901915886..4a7fff67eac5 100644
--- a/packages/SystemUI/res/anim/recents_return_to_launcher_enter.xml
+++ b/packages/SystemUI/res/interpolator/recents_from_launcher_exit_interpolator.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
-** Copyright 2012, The Android Open Source Project
+** Copyright 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.
@@ -16,11 +16,8 @@
** limitations under the License.
*/
-->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="normal">
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
-</set>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0"
+ android:controlY1="0"
+ android:controlX2="0.8"
+ android:controlY2="1" />
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml
index fa28cf42eee9..c61dfd87d842 100644
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
+++ b/packages/SystemUI/res/interpolator/recents_to_launcher_enter_interpolator.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
-** Copyright 2012, The Android Open Source Project
+** Copyright 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.
@@ -16,13 +16,8 @@
** limitations under the License.
*/
-->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:zAdjustment="top">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true" android:fillAfter="true"
- android:interpolator="@android:interpolator/decelerate_cubic"
- android:duration="250"/>
-</set>
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="0"
+ android:controlX2="1"
+ android:controlY2="1" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_separator.xml
index 802acfed73e8..778ef8ffd3dd 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_separator.xml
@@ -15,8 +15,11 @@
~ limitations under the License
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-</LinearLayout>
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="0dp"
+ android:layout_marginBottom="20dp"
+ android:background="?android:attr/dividerHorizontal" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
index fa07eb1b105c..7ca3b954fcf9 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
@@ -16,7 +16,7 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-</LinearLayout>
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index 77b12641c8c6..f73ee1532ba3 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -14,25 +14,35 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/keyboard_shortcuts_wrapper"
- android:layout_width="488dp"
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="488dp"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:focusable="true">
- <ScrollView
+ android:orientation="vertical">
+ <ScrollView
android:id="@+id/keyboard_shortcuts_scroll_view"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1">
- <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
android:id="@+id/keyboard_shortcuts_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
- </ScrollView>
- <View
+ </ScrollView>
+ <!-- Required for stretching to full available height when the items in the scroll view
+ occupy less space then the full height -->
+ <View
android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"/>
-</LinearLayout>
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+ </LinearLayout>
+ <View
+ android:layout_gravity="bottom"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/dividerHorizontal"/>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9bb6dc6abb75..a9b8df2934c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -158,5 +158,4 @@
<!-- Keyboard shortcuts colors -->
<color name="ksh_system_group_color">#ff00bcd4</color>
<color name="ksh_application_group_color">#fff44336</color>
- <color name="ksh_dialog_background_color">#ffffffff</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e8df01b19415..a6ba8b59303d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast,work
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location
</string>
<!-- The tiles to display in QuickSettings -->
@@ -138,12 +138,6 @@
<!-- The duration in seconds to wait before the dismiss buttons are shown. -->
<integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
- <!-- The duration of the window transition when coming to Recents from an app.
- In order to defer the in-app animations until after the transition is complete,
- we also need to use this value as the starting delay when animating the first
- task decorations in. -->
- <integer name="recents_enter_from_app_transition_duration">325</integer>
-
<!-- The duration for animating the task decorations in after transitioning from an app. -->
<integer name="recents_task_enter_from_app_duration">200</integer>
@@ -153,12 +147,6 @@
<!-- The duration for animating the task decorations out before transitioning to an app. -->
<integer name="recents_task_exit_to_app_duration">125</integer>
- <!-- The duration of the window transition when coming to Recents from the Launcher.
- In order to defer the in-app animations until after the transition is complete,
- we also need to use this value as the starting delay when animating the task views
- in from the bottom of the screen. -->
- <integer name="recents_enter_from_home_transition_duration">100</integer>
-
<!-- The min animation duration for animating the nav bar scrim in. -->
<integer name="recents_nav_bar_scrim_enter_duration">400</integer>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 76752e633f4a..6ff9be14b3ce 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1184,6 +1184,11 @@
<!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
<string name="overview_initial_state_paging_desc">Determines whether Overview will initially be in a stacked or paged state</string>
+ <!-- Toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=60]-->
+ <string name="overview_nav_bar_gesture">Enable split-screen swipe-up accelerator</string>
+ <!-- Description for the toggle to enable the gesture to enter split-screen by swiping up from the Overview button. [CHAR LIMIT=NONE]-->
+ <string name="overview_nav_bar_gesture_desc">Enable gesture to enter split-screen by swiping up from the Overview button</string>
+
<!-- Category in the System UI Tuner settings, where new/experimental
settings are -->
<string name="experimental">Experimental</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b078a68ff35a..60a9fc233aa3 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,10 +16,6 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="RecentsStyle" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
- <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
- </style>
-
<style name="RecentsTheme" parent="@android:style/Theme.Material">
<!-- NoTitle -->
<item name="android:windowNoTitle">true</item>
@@ -27,38 +23,23 @@
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
- <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
+ <item name="android:windowAnimationStyle">@null</item>
<item name="android:ambientShadowAlpha">0.35</item>
</style>
- <!-- Alternate Recents theme -->
+ <!-- Recents theme -->
<style name="RecentsTheme.Wallpaper">
- <!-- Wallpaper -->
<item name="android:windowBackground">@color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
</style>
- <!-- Performance optimized alternate Recents theme (no wallpaper) -->
+ <!-- Performance optimized Recents theme (no wallpaper) -->
<style name="RecentsTheme.NoWallpaper">
<item name="android:windowBackground">@android:color/black</item>
</style>
- <!-- Animations for a non-full-screen window or activity. -->
- <style name="Animation.RecentsActivity" parent="@android:style/Animation.Activity">
- <item name="android:activityOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
- <item name="android:activityOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
- <item name="android:taskOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
- <item name="android:taskOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
- <item name="android:taskToFrontEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
- <item name="android:taskToFrontExitAnimation">@anim/recents_launch_from_launcher_exit</item>
- <item name="android:wallpaperOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
- <item name="android:wallpaperOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
- <item name="android:wallpaperIntraOpenEnterAnimation">@anim/wallpaper_recents_launch_from_launcher_enter</item>
- <item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item>
- </style>
-
<style name="TextAppearance.StatusBar.HeadsUp"
parent="@*android:style/TextAppearance.StatusBar">
</style>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index febe5188cf88..4de4cede0faa 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -122,6 +122,11 @@
android:title="@string/overview_fast_toggle_via_button"
android:summary="@string/overview_fast_toggle_via_button_desc" />
+ <com.android.systemui.tuner.TunerSwitch
+ android:key="overview_nav_bar_gesture"
+ android:title="@string/overview_nav_bar_gesture"
+ android:summary="@string/overview_nav_bar_gesture_desc" />
+
</PreferenceScreen>
<SwitchPreference
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index e770b5d89a0b..454d1ceb4b04 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -182,6 +182,7 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode,
mListening = true;
mContext.getContentResolver().registerContentObserver(
Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+ updateShowPercent();
if (mDemoMode) return;
mBatteryController.addStateChangedCallback(this);
}
@@ -193,6 +194,11 @@ public class BatteryMeterDrawable extends Drawable implements DemoMode,
mBatteryController.removeStateChangedCallback(this);
}
+ public void disableShowPercent() {
+ mShowPercent = false;
+ postInvalidate();
+ }
+
private void postInvalidate() {
mHandler.post(new Runnable() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index cd6dce01e48e..5e33a9f84cac 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -34,4 +34,10 @@ public class Interpolators {
public static final Interpolator LINEAR = new LinearInterpolator();
public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
+
+ /**
+ * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+ */
+ public static final Interpolator TOUCH_RESPONSE =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 6840e08f2cfe..29f8af21e3bb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -42,6 +42,7 @@ public class TileQueryHelper {
private static final String TAG = "TileQueryHelper";
private final ArrayList<TileInfo> mTiles = new ArrayList<>();
+ private final ArrayList<String> mSpecs = new ArrayList<>();
private final Context mContext;
private TileStateListener mListener;
@@ -76,7 +77,7 @@ public class TileQueryHelper {
mainHandler.post(new Runnable() {
@Override
public void run() {
- addTile(spec, state, mTiles);
+ addTile(spec, state);
mListener.onTilesChanged(mTiles);
}
});
@@ -95,20 +96,23 @@ public class TileQueryHelper {
mListener = listener;
}
- private static void addTile(String spec, QSTile.State state, List<TileInfo> tiles) {
+ private void addTile(String spec, QSTile.State state) {
+ if (mSpecs.contains(spec)) {
+ return;
+ }
TileInfo info = new TileInfo();
info.state = state;
info.spec = spec;
- tiles.add(info);
+ mTiles.add(info);
+ mSpecs.add(spec);
}
- private static void addTile(String spec, Drawable drawable, CharSequence label, Context context,
- List<TileInfo> tiles) {
+ private void addTile(String spec, Drawable drawable, CharSequence label, Context context) {
QSTile.State state = new QSTile.State();
state.label = label;
state.contentDescription = label;
state.icon = new DrawableIcon(drawable);
- addTile(spec, state, tiles);
+ addTile(spec, state);
}
public static class TileInfo {
@@ -133,7 +137,7 @@ public class TileQueryHelper {
icon.setTint(mContext.getColor(android.R.color.white));
}
CharSequence label = info.serviceInfo.loadLabel(pm);
- addTile(spec, icon, label != null ? label.toString() : "null", mContext, tiles);
+ addTile(spec, icon, label != null ? label.toString() : "null", mContext);
}
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index cd3e3b2a3bf0..72cdf180f999 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -153,6 +153,7 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
private void bindView() {
mDrawable.onBatteryLevelChanged(100, false, false);
mDrawable.onPowerSaveChanged(true);
+ mDrawable.disableShowPercent();
((ImageView) mCurrentView.findViewById(android.R.id.icon)).setImageDrawable(mDrawable);
Checkable checkbox = (Checkable) mCurrentView.findViewById(android.R.id.toggle);
checkbox.setChecked(mPowerSave);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index d01a288d6fcf..3f482c82011a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -45,7 +45,6 @@ import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEven
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
@@ -130,6 +129,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
*/
public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
mLaunchIntent = launchIntent;
+ mOpts = opts;
}
@Override
@@ -437,11 +437,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
protected void onPause() {
super.onPause();
- RecentsDebugFlags flags = Recents.getDebugFlags();
- if (flags.isFastToggleRecentsEnabled()) {
- // Stop the fast-toggle dozer
- mIterateTrigger.stopDozing();
- }
+ // Stop the fast-toggle dozer
+ mIterateTrigger.stopDozing();
}
@Override
@@ -648,6 +645,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
}
public final void onBusEvent(UserInteractionEvent event) {
+ // Stop the fast-toggle dozer
mIterateTrigger.stopDozing();
}
@@ -694,21 +692,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
}
}
- public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() &&
- RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) {
- mIterateTrigger.setDozeDuration(
- getResources().getInteger(R.integer.recents_auto_advance_duration));
- if (!mIterateTrigger.isDozing()) {
- mIterateTrigger.startDozing();
- } else {
- mIterateTrigger.poke();
- }
- }
- }
-
public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
EventBus.getDefault().send(new UpdateFreeformTaskViewVisibilityEvent(true));
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 0afa1f6a495f..177e8417f3fb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -52,10 +52,23 @@ public class RecentsActivityLaunchState {
* Returns the task to focus given the current launch state.
*/
public int getInitialFocusTaskIndex(int numTasks) {
+ RecentsDebugFlags debugFlags = Recents.getDebugFlags();
if (launchedFromAppWithThumbnail) {
+ if (debugFlags.isFastToggleRecentsEnabled()) {
+ // If fast toggling, focus the front most task so that the next tap will focus the
+ // N-1 task
+ return numTasks - 1;
+ }
+
// If coming from another app, focus the next task
return numTasks - 2;
} else {
+ if (debugFlags.isFastToggleRecentsEnabled()) {
+ // If fast toggling, defer focusing until the next tap (which will automatically
+ // focus the front most task)
+ return -1;
+ }
+
// If coming from home, focus the first task
return numTasks - 1;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 6b8968f02a11..fc14758af0f4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -39,8 +39,6 @@ public class RecentsDebugFlags implements TunerService.Tunable {
public static final boolean EnableAffiliatedTaskGroups = true;
// Overrides the Tuner flags and enables the fast toggle and timeout
public static final boolean EnableFastToggleTimeoutOverride = true;
- // Enables toggling the fast-toggle timeout immediately after entering Recents
- public static final boolean EnableFastToggleTimeoutOnEnter = true;
// Enables us to create mock recents tasks
public static final boolean EnableMockTasks = false;
@@ -90,9 +88,6 @@ public class RecentsDebugFlags implements TunerService.Tunable {
* @return whether the initial stack state is paging.
*/
public boolean isInitialStatePaging() {
- if (Static.EnableFastToggleTimeoutOnEnter) {
- return true;
- }
return mInitialStatePaging;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 1cceef4484fe..dd7b7c1b89e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -38,6 +38,7 @@ import android.util.MutableBoolean;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewConfiguration;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.Prefs;
@@ -48,6 +49,7 @@ import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
@@ -81,8 +83,10 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {
private final static String TAG = "RecentsImpl";
+
// The minimum amount of time between each recents button press that we will handle
private final static int MIN_TOGGLE_DELAY_MS = 350;
+
// The duration within which the user releasing the alt tab (from when they pressed alt tab)
// that the fast alt-tab animation will run. If the user's alt-tab takes longer than this
// duration, then we will toggle recents after this duration.
@@ -337,21 +341,31 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mTriggeredFromAltTab = false;
try {
+ ViewConfiguration viewConfig = ViewConfiguration.get(mContext);
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
MutableBoolean isTopTaskHome = new MutableBoolean(true);
+ long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
+
if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!launchState.launchedWithAltTab) {
- // Notify recents to move onto the next task
- EventBus.getDefault().post(new IterateRecentsEvent());
+ // If the user taps quickly
+ if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
+ elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+ // Launch the next focused task
+ EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
+ } else {
+ // Notify recents to move onto the next task
+ EventBus.getDefault().post(new IterateRecentsEvent());
+ }
} else {
// If the user has toggled it too quickly, then just eat up the event here (it's
// better than showing a janky screenshot).
// NOTE: Ideally, the screenshot mechanism would take the window transform into
// account
- if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) {
+ if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
return;
}
@@ -364,7 +378,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// better than showing a janky screenshot).
// NOTE: Ideally, the screenshot mechanism would take the window transform into
// account
- if ((SystemClock.elapsedRealtime() - mLastToggleTime) < MIN_TOGGLE_DELAY_MS) {
+ if (elapsedTime < MIN_TOGGLE_DELAY_MS) {
return;
}
@@ -551,11 +565,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
public void dockTopTask(int topTaskId, int dragMode,
int stackCreateMode, Rect initialBounds) {
SystemServicesProxy ssp = Recents.getSystemServices();
+
+ // Make sure we inform DividerView before we actually start the activity so we can change
+ // the resize mode already.
+ EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
showRecents(false /* triggeredFromAltTab */,
dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
true /* reloadTasks*/);
- EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java
new file mode 100644
index 000000000000..11604b51b4a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchNextTaskRequestEvent.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This event is sent to request that the next task is launched after a double-tap on the Recents
+ * button.
+ */
+public class LaunchNextTaskRequestEvent extends EventBus.Event {
+ // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java
new file mode 100644
index 000000000000..d5083a8b017f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/UndockingTaskEvent.java
@@ -0,0 +1,28 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fires when the user invoked the gesture to undock the task in the docked stack.
+ */
+public class UndockingTaskEvent extends EventBus.Event {
+
+ public UndockingTaskEvent() {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index ee3eb02c8a38..5eeda72637ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -67,9 +67,30 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks {
public final View content;
- public ViewHolder(View v) {
- super(v);
- content = v;
+ private Task mTask;
+
+ public ViewHolder(View content) {
+ super(content);
+ this.content = content;
+ }
+
+ /**
+ * Binds this view holder to the given task.
+ */
+ public void bindToTask(Task newTask) {
+ unbindFromTask();
+ mTask = newTask;
+ mTask.addCallback(this);
+ }
+
+ /**
+ * Unbinds this view holder from the
+ */
+ public void unbindFromTask() {
+ if (mTask != null) {
+ mTask.removeCallback(this);
+ mTask = null;
+ }
}
@Override
@@ -267,12 +288,13 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
}
case TASK_ROW_VIEW_TYPE: {
TaskRow taskRow = (TaskRow) row;
- taskRow.task.addCallback(holder);
TextView tv = (TextView) holder.content.findViewById(R.id.description);
tv.setText(taskRow.task.title);
ImageView iv = (ImageView) holder.content.findViewById(R.id.icon);
iv.setAlpha(0f);
holder.content.setOnClickListener(taskRow);
+
+ holder.bindToTask(taskRow.task);
loader.loadTaskData(taskRow.task, false /* fetchAndInvalidateThumbnails */);
break;
}
@@ -289,7 +311,7 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
if (viewType == TASK_ROW_VIEW_TYPE) {
TaskRow taskRow = (TaskRow) row;
loader.unloadTaskData(taskRow.task);
- taskRow.task.removeCallback(holder);
+ holder.unbindFromTask();
}
}
}
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 e8fa39830f8d..1cd0850ef7fa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -83,13 +83,11 @@ public class SystemBarScrimViews {
* going home).
*/
public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
- int taskViewExitToAppDuration = mContext.getResources().getInteger(
- R.integer.recents_task_exit_to_app_duration);
if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
mNavBarScrimView.animate()
.translationY(mNavBarScrimView.getMeasuredHeight())
.setStartDelay(0)
- .setDuration(taskViewExitToAppDuration)
+ .setDuration(TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
}
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 0eae183e58d6..7eaa1930f6a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -108,7 +108,7 @@ public class TaskStackAnimationHelper {
return;
}
- int offscreenY = stackLayout.mStackRect.bottom;
+ int offscreenYOffset = stackLayout.mStackRect.height();
int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
R.dimen.recents_task_view_affiliate_group_enter_offset);
@@ -145,7 +145,7 @@ public class TaskStackAnimationHelper {
} else if (launchState.launchedFromHome) {
// Move the task view off screen (below) so we can animate it in
RectF bounds = new RectF(mTmpTransform.rect);
- bounds.offsetTo(bounds.left, offscreenY);
+ bounds.offset(0, offscreenYOffset);
tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right,
(int) bounds.bottom);
}
@@ -247,7 +247,7 @@ public class TaskStackAnimationHelper {
return;
}
- int offscreenY = stackLayout.mStackRect.bottom;
+ int offscreenYOffset = stackLayout.mStackRect.height();
// Create the animations for each of the tasks
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -277,7 +277,7 @@ public class TaskStackAnimationHelper {
stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
null);
- mTmpTransform.rect.offsetTo(mTmpTransform.rect.left, offscreenY);
+ mTmpTransform.rect.offset(0, offscreenYOffset);
mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
}
}
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 46fdb2a9b860..bd37c3bfd761 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -383,6 +383,7 @@ public class TaskStackLayoutAlgorithm {
*/
void update(TaskStack stack, ArraySet<Task.TaskKey> ignoreTasksSet) {
SystemServicesProxy ssp = Recents.getSystemServices();
+ RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
// Clear the progress map
mTaskIndexMap.clear();
@@ -449,7 +450,6 @@ public class TaskStackLayoutAlgorithm {
if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
mInitialScrollP = mMinScrollP;
} else if (getDefaultFocusState() > 0f) {
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
if (launchState.launchedFromHome) {
mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, launchTaskIndex));
} else {
@@ -568,7 +568,7 @@ public class TaskStackLayoutAlgorithm {
boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
if (isFrontMostTaskInGroup) {
getStackTransform(taskProgress, mInitialScrollP, tmpTransform, null,
- false /* ignoreSingleTaskCase */);
+ false /* ignoreSingleTaskCase */, false /* forceUpdate */);
float screenY = tmpTransform.rect.top;
boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
if (hasVisibleThumbnail) {
@@ -601,6 +601,12 @@ public class TaskStackLayoutAlgorithm {
*/
public TaskViewTransform getStackTransform(Task task, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform) {
+ return getStackTransform(task, stackScroll, transformOut, frontTransform,
+ false /* forceUpdate */);
+ }
+
+ public TaskViewTransform getStackTransform(Task task, float stackScroll,
+ TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) {
if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
return transformOut;
@@ -610,8 +616,9 @@ public class TaskStackLayoutAlgorithm {
transformOut.reset();
return transformOut;
}
- return getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut,
- frontTransform, false /* ignoreSingleTaskCase */);
+ getStackTransform(mTaskIndexMap.get(task.key), stackScroll, transformOut,
+ frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
+ return transformOut;
}
}
@@ -635,9 +642,9 @@ public class TaskStackLayoutAlgorithm {
* internally to ensure that we can calculate the transform for any
* position in the stack.
*/
- public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
+ public void getStackTransform(float taskProgress, float stackScroll,
TaskViewTransform transformOut, TaskViewTransform frontTransform,
- boolean ignoreSingleTaskCase) {
+ boolean ignoreSingleTaskCase, boolean forceUpdate) {
SystemServicesProxy ssp = Recents.getSystemServices();
// Compute the focused and unfocused offset
@@ -658,9 +665,9 @@ public class TaskStackLayoutAlgorithm {
}
// Skip if the task is not visible
- if (!unfocusedVisible && !focusedVisible) {
+ if (!forceUpdate && !unfocusedVisible && !focusedVisible) {
transformOut.reset();
- return transformOut;
+ return;
}
int x = (mStackRect.width() - mTaskRect.width()) / 2;
@@ -700,7 +707,6 @@ public class TaskStackLayoutAlgorithm {
transformOut.visible = (transformOut.rect.top < mStackRect.bottom) &&
(frontTransform == null || transformOut.rect.top != frontTransform.rect.top);
transformOut.p = relP;
- return transformOut;
}
/**
@@ -797,8 +803,10 @@ public class TaskStackLayoutAlgorithm {
mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin);
float max = mUnfocusedRange.relativeMax +
mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax);
- getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */);
- getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */);
+ getStackTransform(min, 0f, mBackOfStackTransform, null, true /* ignoreSingleTaskCase */,
+ true /* forceUpdate */);
+ getStackTransform(max, 0f, mFrontOfStackTransform, null, true /* ignoreSingleTaskCase */,
+ true /* forceUpdate */);
mBackOfStackTransform.visible = true;
mFrontOfStackTransform.visible = true;
}
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 1c97b5a22ec7..bb74de493f58 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -58,6 +58,7 @@ import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationC
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
@@ -654,7 +655,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
transform.fillIn(tv);
} else {
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
- transform, null);
+ transform, null, true /* forceUpdate */);
}
transform.visible = true;
}
@@ -1544,6 +1545,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mUIDozeTrigger.stopDozing();
}
+ public final void onBusEvent(LaunchNextTaskRequestEvent event) {
+ int launchTaskIndex = mStack.indexOfStackTask(mStack.getLaunchTarget());
+ if (launchTaskIndex != -1) {
+ launchTaskIndex = Math.max(0, launchTaskIndex - 1);
+ } else {
+ launchTaskIndex = mStack.getTaskCount() - 1;
+ }
+ if (launchTaskIndex != -1) {
+ // Stop all animations
+ mUIDozeTrigger.stopDozing();
+ cancelAllTaskViewAnimations();
+
+ Task launchTask = mStack.getStackTasks().get(launchTaskIndex);
+ EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
+ launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
+ }
+ }
+
public final void onBusEvent(LaunchTaskStartedEvent event) {
mAnimationHelper.startLaunchTaskAnimation(event.taskView, event.screenPinningRequested,
event.getAnimationTrigger());
@@ -1762,21 +1781,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
}
}
- public final void onBusEvent(EnterRecentsTaskStackAnimationCompletedEvent event) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
- if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled() &&
- RecentsDebugFlags.Static.EnableFastToggleTimeoutOnEnter) {
- if (mFocusedTask != null) {
- int timerIndicatorDuration = getResources().getInteger(
- R.integer.recents_auto_advance_duration);
- int focusedTaskIndex = mStack.indexOfStackTask(mFocusedTask);
- setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
- false /* requestViewFocus */, timerIndicatorDuration);
- }
- }
- }
-
public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) {
List<TaskView> taskViews = getTaskViews();
int taskViewCount = taskViews.size();
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 b8b506800488..d6680fdf23e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -29,6 +29,7 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
+import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -497,6 +498,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
// onBeginDrag().
mSv.removeIgnoreTask(tv.getTask());
mSv.updateLayoutAlgorithm(false /* boundScroll */);
+ mSv.relayoutTaskViews(AnimationProps.IMMEDIATE);
mSwipeHelperAnimations.remove(v);
}
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 703005f00a49..439d96f7d27b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -242,7 +242,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform,
- AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) {
+ AnimationProps toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) {
RecentsConfiguration config = Recents.getConfiguration();
cancelTransformAnimation();
@@ -261,14 +261,16 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
updateCallback.onAnimationUpdate(null);
}
} else {
+ // Both the progress and the update are a function of the bounds movement of the task
if (Float.compare(getTaskProgress(), toTransform.p) != 0) {
- mTmpAnimators.add(ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
- toTransform.p));
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(),
+ toTransform.p);
+ mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, anim));
}
if (updateCallback != null) {
ValueAnimator updateCallbackAnim = ValueAnimator.ofInt(0, 1);
updateCallbackAnim.addUpdateListener(updateCallback);
- mTmpAnimators.add(updateCallbackAnim);
+ mTmpAnimators.add(toAnimation.apply(AnimationProps.BOUNDS, updateCallbackAnim));
}
// Create the animator
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index 5ef56f3312dd..12e271397fba 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -26,10 +26,9 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Property;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageButton;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
/**
@@ -71,7 +70,6 @@ public class DividerHandleView extends ImageButton {
private final int mWidth;
private final int mHeight;
private final int mCircleDiameter;
- private final Interpolator mFastOutSlowInInterpolator;
private int mCurrentWidth;
private int mCurrentHeight;
private AnimatorSet mAnimator;
@@ -85,8 +83,6 @@ public class DividerHandleView extends ImageButton {
mCurrentWidth = mWidth;
mCurrentHeight = mHeight;
mCircleDiameter = (mWidth + mHeight) / 3;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_slow_in);
}
public void setTouching(boolean touching, boolean animate) {
@@ -120,8 +116,8 @@ public class DividerHandleView extends ImageButton {
? DividerView.TOUCH_ANIMATION_DURATION
: DividerView.TOUCH_RELEASE_ANIMATION_DURATION);
mAnimator.setInterpolator(touching
- ? DividerView.TOUCH_RESPONSE_INTERPOLATOR
- : mFastOutSlowInInterpolator);
+ ? Interpolators.TOUCH_RESPONSE
+ : Interpolators.FAST_OUT_SLOW_IN);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 1e11fa81f3bc..83c22b110433 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -48,10 +48,12 @@ import android.widget.FrameLayout;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.internal.policy.DockedDividerUtils;
+import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
@@ -67,8 +69,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
static final long TOUCH_ANIMATION_DURATION = 150;
static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
- static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
private static final String TAG = "DividerView";
@@ -116,7 +116,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
- private Interpolator mFastOutSlowInInterpolator;
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -158,8 +157,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mTouchElevation = getResources().getDimensionPixelSize(
R.dimen.docked_stack_divider_lift_elevation);
mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_slow_in);
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
updateDisplayInfo();
@@ -192,7 +189,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
insets.getStableInsetRight(), insets.getStableInsetBottom());
if (mSnapAlgorithm != null) {
mSnapAlgorithm = null;
- getSnapAlgorithm();
+ initializeSnapAlgorithm();
}
}
return super.onApplyWindowInsets(insets);
@@ -211,17 +208,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mHandle.setTouching(true, animate);
}
mDockSide = mWindowManagerProxy.getDockSide();
- getSnapAlgorithm();
- if (mDockSide != WindowManager.DOCKED_INVALID) {
- mWindowManagerProxy.setResizing(true);
- mWindowManager.setSlippery(false);
- if (touching) {
- liftBackground();
- }
- return true;
- } else {
- return false;
+ initializeSnapAlgorithm();
+ mWindowManagerProxy.setResizing(true);
+ mWindowManager.setSlippery(false);
+ if (touching) {
+ liftBackground();
}
+ return mDockSide != WindowManager.DOCKED_INVALID;
}
public void stopDragging(int position, float velocity, boolean avoidDismissStart) {
@@ -233,17 +226,36 @@ public class DividerView extends FrameLayout implements OnTouchListener,
public void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator) {
+ stopDragging(position, target, duration, 0 /* startDelay*/, interpolator);
+ }
+
+ public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
+ Interpolator interpolator) {
mHandle.setTouching(false, true /* animate */);
- flingTo(position, target, duration, interpolator);
+ flingTo(position, target, duration, startDelay, interpolator);
mWindowManager.setSlippery(true);
releaseBackground();
}
- public DividerSnapAlgorithm getSnapAlgorithm() {
+ private void stopDragging() {
+ mHandle.setTouching(false, true /* animate */);
+ mWindowManager.setSlippery(true);
+ releaseBackground();
+ }
+
+ private void updateDockSide() {
+ mDockSide = mWindowManagerProxy.getDockSide();
+ }
+
+ private void initializeSnapAlgorithm() {
if (mSnapAlgorithm == null) {
mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
}
+ }
+
+ public DividerSnapAlgorithm getSnapAlgorithm() {
+ initializeSnapAlgorithm();
return mSnapAlgorithm;
}
@@ -267,6 +279,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mStartX = (int) event.getX();
mStartY = (int) event.getY();
boolean result = startDragging(true /* animate */, true /* touching */);
+ if (!result) {
+
+ // Weren't able to start dragging successfully, so cancel it again.
+ stopDragging();
+ }
mStartPosition = getCurrentPosition();
mMoving = false;
return result;
@@ -320,10 +337,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
anim.start();
}
- private void flingTo(int position, SnapTarget target, long duration,
+ private void flingTo(int position, SnapTarget target, long duration, long startDelay,
Interpolator interpolator) {
ValueAnimator anim = getFlingAnimator(position, target);
anim.setDuration(duration);
+ anim.setStartDelay(startDelay);
anim.setInterpolator(interpolator);
anim.start();
}
@@ -377,7 +395,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackground.animate().scaleX(1.4f);
}
mBackground.animate()
- .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setInterpolator(Interpolators.TOUCH_RESPONSE)
.setDuration(TOUCH_ANIMATION_DURATION)
.translationZ(mTouchElevation)
.start();
@@ -385,7 +403,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
// Lift handle as well so it doesn't get behind the background, even though it doesn't
// cast shadow.
mHandle.animate()
- .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setInterpolator(Interpolators.TOUCH_RESPONSE)
.setDuration(TOUCH_ANIMATION_DURATION)
.translationZ(mTouchElevation)
.start();
@@ -393,14 +411,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private void releaseBackground() {
mBackground.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
.translationZ(0)
.scaleX(1f)
.scaleY(1f)
.start();
mHandle.animate()
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
.translationZ(0)
.start();
@@ -421,6 +439,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
mSnapAlgorithm = null;
+ initializeSnapAlgorithm();
}
private int calculatePosition(int touchX, int touchY) {
@@ -725,13 +744,29 @@ public class DividerView extends FrameLayout implements OnTouchListener,
public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
if (mAnimateAfterRecentsDrawn) {
mAnimateAfterRecentsDrawn = false;
+ updateDockSide();
stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- TOUCH_RESPONSE_INTERPOLATOR);
+ Interpolators.TOUCH_RESPONSE);
}
if (mGrowAfterRecentsDrawn) {
mGrowAfterRecentsDrawn = false;
+ updateDockSide();
stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- TOUCH_RESPONSE_INTERPOLATOR);
+ Interpolators.TOUCH_RESPONSE);
+ }
+ }
+
+ public final void onBusEvent(UndockingTaskEvent undockingTaskEvent) {
+ int dockSide = mWindowManagerProxy.getDockSide();
+ if (dockSide != WindowManager.DOCKED_INVALID) {
+ startDragging(false /* animate */, false /* touching */);
+ SnapTarget target = dockSideTopLeft(dockSide)
+ ? mSnapAlgorithm.getDismissEndTarget()
+ : mSnapAlgorithm.getDismissStartTarget();
+
+ // Don't start immediately - give a little bit time to settle the drag resize change.
+ stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */,
+ Interpolators.TOUCH_RESPONSE);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 24ab5063d94e..15bcaf834f72 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -97,7 +97,7 @@ public class WindowManagerProxy {
@Override
public void run() {
try {
- ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, false,
+ ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, null, true, true,
false);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 963920c3b91e..0b7bfa8871ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -23,17 +23,15 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Handler;
import android.os.Looper;
-import android.util.DisplayMetrics;
+import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.KeyboardShortcutGroup;
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.widget.LinearLayout;
-import android.widget.ScrollView;
import android.widget.TextView;
import com.android.systemui.R;
@@ -65,7 +63,7 @@ public class KeyboardShortcuts {
private Dialog mKeyboardShortcutsDialog;
public KeyboardShortcuts(Context context) {
- this.mContext = context;
+ this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
}
public void toggleKeyboardShortcuts() {
@@ -108,40 +106,28 @@ public class KeyboardShortcuts {
mHandler.post(new Runnable() {
@Override
public void run() {
- // TODO: break all this code out into a handleShowKeyboard...
- // Might add more things posted; should consider adding a custom handler so
- // you can send the keyboardShortcutsGroups as part of the message.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
- LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- LAYOUT_INFLATER_SERVICE);
- final View keyboardShortcutsView = inflater.inflate(
- R.layout.keyboard_shortcuts_view, null);
- DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
- ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_scroll_view);
- // TODO: find a better way to set the height.
- scrollView.setLayoutParams(new LinearLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT,
- (int) (dm.heightPixels * dm.density)));
-
- populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
- R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
- dialogBuilder.setView(keyboardShortcutsView);
- dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
- mKeyboardShortcutsDialog = dialogBuilder.create();
- mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
-
- // Setup window.
- Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
- keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
- keyboardShortcutsWindow.setBackgroundDrawable(
- mContext.getDrawable(R.color.ksh_dialog_background_color));
- keyboardShortcutsWindow.setGravity(TOP);
- mKeyboardShortcutsDialog.show();
+ handleShowKeyboardShortcuts(keyboardShortcutGroups);
}
});
}
+ private void handleShowKeyboardShortcuts(List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ LAYOUT_INFLATER_SERVICE);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_view, null);
+ populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
+ dialogBuilder.setView(keyboardShortcutsView);
+ dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+ mKeyboardShortcutsDialog = dialogBuilder.create();
+ mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+ Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+ keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+ mKeyboardShortcutsDialog.show();
+ }
+
private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout,
List<KeyboardShortcutGroup> keyboardShortcutGroups) {
LayoutInflater inflater = LayoutInflater.from(mContext);
@@ -156,36 +142,37 @@ public class KeyboardShortcuts {
: mContext.getColor(R.color.ksh_application_group_color));
keyboardShortcutsLayout.addView(categoryTitle);
- LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate(
- R.layout.keyboard_shortcuts_wrapper, null);
+ LinearLayout shortcutContainer = (LinearLayout) inflater.inflate(
+ R.layout.keyboard_shortcuts_container, keyboardShortcutsLayout, false);
final int itemsSize = group.getItems().size();
for (int j = 0; j < itemsSize; j++) {
KeyboardShortcutInfo info = group.getItems().get(j);
- View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null);
+ View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item,
+ shortcutContainer, false);
TextView textView = (TextView) shortcutView
.findViewById(R.id.keyboard_shortcuts_keyword);
textView.setText(info.getLabel());
+ LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+ .findViewById(R.id.keyboard_shortcuts_item_container);
List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
final int shortcutKeysSize = shortcutKeys.size();
for (int k = 0; k < shortcutKeysSize; k++) {
String shortcutKey = shortcutKeys.get(k);
TextView shortcutKeyView = (TextView) inflater.inflate(
- R.layout.keyboard_shortcuts_key_view, null);
+ R.layout.keyboard_shortcuts_key_view, shortcutItemsContainer, false);
shortcutKeyView.setText(shortcutKey);
- LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
- .findViewById(R.id.keyboard_shortcuts_item_container);
shortcutItemsContainer.addView(shortcutKeyView);
}
- shortcutWrapper.addView(shortcutView);
+ shortcutContainer.addView(shortcutView);
+ }
+ keyboardShortcutsLayout.addView(shortcutContainer);
+ if (i < keyboardShortcutGroupsSize - 1) {
+ View separator = inflater.inflate(
+ R.layout.keyboard_shortcuts_category_separator, keyboardShortcutsLayout,
+ false);
+ keyboardShortcutsLayout.addView(separator);
}
-
- // TODO: merge container and wrapper into one xml file - wrapper is always a child of
- // container.
- LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate(
- R.layout.keyboard_shortcuts_container, null);
- shortcutsContainer.addView(shortcutWrapper);
- keyboardShortcutsLayout.addView(shortcutsContainer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index a2586f1984f2..bb03454de0f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -304,8 +304,7 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL
public void onTuningChanged(String key, String newValue) {
switch (key) {
case KEY_DOCK_WINDOW_GESTURE:
- mDockWindowEnabled = (newValue == null) ||
- (Integer.parseInt(newValue) != 0);
+ mDockWindowEnabled = newValue != null && (Integer.parseInt(newValue) != 0);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 935930195ba1..d625fc2bc738 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -27,7 +27,6 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Space;
-
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.KeyButtonView;
import com.android.systemui.tuner.TunerService;
@@ -58,8 +57,9 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
public static final String KEY_IMAGE_DELIM = ":";
public static final String KEY_CODE_END = ")";
- protected final LayoutInflater mLayoutInflater;
- protected final LayoutInflater mLandscapeInflater;
+ protected LayoutInflater mLayoutInflater;
+ protected LayoutInflater mLandscapeInflater;
+ private int mDensity;
protected FrameLayout mRot0;
protected FrameLayout mRot90;
@@ -69,11 +69,27 @@ public class NavigationBarInflaterView extends FrameLayout implements TunerServi
public NavigationBarInflaterView(Context context, AttributeSet attrs) {
super(context, attrs);
- mLayoutInflater = LayoutInflater.from(context);
+ mDensity = context.getResources().getConfiguration().densityDpi;
+ createInflaters();
+ }
+
+ private void createInflaters() {
+ mLayoutInflater = LayoutInflater.from(mContext);
Configuration landscape = new Configuration();
- landscape.setTo(context.getResources().getConfiguration());
+ landscape.setTo(mContext.getResources().getConfiguration());
landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;
- mLandscapeInflater = LayoutInflater.from(context.createConfigurationContext(landscape));
+ mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape));
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mDensity != newConfig.densityDpi) {
+ mDensity = newConfig.densityDpi;
+ createInflaters();
+ clearViews();
+ inflateLayout(mCurrentLayout);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 575eda7cf873..f822bd535851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,8 +39,6 @@ import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -212,10 +210,6 @@ public class NotificationPanelView extends PanelView implements
}
};
- /** Interpolator to be used for animations that respond directly to a touch */
- private final Interpolator mTouchResponseInterpolator =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
-
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(!DEBUG);
@@ -1447,7 +1441,7 @@ public class NotificationPanelView extends PanelView implements
mScrollView.setBlockFlinging(true);
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
if (isClick) {
- animator.setInterpolator(mTouchResponseInterpolator);
+ animator.setInterpolator(Interpolators.TOUCH_RESPONSE);
animator.setDuration(368);
} else {
mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 07dc4fd5fb7c..4dee51df131c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -118,7 +118,10 @@ import com.android.systemui.doze.DozeLog;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.UndockingTaskEvent;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.BaseStatusBar;
@@ -1112,26 +1115,25 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public boolean onLongClick(View v) {
if (mRecents != null) {
- Point realSize = new Point();
- mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
- .getRealSize(realSize);
- Rect initialBounds;
-
- // Hack level over 9000: Make it one pixel smaller so activity manager doesn't
- // dismiss it immediately again. Remove once b/26777526 is fixed.
- if (mContext.getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_LANDSCAPE) {
- initialBounds = new Rect(0, 0, realSize.x - 1, realSize.y);
+ int dockSide = WindowManagerProxy.getInstance().getDockSide();
+ if (dockSide == WindowManager.DOCKED_INVALID) {
+ Point realSize = new Point();
+ mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+ .getRealSize(realSize);
+ Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y);
+ boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
+ ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
+ initialBounds);
+ if (docked) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
+ return true;
+ }
} else {
- initialBounds = new Rect(0, 0, realSize.x, realSize.y - 1);
- }
- boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
- ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
- initialBounds);
- if (docked) {
- MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS);
+ EventBus.getDefault().send(new UndockingTaskEvent());
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
return true;
}
+
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 9996b7567893..45aae2dd61f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -30,12 +30,12 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
@@ -226,12 +226,25 @@ public class StatusBarIconController extends StatusBarIconList implements Tunabl
public void setExternalIcon(String slot) {
int viewIndex = getViewIndex(getSlotIndex(slot));
+ int height = mContext.getResources().getDimensionPixelSize(
+ R.dimen.status_bar_icon_drawing_size);
ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setAdjustViewBounds(true);
+ setHeightAndCenter(imageView, height);
imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setAdjustViewBounds(true);
+ setHeightAndCenter(imageView, height);
+ }
+
+ private void setHeightAndCenter(ImageView imageView, int height) {
+ ViewGroup.LayoutParams params = imageView.getLayoutParams();
+ params.height = height;
+ if (params instanceof LinearLayout.LayoutParams) {
+ ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL;
+ }
+ imageView.setLayoutParams(params);
}
public void setIcon(String slot, StatusBarIcon icon) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index b0369368b4b2..500d60359145 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -20,7 +20,6 @@ public interface HotspotController {
void addCallback(Callback callback);
void removeCallback(Callback callback);
boolean isHotspotEnabled();
- boolean isHotspotSupported();
void setHotspotEnabled(boolean enabled);
boolean isTetheringAllowed();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 61d26c72a898..07b74094ffb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -27,8 +27,6 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
-import com.android.settingslib.TetherUtil;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -98,11 +96,6 @@ public class HotspotControllerImpl implements HotspotController {
}
@Override
- public boolean isHotspotSupported() {
- return TetherUtil.isTetheringSupported(mContext);
- }
-
- @Override
public boolean isTetheringAllowed() {
return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING,
UserHandle.of(mCurrentUser));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index bc8c82572c9d..784f610e40a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -80,10 +80,6 @@ public class TvStatusBar extends BaseStatusBar {
boolean showImeSwitcher) {
}
- @Override
- public void toggleRecentApps() {
- }
-
@Override // CommandQueue
public void setWindowState(int window, int state) {
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0e67a24748b8..e1dd87f55ed4 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -348,5 +348,9 @@ message MetricsEvent {
// OS: 6.1
// GMS: 7.8.99
USER_CREDENTIALS = 285;
+
+ // Logged when the user undocks a previously docked window by long pressing recents while in
+ // docked mode.
+ ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3fd8b40dbc14..430092071d90 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2670,18 +2670,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if ro.tether.denied = true we default to no tethering
// gservices could set the secure setting to 1 though to enable it on a build where it
// had previously been turned off.
+ @Override
public boolean isTetheringSupported() {
enforceTetherAccessPermission();
int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.TETHER_SUPPORTED, defaultVal) != 0)
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
- return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 ||
+ return tetherEnabledInSettings && mUserManager.isAdminUser() &&
+ ((mTethering.getTetherableUsbRegexs().length != 0 ||
mTethering.getTetherableWifiRegexs().length != 0 ||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
mTethering.getUpstreamIfaceTypes().length != 0);
}
+ @Override
public void startTethering(int type, ResultReceiver receiver,
boolean showProvisioningUi) {
ConnectivityManager.enforceTetherChangePermission(mContext);
@@ -2692,6 +2695,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mTethering.startTethering(type, receiver, showProvisioningUi);
}
+ @Override
public void stopTethering(int type) {
ConnectivityManager.enforceTetherChangePermission(mContext);
mTethering.stopTethering(type);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 9bd79c9cf6c9..423ef84dd625 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1649,6 +1649,7 @@ public class DeviceIdleController extends SystemService
// Whoops, there is an upcoming alarm. We don't actually want to go idle.
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm", Process.myUid());
+ becomeInactiveIfAppropriateLocked();
}
return;
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 3ce44526d17b..5120e1b08f13 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2800,14 +2800,13 @@ class MountService extends IMountService.Stub
}
@Override
- public void prepareUserStorage(
- String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
+ public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
waitForReady();
try {
mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
- userId, serialNumber, ephemeral ? 1 : 0);
+ userId, serialNumber, flags);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 4f0d4d951e1c..bef6f0aabf5d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -62,7 +62,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_OOM_ADJ = DEBUG_ALL || false;
- static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
+ static final boolean DEBUG_PAUSE = DEBUG_ALL || true;
static final boolean DEBUG_POWER = DEBUG_ALL || false;
static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
@@ -77,7 +77,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
static final boolean DEBUG_STACK = DEBUG_ALL || false;
- static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || false;
+ static final boolean DEBUG_STATES = DEBUG_ALL_ACTIVITIES || true;
static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
static final boolean DEBUG_TASKS = DEBUG_ALL || false;
static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
@@ -85,7 +85,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_UID_OBSERVERS = DEBUG_ALL || false;
static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
- static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
+ static final boolean DEBUG_VISIBILITY = DEBUG_ALL || true;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG_ALL_ACTIVITIES || false;
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 072249f5928b..c021f4cfccaa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -252,10 +252,12 @@ import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -600,6 +602,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final AppErrors mAppErrors;
+ boolean mDoingSetFocusedActivity;
+
public boolean canShowErrorDialogs() {
return mShowDialogs && !mSleeping && !mShuttingDown;
}
@@ -2730,6 +2734,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
+
+ final boolean wasDoingSetFocusedActivity = mDoingSetFocusedActivity;
+ if (wasDoingSetFocusedActivity) Slog.w(TAG,
+ "setFocusedActivityLocked: called recursively, r=" + r + ", reason=" + reason);
+ mDoingSetFocusedActivity = true;
+
final ActivityRecord last = mFocusedActivity;
mFocusedActivity = r;
if (r.task.isApplicationTask()) {
@@ -2781,6 +2791,12 @@ public final class ActivityManagerService extends ActivityManagerNative
mLastFocusedUserId = mFocusedActivity.userId;
}
+ // Log a warning if the focused app is changed during the process. This could
+ // indicate a problem of the focus setting logic!
+ if (mFocusedActivity != r) Slog.w(TAG,
+ "setFocusedActivityLocked: r=" + r + " but focused to " + mFocusedActivity);
+ mDoingSetFocusedActivity = wasDoingSetFocusedActivity;
+
EventLogTags.writeAmFocusedActivity(
mFocusedActivity == null ? -1 : mFocusedActivity.userId,
mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
@@ -5337,7 +5353,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// We don't kill persistent processes.
continue;
}
- if (targetSdkVersion > 0 && app.info.targetSdkVersion < targetSdkVersion) {
+ if (targetSdkVersion > 0
+ && app.info.targetSdkVersion >= targetSdkVersion) {
continue;
}
if (app.removed) {
@@ -8753,6 +8770,13 @@ public final class ActivityManagerService extends ActivityManagerNative
continue;
}
+ if (!tr.mUserSetupComplete) {
+ // Don't include task launched while user is not done setting-up.
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, user setup not complete: " + tr);
+ continue;
+ }
+
ActivityManager.RecentTaskInfo rti = createRecentTaskInfoFromTaskRecord(tr);
if (!detailed) {
rti.baseIntent.replaceExtras((Bundle)null);
@@ -12408,9 +12432,8 @@ public final class ActivityManagerService extends ActivityManagerNative
mLocalDeviceIdleController
= LocalServices.getService(DeviceIdleController.LocalService.class);
- // Make sure we have the current profile info, since it is needed for
- // security checks.
- mUserController.updateCurrentProfileIdsLocked();
+ // Make sure we have the current profile info, since it is needed for security checks.
+ mUserController.onSystemReady();
mRecentTasks.onSystemReady();
// Check to see if there are any update receivers to run.
@@ -17631,6 +17654,22 @@ public final class ActivityManagerService extends ActivityManagerNative
final long origId = Binder.clearCallingIdentity();
final ActivityStack stack = mStackSupervisor.getStack(fromStackId);
if (stack != null) {
+ if (fromStackId == DOCKED_STACK_ID) {
+
+ // We are moving all tasks from the docked stack to the fullscreen stack, which
+ // is dismissing the docked stack, so resize all other stacks to fullscreen here
+ // already so we don't end up with resize trashing.
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i)) {
+ ActivityStack otherStack = mStackSupervisor.getStack(i);
+ if (otherStack != null) {
+ mStackSupervisor.resizeStackLocked(i,
+ null, null, null, PRESERVE_WINDOWS,
+ true /* allowResizeInDockedMode */);
+ }
+ }
+ }
+ }
final ArrayList<TaskRecord> tasks = stack.getAllTasks();
final int size = tasks.size();
if (onTop) {
@@ -17769,7 +17808,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (values.getLocales().size() == 1) {
// This is an optimization to avoid the JNI call when the result of
// getFirstMatch() does not depend on the supported locales.
- locale = values.getLocales().getPrimary();
+ locale = values.getLocales().get(0);
} else {
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales =
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 5a0c1c1bcd72..c352fc819884 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2168,7 +2168,9 @@ final class ActivityStack {
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
// This activity is now becoming visible.
- mWindowManager.setAppVisibility(next.appToken, true);
+ if (!next.visible) {
+ mWindowManager.setAppVisibility(next.appToken, true);
+ }
// schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked();
@@ -4304,6 +4306,12 @@ final class ActivityStack {
oldTaskOverride = record.task.extractOverrideConfig(record.configuration);
}
+ // Conversely, do the same when going the other direction.
+ if (Configuration.EMPTY.equals(taskConfig)
+ && !Configuration.EMPTY.equals(oldTaskOverride)) {
+ taskConfig = record.task.extractOverrideConfig(record.configuration);
+ }
+
// Determine what has changed. May be nothing, if this is a config
// that has come back from the app after going idle. In that case
// we just want to leave the official config object now in the
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 95bc95a8767a..0b2ff655597d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -583,7 +583,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
}
final ActivityRecord r = topRunningActivityLocked();
- if (mService.mFocusedActivity != r) {
+ if (!mService.mDoingSetFocusedActivity && mService.mFocusedActivity != r) {
// The focus activity should always be the top activity in the focused stack.
// There will be chaos and anarchy if it isn't...
mService.setFocusedActivityLocked(r, reason + " setFocusStack");
@@ -1889,12 +1889,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
Rect tempTaskInsetBounds) {
- if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) {
- // The bounds passed in corresponds to the fullscreen bounds which we normally
- // represent with null. Go ahead and set it to null so that all tasks configuration
- // can have the right fullscreen state.
- bounds = null;
- }
bounds = TaskRecord.validateBounds(bounds);
mTmpBounds.clear();
@@ -1913,7 +1907,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
task.updateOverrideConfiguration(tempRect2);
} else {
task.updateOverrideConfiguration(
- tempTaskBounds != null ? tempTaskBounds : bounds);
+ tempTaskBounds != null ? tempTaskBounds : bounds,
+ tempTaskInsetBounds != null ? tempTaskInsetBounds : bounds);
}
}
@@ -2213,9 +2208,9 @@ public final class ActivityStackSupervisor implements DisplayListener {
// Temporarily disable resizeablility of task we are moving. We don't want it to be resized
// if a docked stack is created below which will lead to the stack we are moving from and
// its resizeable tasks being resized.
- task.mResizeMode = RESIZE_MODE_UNRESIZEABLE;
+ task.mTemporarilyUnresizable = true;
final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
- task.mResizeMode = resizeMode;
+ task.mTemporarilyUnresizable = false;
mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
stack.addTask(task, toTop, reason);
@@ -2606,9 +2601,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
stack.setVisibleBehindActivity(visible ? r : null);
if (!visible) {
- // Make the activity immediately above r opaque.
+ // If there is a translucent home activity, we need to force it stop being translucent,
+ // because we can't depend on the application to necessarily perform that operation.
+ // Check out b/14469711 for details.
final ActivityRecord next = stack.findNextTranslucentActivity(r);
- if (next != null) {
+ if (next != null && next.isHomeActivity()) {
mService.convertFromTranslucent(next.appToken);
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 97ef10b10ab2..28882def6b99 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -81,12 +81,6 @@ public final class BatteryStatsService extends IBatteryStats.Stub
Context mContext;
PowerManagerInternal mPowerManagerInternal;
- final int UPDATE_CPU = 0x01;
- final int UPDATE_WIFI = 0x02;
- final int UPDATE_RADIO = 0x04;
- final int UPDATE_BT = 0x08;
- final int UPDATE_ALL = UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT;
-
class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
public static final int MSG_SYNC_EXTERNAL_STATS = 1;
public static final int MSG_WRITE_TO_DISK = 2;
@@ -133,16 +127,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
@Override
- public void scheduleSync(String reason) {
- synchronized (this) {
- scheduleSyncLocked(reason, UPDATE_ALL);
- }
- }
-
- @Override
- public void scheduleWifiSync(String reason) {
+ public void scheduleSync(String reason, int updateFlags) {
synchronized (this) {
- scheduleSyncLocked(reason, UPDATE_WIFI);
+ scheduleSyncLocked(reason, updateFlags);
}
}
@@ -194,7 +181,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void shutdown() {
Slog.w("BatteryStats", "Writing battery stats before shutdown...");
- updateExternalStats("shutdown", UPDATE_ALL);
+ updateExternalStats("shutdown", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.shutdownLocked();
}
@@ -294,7 +281,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- updateExternalStats("get-stats", UPDATE_ALL);
+ updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.writeToParcel(out, 0);
}
@@ -309,7 +296,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
//Slog.i("foo", "SENDING BATTERY INFO:");
//mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
Parcel out = Parcel.obtain();
- updateExternalStats("get-stats", UPDATE_ALL);
+ updateExternalStats("get-stats", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.writeToParcel(out, 0);
}
@@ -672,7 +659,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
: "inactive";
- mHandler.scheduleWifiSync("wifi-data: " + type);
+ mHandler.scheduleSync("wifi-data: " + type,
+ BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI);
}
mStats.noteWifiRadioPowerState(powerState, tsNanos);
}
@@ -860,13 +848,25 @@ public final class BatteryStatsService extends IBatteryStats.Stub
@Override
public void noteBleScanStarted(WorkSource ws) {
enforceCallingPermission();
- Slog.d(TAG, "BLE scan started for " + ws);
+ synchronized (mStats) {
+ mStats.noteBluetoothScanStartedFromSourceLocked(ws);
+ }
}
@Override
public void noteBleScanStopped(WorkSource ws) {
enforceCallingPermission();
- Slog.d(TAG, "BLE scan stopped for " + ws);
+ synchronized (mStats) {
+ mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
+ }
+ }
+
+ @Override
+ public void noteResetBleScan() {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteResetBluetoothScanLocked();
+ }
}
public boolean isOnBattery() {
@@ -895,7 +895,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
// Sync external stats first as the battery has changed states. If we don't sync
// immediately here, we may not collect the relevant data later.
- updateExternalStats("battery-state", UPDATE_ALL);
+ updateExternalStats("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
}
@@ -1082,9 +1082,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
pw.println("Battery stats reset.");
noOutput = true;
}
- updateExternalStats("dump", UPDATE_ALL);
+ updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
} else if ("--write".equals(arg)) {
- updateExternalStats("dump", UPDATE_ALL);
+ updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
mStats.writeSyncLocked();
pw.println("Battery stats written.");
@@ -1148,7 +1148,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
}
// Fetch data from external sources and update the BatteryStatsImpl object with them.
- updateExternalStats("dump", UPDATE_ALL);
+ updateExternalStats("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -1358,8 +1358,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub
*
* @param reason The reason why this collection was requested. Useful for debugging.
* @param updateFlags Which external stats to update. Can be a combination of
- * {@link #UPDATE_CPU}, {@link #UPDATE_RADIO}, {@link #UPDATE_WIFI},
- * and {@link #UPDATE_BT}.
+ * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU},
+ * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO},
+ * {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI},
+ * and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}.
*/
void updateExternalStats(final String reason, final int updateFlags) {
synchronized (mExternalStatsLock) {
@@ -1374,17 +1376,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub
}
WifiActivityEnergyInfo wifiEnergyInfo = null;
- if ((updateFlags & UPDATE_WIFI) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
wifiEnergyInfo = pullWifiEnergyInfoLocked();
}
ModemActivityInfo modemActivityInfo = null;
- if ((updateFlags & UPDATE_RADIO) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
modemActivityInfo = pullModemActivityInfoLocked();
}
BluetoothActivityEnergyInfo bluetoothEnergyInfo = null;
- if ((updateFlags & UPDATE_BT) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
// We only pull bluetooth stats when we have to, as we are not distributing its
// use amongst apps and the sampling frequency does not matter.
bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
@@ -1398,20 +1400,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub
BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS, reason, 0);
}
- if ((updateFlags & UPDATE_CPU) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_CPU) != 0) {
mStats.updateCpuTimeLocked();
mStats.updateKernelWakelocksLocked();
}
- if ((updateFlags & UPDATE_RADIO) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
mStats.updateMobileRadioStateLocked(elapsedRealtime, modemActivityInfo);
}
- if ((updateFlags & UPDATE_WIFI) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
mStats.updateWifiStateLocked(wifiEnergyInfo);
}
- if ((updateFlags & UPDATE_BT) != 0) {
+ if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
}
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index a7d948c9a695..10f09775608b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,37 +16,7 @@
package com.android.server.am;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
@@ -55,6 +25,7 @@ import android.app.ActivityManager.TaskThumbnail;
import android.app.ActivityManager.TaskThumbnailInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -86,6 +57,37 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+
final class TaskRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
@@ -106,6 +108,7 @@ final class TaskRecord {
private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
private static final String ATTR_USERID = "user_id";
+ private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
private static final String ATTR_EFFECTIVE_UID = "effective_uid";
private static final String ATTR_TASKTYPE = "task_type";
private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
@@ -155,11 +158,15 @@ final class TaskRecord {
String stringName; // caching of toString() result.
int userId; // user for which this task was created
+ boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
+ // was changed.
int numFullscreen; // Number of fullscreen activities.
int mResizeMode; // The resize mode of this task and its activities.
// Based on the {@link ActivityInfo#resizeMode} of the root activity.
+ boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
+ // changes on a temporary basis.
int mLockTaskMode; // Which tasklock mode to launch this task in. One of
// ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
@@ -238,6 +245,9 @@ final class TaskRecord {
// Bounds of the Task. null for fullscreen tasks.
Rect mBounds = null;
+ private final Rect mTmpRect = new Rect();
+ private final Rect mTmpRect2 = new Rect();
+
// Last non-fullscreen bounds the task was launched in or resized to.
// The information is persisted and used to determine the appropriate stack to launch the
// task into on restore.
@@ -311,7 +321,8 @@ final class TaskRecord {
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean privileged, boolean _realActivitySuspended) {
+ int resizeMode, boolean privileged, boolean _realActivitySuspended,
+ boolean userSetupComplete) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
@@ -334,6 +345,7 @@ final class TaskRecord {
taskType = _taskType;
mTaskToReturnTo = HOME_ACTIVITY_TYPE;
userId = _userId;
+ mUserSetupComplete = userSetupComplete;
effectiveUid = _effectiveUid;
firstActiveTime = _firstActiveTime;
lastActiveTime = _lastActiveTime;
@@ -434,6 +446,7 @@ final class TaskRecord {
}
userId = UserHandle.getUserId(info.applicationInfo.uid);
+ mUserSetupComplete = mService.mUserController.isUserSetupCompleteLocked(userId);
if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
// If the activity itself has requested auto-remove, then just always do it.
autoRemoveRecents = true;
@@ -934,7 +947,7 @@ final class TaskRecord {
boolean isResizeable() {
return !isHomeTask() && (mService.mForceResizableActivities
- || ActivityInfo.isResizeableMode(mResizeMode));
+ || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable;
}
boolean inCropWindowsResizeMode() {
@@ -1064,6 +1077,7 @@ final class TaskRecord {
out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
out.attribute(null, ATTR_USERID, String.valueOf(userId));
+ out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
@@ -1133,6 +1147,7 @@ final class TaskRecord {
boolean askedCompatMode = false;
int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
int userId = 0;
+ boolean userSetupComplete = true;
int effectiveUid = -1;
String lastDescription = null;
long firstActiveTime = -1;
@@ -1179,6 +1194,8 @@ final class TaskRecord {
askedCompatMode = Boolean.valueOf(attrValue);
} else if (ATTR_USERID.equals(attrName)) {
userId = Integer.valueOf(attrValue);
+ } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) {
+ userSetupComplete = Boolean.valueOf(attrValue);
} else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
effectiveUid = Integer.valueOf(attrValue);
} else if (ATTR_TASKTYPE.equals(attrName)) {
@@ -1278,7 +1295,7 @@ final class TaskRecord {
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged,
- realActivitySuspended);
+ realActivitySuspended, userSetupComplete);
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -1291,9 +1308,22 @@ final class TaskRecord {
/**
* Update task's override configuration based on the bounds.
+ * @param bounds The bounds of the task.
* @return Update configuration or null if there is no change.
*/
Configuration updateOverrideConfiguration(Rect bounds) {
+ return updateOverrideConfiguration(bounds, null /* insetBounds */);
+ }
+
+ /**
+ * Update task's override configuration based on the bounds.
+ * @param bounds The bounds of the task.
+ * @param insetBounds The bounds used to calculate the system insets, which is used here to
+ * subtract the navigation bar/status bar size from the screen size reported
+ * to the application. See {@link IActivityManager#resizeDockedStack}.
+ * @return Update configuration or null if there is no change.
+ */
+ Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) {
if (Objects.equals(mBounds, bounds)) {
return null;
}
@@ -1316,7 +1346,12 @@ final class TaskRecord {
if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
mLastNonFullscreenBounds = mBounds;
}
- mOverrideConfig = calculateOverrideConfig(mBounds);
+
+ // Stable insets need to be subtracted because we also subtract it in the fullscreen
+ // configuration.
+ mTmpRect.set(bounds);
+ subtractStableInsets(mTmpRect, insetBounds != null ? insetBounds : mTmpRect);
+ mOverrideConfig = calculateOverrideConfig(mTmpRect);
}
if (mFullscreen != oldFullscreen) {
@@ -1326,6 +1361,16 @@ final class TaskRecord {
return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
}
+ private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds) {
+ mTmpRect2.set(inInsetBounds);
+ mService.mWindowManager.subtractStableInsets(mTmpRect2);
+ int leftInset = mTmpRect2.left - inInsetBounds.left;
+ int topInset = mTmpRect2.top - inInsetBounds.top;
+ int rightInset = inInsetBounds.right - mTmpRect2.right;
+ int bottomInset = inInsetBounds.bottom - mTmpRect2.bottom;
+ inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
+ }
+
Configuration calculateOverrideConfig(Rect bounds) {
final Configuration serviceConfig = mService.mConfiguration;
final Configuration config = new Configuration(Configuration.EMPTY);
@@ -1341,8 +1386,9 @@ final class TaskRecord {
? Configuration.ORIENTATION_PORTRAIT
: Configuration.ORIENTATION_LANDSCAPE;
final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
- config.screenLayout = Configuration.reduceScreenLayout(
- sl, config.screenWidthDp, config.screenHeightDp);
+ int longSize = Math.max(config.screenWidthDp, config.screenHeightDp);
+ int shortSize = Math.min(config.screenWidthDp, config.screenHeightDp);
+ config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
return config;
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 551f332cce8f..2f63b2d3e9bf 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,6 +24,7 @@ import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.content.Context.KEYGUARD_SERVICE;
import static android.os.Process.SYSTEM_UID;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -45,11 +46,14 @@ import android.app.Dialog;
import android.app.IStopUserCallback;
import android.app.IUserSwitchObserver;
import android.app.KeyguardManager;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
@@ -66,10 +70,12 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
+import android.provider.Settings;
import android.util.IntArray;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.R;
@@ -145,6 +151,34 @@ final class UserController {
private final LockPatternUtils mLockPatternUtils;
+ // Set of users who have completed the set-up process.
+ private final SparseBooleanArray mSetupCompletedUsers = new SparseBooleanArray();
+ private final UserSetupCompleteContentObserver mUserSetupCompleteContentObserver;
+
+ private class UserSetupCompleteContentObserver extends ContentObserver {
+ private final Uri mUserSetupComplete = Settings.Secure.getUriFor(USER_SETUP_COMPLETE);
+
+ public UserSetupCompleteContentObserver(Handler handler) {
+ super(handler);
+ }
+
+ void register(ContentResolver resolver) {
+ resolver.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
+ synchronized (mService) {
+ updateCurrentUserSetupCompleteLocked();
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (mUserSetupComplete.equals(uri)) {
+ synchronized (mService) {
+ updateCurrentUserSetupCompleteLocked();
+ }
+ }
+ }
+ }
+
UserController(ActivityManagerService service) {
mService = service;
mHandler = mService.mHandler;
@@ -154,6 +188,7 @@ final class UserController {
mUserLru.add(UserHandle.USER_SYSTEM);
mLockPatternUtils = new LockPatternUtils(mService.mContext);
updateStartedUserArrayLocked();
+ mUserSetupCompleteContentObserver = new UserSetupCompleteContentObserver(mHandler);
}
void finishUserSwitch(UserState uss) {
@@ -424,6 +459,7 @@ final class UserController {
mStartedUsers.remove(userId);
mUserLru.remove(Integer.valueOf(userId));
updateStartedUserArrayLocked();
+ mSetupCompletedUsers.delete(userId);
mService.onUserStoppedLocked(userId);
// Clean up all state and processes associated with the user.
@@ -619,6 +655,7 @@ final class UserController {
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
+ updateCurrentUserSetupCompleteLocked();
if (foreground) {
mCurrentUserId = userId;
@@ -833,6 +870,17 @@ final class UserController {
mUserSwitchObservers.finishBroadcast();
}
+ void updateCurrentUserSetupCompleteLocked() {
+ final ContentResolver cr = mService.mContext.getContentResolver();
+ final boolean setupComplete =
+ Settings.Secure.getIntForUser(cr, USER_SETUP_COMPLETE, 0, mCurrentUserId) != 0;
+ mSetupCompletedUsers.put(mCurrentUserId, setupComplete);
+ }
+
+ boolean isUserSetupCompleteLocked(int userId) {
+ return mSetupCompletedUsers.get(userId);
+ }
+
private void stopBackgroundUsersIfEnforced(int oldUserId) {
// Never stop system user
if (oldUserId == UserHandle.USER_SYSTEM) {
@@ -1141,12 +1189,17 @@ final class UserController {
}
}
+ void onSystemReady() {
+ updateCurrentProfileIdsLocked();
+ mUserSetupCompleteContentObserver.register(mService.mContext.getContentResolver());
+ }
+
/**
* Refreshes the list of users related to the current user when either a
* user switch happens or when a new related user is started in the
* background.
*/
- void updateCurrentProfileIdsLocked() {
+ private void updateCurrentProfileIdsLocked() {
final List<UserInfo> profiles = getUserManager().getProfiles(mCurrentUserId,
false /* enabledOnly */);
int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index a73a67a9ca7d..760b21819420 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -451,7 +451,7 @@ public class Tethering extends BaseNetworkObserver {
((BluetoothPan) proxy).setBluetoothTethering(enable);
// TODO: Enabling bluetooth tethering can fail asynchronously here.
// We should figure out a way to bubble up that failure instead of sending success.
- int result = ((BluetoothPan) proxy).isTetheringOn() ?
+ int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
ConnectivityManager.TETHER_ERROR_NO_ERROR :
ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
sendTetherResult(receiver, result);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index be55799dd763..e749433b1e3f 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -349,9 +349,9 @@ public class JobStatus {
pw.print(prefix); UserHandle.formatUid(pw, uId);
pw.print(" tag="); pw.println(tag);
pw.print(prefix);
- pw.print("Source: uid="); UserHandle.formatUid(pw, sourceUid);
- pw.print(" user="); pw.print(sourceUserId);
- pw.print(" pkg="); pw.println(sourcePackageName);
+ pw.print("Source: uid="); UserHandle.formatUid(pw, getSourceUid());
+ pw.print(" user="); pw.print(getSourceUserId());
+ pw.print(" pkg="); pw.println(getSourcePackageName());
pw.print(prefix); pw.println("JobInfo:");
pw.print(prefix); pw.print(" Service: ");
pw.println(job.getService().flattenToShortString());
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index f5da52ee733c..29d52c1739ba 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -250,6 +250,12 @@ abstract public class ManagedServices {
rebindServices();
}
+ public void onUserUnlocked(int user) {
+ if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
+ rebuildRestoredPackages();
+ rebindServices();
+ }
+
public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
if (service == null) {
return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 078094cfef7a..bcb2c598c82d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -816,6 +816,12 @@ public class NotificationManagerService extends SystemService {
} else if (action.equals(Intent.ACTION_USER_REMOVED)) {
final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
mZenModeHelper.onUserRemoved(user);
+ } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
+ final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ mConditionProviders.onUserUnlocked(user);
+ mListeners.onUserUnlocked(user);
+ mAssistant.onUserUnlocked(user);
+ mZenModeHelper.onUserUnlocked(user);
}
}
};
@@ -994,6 +1000,7 @@ public class NotificationManagerService extends SystemService {
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b7abce2159d3..7518c6e316f9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -16,7 +16,6 @@
package com.android.server.notification;
-import static android.media.AudioAttributes.USAGE_ALARM;
import static android.media.AudioAttributes.USAGE_NOTIFICATION;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.AudioAttributes.USAGE_UNKNOWN;
@@ -195,27 +194,35 @@ public class ZenModeHelper {
}
public void onUserSwitched(int user) {
+ loadConfigForUser(user, "onUserSwitched");
+ }
+
+ public void onUserRemoved(int user) {
+ if (user < UserHandle.USER_SYSTEM) return;
+ if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
+ mConfigs.remove(user);
+ }
+
+ public void onUserUnlocked(int user) {
+ loadConfigForUser(user, "onUserUnlocked");
+ }
+
+ private void loadConfigForUser(int user, String reason) {
if (mUser == user || user < UserHandle.USER_SYSTEM) return;
mUser = user;
- if (DEBUG) Log.d(TAG, "onUserSwitched u=" + user);
+ if (DEBUG) Log.d(TAG, reason + " u=" + user);
ZenModeConfig config = mConfigs.get(user);
if (config == null) {
- if (DEBUG) Log.d(TAG, "onUserSwitched: generating default config for user " + user);
+ if (DEBUG) Log.d(TAG, reason + " generating default config for user " + user);
config = mDefaultConfig.copy();
config.user = user;
}
synchronized (mConfig) {
- setConfigLocked(config, "onUserSwitched");
+ setConfigLocked(config, reason);
}
cleanUpZenRules();
}
- public void onUserRemoved(int user) {
- if (user < UserHandle.USER_SYSTEM) return;
- if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
- mConfigs.remove(user);
- }
-
public int getZenModeListenerInterruptionFilter() {
return NotificationManager.zenModeToInterruptionFilter(mZenMode);
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index dac89ec759f7..c08f71314d1f 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,11 +16,11 @@
package com.android.server.pm;
-import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.Build;
+import android.os.storage.StorageManager;
import android.util.Slog;
import com.android.internal.os.InstallerConnection;
@@ -29,9 +29,6 @@ import com.android.server.SystemService;
import dalvik.system.VMRuntime;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
public final class Installer extends SystemService {
private static final String TAG = "Installer";
@@ -52,19 +49,9 @@ public final class Installer extends SystemService {
/** This is an OTA update dexopt */
public static final int DEXOPT_OTA = 1 << 6;
- /** @hide */
- @IntDef(flag = true, value = {
- FLAG_DE_STORAGE,
- FLAG_CE_STORAGE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface StorageFlags {}
-
- public static final int FLAG_DE_STORAGE = 1 << 0;
- public static final int FLAG_CE_STORAGE = 1 << 1;
-
- public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 2;
- public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 3;
+ // NOTE: keep in sync with installd
+ public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
+ public static final int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
private final InstallerConnection mInstaller;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 64af21313a1d..a3af561bf44f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -176,8 +176,14 @@ class PackageDexOptimizer {
dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
- // No dexopt needed and we don't use profiles. Nothing to do.
- continue;
+ if (useProfiles) {
+ // Profiles may trigger re-compilation. The final decision is taken in
+ // installd.
+ dexoptNeeded = DexFile.DEX2OAT_NEEDED;
+ } else {
+ // No dexopt needed and we don't use profiles. Nothing to do.
+ continue;
+ }
}
final String dexoptType;
String oatDir = null;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 553a9a26de16..504ce3174d20 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -235,7 +235,6 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
-import com.android.server.pm.Installer.StorageFlags;
import com.android.server.pm.PermissionsState.PermissionState;
import com.android.server.pm.Settings.DatabaseVersion;
import com.android.server.pm.Settings.VersionInfo;
@@ -2388,9 +2387,9 @@ public class PackageManagerService extends IPackageManager.Stub {
// can't wait for user to start
final int flags;
if (StorageManager.isFileBasedEncryptionEnabled()) {
- flags = Installer.FLAG_DE_STORAGE;
+ flags = StorageManager.FLAG_STORAGE_DE;
} else {
- flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
reconcileAppsData(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, flags);
@@ -6860,7 +6859,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private boolean removeDataDirsLI(String volumeUuid, String packageName) {
// TODO: triage flags as part of 26466827
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
boolean res = true;
final int[] users = sUserManager.getUserIds();
@@ -6906,7 +6905,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
// TODO: triage flags as part of 26466827
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
final int[] users = sUserManager.getUserIds();
for (int user : users) {
@@ -13947,7 +13946,8 @@ public class PackageManagerService extends IPackageManager.Stub {
outInfo.removedUsers = new int[] {removeUser};
}
// TODO: triage flags as part of 26466827
- final int installerFlags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int installerFlags = StorageManager.FLAG_STORAGE_CE
+ | StorageManager.FLAG_STORAGE_DE;
try {
mInstaller.destroyAppData(ps.volumeUuid, packageName, removeUser, installerFlags);
} catch (InstallerException e) {
@@ -14127,7 +14127,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// record of app. This helps users recover from UID mismatches without
// resorting to a full data wipe.
// TODO: triage flags as part of 26466827
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
mInstaller.clearAppData(pkg.volumeUuid, packageName, userId, flags);
} catch (InstallerException e) {
@@ -14362,7 +14362,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
// TODO: triage flags as part of 26466827
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
mInstaller.clearAppData(p.volumeUuid, packageName, userId,
flags | Installer.FLAG_CLEAR_CACHE_ONLY);
@@ -14463,7 +14463,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// TODO: triage flags as part of 26466827
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
mInstaller.getAppSize(p.volumeUuid, packageName, userHandle, flags, apkPath,
libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
@@ -16787,16 +16787,20 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
// Reconcile app data for all started/unlocked users
+ final StorageManager sm = mContext.getSystemService(StorageManager.class);
final UserManager um = mContext.getSystemService(UserManager.class);
for (UserInfo user : um.getUsers()) {
+ final int flags;
if (um.isUserUnlocked(user.id)) {
- reconcileAppsData(volumeUuid, user.id,
- Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE);
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
} else if (um.isUserRunning(user.id)) {
- reconcileAppsData(volumeUuid, user.id, Installer.FLAG_DE_STORAGE);
+ flags = StorageManager.FLAG_STORAGE_DE;
} else {
continue;
}
+
+ sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
+ reconcileAppsData(volumeUuid, user.id, flags);
}
synchronized (mPackages) {
@@ -16905,20 +16909,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
}
}
-
- final StorageManager sm = mContext.getSystemService(StorageManager.class);
- final UserManager um = mContext.getSystemService(UserManager.class);
- for (UserInfo user : um.getUsers()) {
- final File userDir = Environment.getDataUserDirectory(volumeUuid, user.id);
- if (userDir.exists()) continue;
-
- try {
- sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, user.isEphemeral());
- UserManagerService.enforceSerialNumber(userDir, user.serialNumber);
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to create user directory on " + volumeUuid, e);
- }
- }
}
private void assertPackageKnown(String volumeUuid, String packageName)
@@ -16988,7 +16978,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps on all mounted volumes.
*/
- void reconcileAppsData(int userId, @StorageFlags int flags) {
+ void reconcileAppsData(int userId, int flags) {
final StorageManager storage = mContext.getSystemService(StorageManager.class);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
final String volumeUuid = vol.getFsUuid();
@@ -17005,7 +16995,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* Verifies that directories exist and that ownership and labeling is
* correct for all installed apps.
*/
- private void reconcileAppsData(String volumeUuid, int userId, @StorageFlags int flags) {
+ private void reconcileAppsData(String volumeUuid, int userId, int flags) {
Slog.v(TAG, "reconcileAppsData for " + volumeUuid + " u" + userId + " 0x"
+ Integer.toHexString(flags));
@@ -17016,7 +17006,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
// First look for stale data that doesn't belong, and check if things
// have changed since we did our last restorecon
- if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
if (!isUserKeyUnlocked(userId)) {
throw new RuntimeException(
"Yikes, someone asked us to reconcile CE storage while " + userId
@@ -17034,12 +17024,12 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
synchronized (mInstallLock) {
destroyAppDataLI(volumeUuid, packageName, userId,
- Installer.FLAG_CE_STORAGE);
+ StorageManager.FLAG_STORAGE_CE);
}
}
}
}
- if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
restoreconNeeded |= SELinuxMMAC.isRestoreconNeeded(deDir);
final File[] files = FileUtils.listFilesOrEmpty(deDir);
@@ -17051,7 +17041,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
logCriticalInfo(Log.WARN, "Destroying " + file + " due to: " + e);
synchronized (mInstallLock) {
destroyAppDataLI(volumeUuid, packageName, userId,
- Installer.FLAG_DE_STORAGE);
+ StorageManager.FLAG_STORAGE_DE);
}
}
}
@@ -17080,10 +17070,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
}
if (restoreconNeeded) {
- if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
SELinuxMMAC.setRestoreconDone(ceDir);
}
- if ((flags & Installer.FLAG_DE_STORAGE) != 0) {
+ if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) {
SELinuxMMAC.setRestoreconDone(deDir);
}
}
@@ -17112,9 +17102,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
for (UserInfo user : um.getUsers()) {
final int flags;
if (um.isUserUnlocked(user.id)) {
- flags = Installer.FLAG_DE_STORAGE | Installer.FLAG_CE_STORAGE;
+ flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
} else if (um.isUserRunning(user.id)) {
- flags = Installer.FLAG_DE_STORAGE;
+ flags = StorageManager.FLAG_STORAGE_DE;
} else {
continue;
}
@@ -17135,7 +17125,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
* will try recovering system apps by wiping data; third-party app data is
* left intact.
*/
- private void prepareAppData(String volumeUuid, int userId, @StorageFlags int flags,
+ private void prepareAppData(String volumeUuid, int userId, int flags,
PackageParser.Package pkg, boolean restoreconNeeded) {
if (DEBUG_APP_DATA) {
Slog.v(TAG, "prepareAppData for " + pkg.packageName + " u" + userId + " 0x"
@@ -17173,7 +17163,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
restoreconAppDataLI(volumeUuid, packageName, userId, flags, appId, app.seinfo);
}
- if ((flags & Installer.FLAG_CE_STORAGE) != 0) {
+ if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) {
// Create a native library symlink only if we have native libraries
// and if the native libraries are 32 bit libraries. We do not provide
// this symlink for 64 bit libraries.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index bbbe6936a4e6..fcb777b8e7fa 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3787,7 +3787,7 @@ final class Settings {
continue;
}
// TODO: triage flags!
- final int flags = Installer.FLAG_CE_STORAGE | Installer.FLAG_DE_STORAGE;
+ final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
try {
installer.createAppData(volumeUuids[i], names[i], userHandle, flags, appIds[i],
seinfos[i], targetSdkVersions[i]);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5f4656742e05..3cc7b10c6f24 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -25,7 +25,6 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
-import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -78,7 +77,9 @@ import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
-import com.android.server.pm.Installer.StorageFlags;
+
+import libcore.io.IoUtils;
+import libcore.util.Objects;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -96,9 +97,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-import libcore.util.Objects;
-
/**
* Service for {@link UserManager}.
*
@@ -1893,17 +1891,8 @@ public class UserManagerService extends IUserManager.Stub {
}
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
- for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
- final String volumeUuid = vol.getFsUuid();
- try {
- final File userDir = Environment.getDataUserDirectory(volumeUuid, userId);
- storage.prepareUserStorage(
- volumeUuid, userId, userInfo.serialNumber, userInfo.isEphemeral());
- enforceSerialNumber(userDir, userInfo.serialNumber);
- } catch (IOException e) {
- Log.wtf(LOG_TAG, "Failed to create user directory on " + volumeUuid, e);
- }
- }
+ prepareUserStorage(userId, userInfo.serialNumber,
+ StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
mPm.createNewUser(userId);
userInfo.partial = false;
synchronized (mPackagesLock) {
@@ -2466,11 +2455,24 @@ public class UserManagerService extends IUserManager.Stub {
}
/**
+ * Prepare storage areas for given user on all mounted devices.
+ */
+ private void prepareUserStorage(int userId, int userSerial, int flags) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
+ final String volumeUuid = vol.getFsUuid();
+ storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
+ }
+ }
+
+ /**
* Called right before a user is started. This gives us a chance to prepare
* app storage and apply any user restrictions.
*/
public void onBeforeStartUser(int userId) {
- mPm.reconcileAppsData(userId, Installer.FLAG_DE_STORAGE);
+ final int userSerial = getUserSerialNumber(userId);
+ prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_DE);
+ mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_DE);
if (userId != UserHandle.USER_SYSTEM) {
synchronized (mRestrictionsLock) {
@@ -2484,7 +2486,9 @@ public class UserManagerService extends IUserManager.Stub {
* app storage.
*/
public void onBeforeUnlockUser(int userId) {
- mPm.reconcileAppsData(userId, Installer.FLAG_CE_STORAGE);
+ final int userSerial = getUserSerialNumber(userId);
+ prepareUserStorage(userId, userSerial, StorageManager.FLAG_STORAGE_CE);
+ mPm.reconcileAppsData(userId, StorageManager.FLAG_STORAGE_CE);
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 43b82e9fcd11..a92cc31659e6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6877,7 +6877,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID);
final boolean freeformStackVisible =
mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID);
- final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible;
+ final boolean resizing = mWindowManagerInternal.isDockedDividerResizing();
+
+ // We need to force system bars when the docked stack is visible, when the freeform stack
+ // is visible but also when we are resizing for the transitions when docked stack
+ // visibility changes.
+ final boolean forceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
final boolean forceOpaqueSystemBars = forceShowSystemBars && !mForceStatusBarFromKeyguard;
// apply translucent bar vis flags
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index b065e855915d..342c078f8162 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -584,14 +584,14 @@ public final class TvInputManagerService extends SystemService {
for (IBinder sessionToken : serviceState.sessionTokens) {
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState.session == null && (inputId == null
- || sessionState.info.getId().equals(inputId))) {
+ || sessionState.inputId.equals(inputId))) {
sessionsToAbort.add(sessionState);
}
}
for (SessionState sessionState : sessionsToAbort) {
removeSessionStateLocked(sessionState.sessionToken, sessionState.userId);
sendSessionTokenToClientLocked(sessionState.client,
- sessionState.info.getId(), null, null, sessionState.seq);
+ sessionState.inputId, null, null, sessionState.seq);
}
updateServiceConnectionLocked(serviceState.component, userId);
}
@@ -601,7 +601,7 @@ public final class TvInputManagerService extends SystemService {
UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (DEBUG) {
- Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.info.getId() + ")");
+ Slog.d(TAG, "createSessionInternalLocked(inputId=" + sessionState.inputId + ")");
}
InputChannel[] channels = InputChannel.openInputChannelPair(sessionToken.toString());
@@ -611,14 +611,14 @@ public final class TvInputManagerService extends SystemService {
// Create a session. When failed, send a null token immediately.
try {
if (sessionState.isRecordingSession) {
- service.createRecordingSession(callback, sessionState.info.getId());
+ service.createRecordingSession(callback, sessionState.inputId);
} else {
- service.createSession(channels[1], callback, sessionState.info.getId());
+ service.createSession(channels[1], callback, sessionState.inputId);
}
} catch (RemoteException e) {
Slog.e(TAG, "error in createSession", e);
removeSessionStateLocked(sessionToken, userId);
- sendSessionTokenToClientLocked(sessionState.client, sessionState.info.getId(), null,
+ sendSessionTokenToClientLocked(sessionState.client, sessionState.inputId, null,
null, sessionState.seq);
}
channels[1].dispose();
@@ -684,14 +684,11 @@ public final class TvInputManagerService extends SystemService {
}
}
- TvInputInfo info = sessionState.info;
- if (info != null) {
- ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
- if (serviceState != null) {
- serviceState.sessionTokens.remove(sessionToken);
- }
+ ServiceState serviceState = userState.serviceStateMap.get(sessionState.componentName);
+ if (serviceState != null) {
+ serviceState.sessionTokens.remove(sessionToken);
}
- updateServiceConnectionLocked(sessionState.info.getComponent(), userId);
+ updateServiceConnectionLocked(sessionState.componentName, userId);
// Log the end of watch.
SomeArgs args = SomeArgs.obtain();
@@ -707,7 +704,7 @@ public final class TvInputManagerService extends SystemService {
sessionState = getSessionStateLocked(sessionState.hardwareSessionToken,
Process.SYSTEM_UID, userId);
}
- ServiceState serviceState = getServiceStateLocked(sessionState.info.getComponent(), userId);
+ ServiceState serviceState = getServiceStateLocked(sessionState.componentName, userId);
if (!serviceState.isHardware) {
return;
}
@@ -1091,8 +1088,9 @@ public final class TvInputManagerService extends SystemService {
// Create a new session token and a session state.
IBinder sessionToken = new Binder();
- SessionState sessionState = new SessionState(sessionToken, info,
- isRecordingSession, client, seq, callingUid, resolvedUserId);
+ SessionState sessionState = new SessionState(sessionToken, info.getId(),
+ info.getComponent(), isRecordingSession, client, seq, callingUid,
+ resolvedUserId);
// Add them to the global session state map of the current user.
userState.sessionStateMap.put(sessionToken, sessionState);
@@ -1273,7 +1271,7 @@ public final class TvInputManagerService extends SystemService {
// Log the start of watch.
SomeArgs args = SomeArgs.obtain();
- args.arg1 = sessionState.info.getComponent().getPackageName();
+ args.arg1 = sessionState.componentName.getPackageName();
args.arg2 = System.currentTimeMillis();
args.arg3 = ContentUris.parseId(channelUri);
args.arg4 = params;
@@ -1779,10 +1777,10 @@ public final class TvInputManagerService extends SystemService {
return false;
}
for (SessionState sessionState : userState.sessionStateMap.values()) {
- if (sessionState.info.getId().equals(inputId)
+ if (sessionState.inputId.equals(inputId)
&& sessionState.hardwareSessionToken != null) {
hardwareInputId = userState.sessionStateMap.get(
- sessionState.hardwareSessionToken).info.getId();
+ sessionState.hardwareSessionToken).inputId;
break;
}
}
@@ -1918,7 +1916,7 @@ public final class TvInputManagerService extends SystemService {
pw.println(entry.getKey() + ": " + session);
pw.increaseIndent();
- pw.println("info: " + session.info);
+ pw.println("inputId: " + session.inputId);
pw.println("client: " + session.client);
pw.println("seq: " + session.seq);
pw.println("callingUid: " + session.callingUid);
@@ -2046,7 +2044,8 @@ public final class TvInputManagerService extends SystemService {
}
private final class SessionState implements IBinder.DeathRecipient {
- private final TvInputInfo info;
+ private final String inputId;
+ private final ComponentName componentName;
private final boolean isRecordingSession;
private final ITvInputClient client;
private final int seq;
@@ -2058,10 +2057,12 @@ public final class TvInputManagerService extends SystemService {
// Not null if this session represents an external device connected to a hardware TV input.
private IBinder hardwareSessionToken;
- private SessionState(IBinder sessionToken, TvInputInfo info, boolean isRecordingSession,
- ITvInputClient client, int seq, int callingUid, int userId) {
+ private SessionState(IBinder sessionToken, String inputId, ComponentName componentName,
+ boolean isRecordingSession, ITvInputClient client, int seq, int callingUid,
+ int userId) {
this.sessionToken = sessionToken;
- this.info = info;
+ this.inputId = inputId;
+ this.componentName = componentName;
this.isRecordingSession = isRecordingSession;
this.client = client;
this.seq = seq;
@@ -2274,19 +2275,19 @@ public final class TvInputManagerService extends SystemService {
@Override
public void onSessionCreated(ITvInputSession session, IBinder hardwareSessionToken) {
if (DEBUG) {
- Slog.d(TAG, "onSessionCreated(inputId=" + mSessionState.info.getId() + ")");
+ Slog.d(TAG, "onSessionCreated(inputId=" + mSessionState.inputId + ")");
}
synchronized (mLock) {
mSessionState.session = session;
mSessionState.hardwareSessionToken = hardwareSessionToken;
if (session != null && addSessionTokenToClientStateLocked(session)) {
sendSessionTokenToClientLocked(mSessionState.client,
- mSessionState.info.getId(), mSessionState.sessionToken, mChannels[0],
+ mSessionState.inputId, mSessionState.sessionToken, mChannels[0],
mSessionState.seq);
} else {
removeSessionStateLocked(mSessionState.sessionToken, mSessionState.userId);
sendSessionTokenToClientLocked(mSessionState.client,
- mSessionState.info.getId(), null, null, mSessionState.seq);
+ mSessionState.inputId, null, null, mSessionState.seq);
}
mChannels[0].dispose();
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index be1b85c2f9b5..a06d3fc74393 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -289,11 +289,9 @@ class Task implements DimLayer.DimLayerUser {
if (displayContent != null) {
displayContent.getLogicalDisplayRect(mTmpRect);
rotation = displayContent.getDisplayInfo().rotation;
- if (bounds == null) {
+ mFullscreen = bounds == null;
+ if (mFullscreen) {
bounds = mTmpRect;
- mFullscreen = true;
- } else {
- mFullscreen = mTmpRect.equals(bounds);
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ecc13648aeb7..40ca1c5a688c 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -255,11 +255,9 @@ public class TaskStack implements DimLayer.DimLayerUser,
if (mDisplayContent != null) {
mDisplayContent.getLogicalDisplayRect(mTmpRect);
rotation = mDisplayContent.getDisplayInfo().rotation;
- if (bounds == null) {
+ mFullscreen = bounds == null;
+ if (mFullscreen) {
bounds = mTmpRect;
- mFullscreen = true;
- } else {
- mFullscreen = mTmpRect.equals(bounds);
}
}
@@ -587,7 +585,8 @@ public class TaskStack implements DimLayer.DimLayerUser,
}
void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
- if (!StackId.isResizeableByDockedStack(mStackId) || mDisplayContent == null) {
+ if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
+ || mDisplayContent == null) {
outBounds.set(mBounds);
return;
}
@@ -616,8 +615,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
mDisplayContent.getLogicalDisplayRect(mTmpRect);
dockedStack.getRawBounds(mTmpRect2);
- final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP
- || dockedSide == DOCKED_LEFT;
+ final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
@@ -722,6 +720,19 @@ public class TaskStack implements DimLayer.DimLayerUser,
}
}
+ void resetDockedStackToMiddle() {
+ if (mStackId != DOCKED_STACK_ID) {
+ throw new IllegalStateException("Not a docked stack=" + this);
+ }
+
+ mService.mDockedStackCreateBounds = null;
+
+ final Rect bounds = new Rect();
+ getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
+ mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
+ 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
+ }
+
void detachDisplay() {
EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
@@ -865,14 +876,14 @@ public class TaskStack implements DimLayer.DimLayerUser,
final int orientation = mService.mCurConfiguration.orientation;
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
// Portrait mode, docked either at the top or the bottom.
- if (bounds.top - mTmpRect.top < mTmpRect.bottom - bounds.bottom) {
+ if (bounds.top - mTmpRect.top <= mTmpRect.bottom - bounds.bottom) {
return DOCKED_TOP;
} else {
return DOCKED_BOTTOM;
}
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Landscape mode, docked either on the left or on the right.
- if (bounds.left - mTmpRect.left < mTmpRect.right - bounds.right) {
+ if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) {
return DOCKED_LEFT;
} else {
return DOCKED_RIGHT;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a26430e773cc..ae6c89a4d610 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -464,6 +464,8 @@ public class WindowManagerService extends IWindowManager.Stub
EmulatorDisplayOverlay mEmulatorDisplayOverlay;
final float[] mTmpFloats = new float[9];
+ final Rect mTmpRect = new Rect();
+ final Rect mTmpRect2 = new Rect();
boolean mDisplayReady;
boolean mSafeMode;
@@ -4845,17 +4847,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- /** Returns true if the input bounds corresponds to the fullscreen bounds the stack is on. */
- public boolean isFullscreenBounds(int stackId, Rect bounds) {
- synchronized (mWindowMap) {
- final TaskStack stack = mStackIdToStack.get(stackId);
- if (stack == null || bounds == null) {
- return true;
- }
- return stack.isFullscreenBounds(bounds);
- }
- }
-
/**
* Re-sizes a stack and its containing tasks.
* @param stackId Id of stack to resize.
@@ -5373,8 +5364,18 @@ public class WindowManagerService extends IWindowManager.Stub
mWindowPlacerLocked.performSurfacePlacement();
// Notify whether the docked stack exists for the current user
- getDefaultDisplayContentLocked().mDividerControllerLocked
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ displayContent.mDividerControllerLocked
.notifyDockedStackExistsChanged(hasDockedTasksForUser(newUserId));
+
+ // If the display is already prepared, update the density.
+ // Otherwise, we'll update it when it's prepared.
+ if (mDisplayReady) {
+ final int forcedDensity = getForcedDisplayDensityForUserLocked(newUserId);
+ final int targetDensity = forcedDensity != 0 ? forcedDensity
+ : displayContent.mInitialDisplayDensity;
+ setForcedDisplayDensityLocked(displayContent, targetDensity);
+ }
}
}
@@ -8370,21 +8371,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
// Display density.
- String densityStr = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_DENSITY_FORCED);
- if (densityStr == null || densityStr.length() == 0) {
- densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
- }
- if (densityStr != null && densityStr.length() > 0) {
- int density;
- try {
- density = Integer.parseInt(densityStr);
- if (displayContent.mBaseDisplayDensity != density) {
- Slog.i(TAG_WM, "FORCED DISPLAY DENSITY: " + density);
- displayContent.mBaseDisplayDensity = density;
- }
- } catch (NumberFormatException ex) {
- }
+ final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId);
+ if (density != 0) {
+ displayContent.mBaseDisplayDensity = density;
}
// Display scaling mode.
@@ -8470,8 +8459,9 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
setForcedDisplayDensityLocked(displayContent, density);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.DISPLAY_DENSITY_FORCED,
+ Integer.toString(density), mCurrentUserId);
}
}
} finally {
@@ -8479,13 +8469,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- // displayContent must not be null
- private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
- Slog.i(TAG_WM, "Using new display density: " + density);
- displayContent.mBaseDisplayDensity = density;
- reconfigureDisplayLocked(displayContent);
- }
-
@Override
public void clearForcedDisplayDensity(int displayId) {
if (mContext.checkCallingOrSelfPermission(
@@ -8504,8 +8487,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (displayContent != null) {
setForcedDisplayDensityLocked(displayContent,
displayContent.mInitialDisplayDensity);
- Settings.Global.putString(mContext.getContentResolver(),
- Settings.Global.DISPLAY_DENSITY_FORCED, "");
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
}
}
} finally {
@@ -8513,6 +8496,38 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ /**
+ * @param userId the ID of the user
+ * @return the forced display density for the specified user, if set, or
+ * {@code 0} if not set
+ */
+ private int getForcedDisplayDensityForUserLocked(int userId) {
+ String densityStr = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.DISPLAY_DENSITY_FORCED, userId);
+ if (densityStr == null || densityStr.length() == 0) {
+ densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
+ }
+ if (densityStr != null && densityStr.length() > 0) {
+ try {
+ return Integer.parseInt(densityStr);
+ } catch (NumberFormatException ex) {
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Forces the given display to the use the specified density.
+ *
+ * @param displayContent the display to modify
+ * @param density the density in DPI to use
+ */
+ private void setForcedDisplayDensityLocked(@NonNull DisplayContent displayContent,
+ int density) {
+ displayContent.mBaseDisplayDensity = density;
+ reconfigureDisplayLocked(displayContent);
+ }
+
// displayContent must not be null
private void reconfigureDisplayLocked(DisplayContent displayContent) {
// TODO: Multidisplay: for now only use with default display.
@@ -10394,8 +10409,28 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void getStableInsets(Rect outInsets) throws RemoteException {
synchronized (mWindowMap) {
+ getStableInsetsLocked(outInsets);
+ }
+ }
+
+ private void getStableInsetsLocked(Rect outInsets) {
+ final DisplayInfo di = getDefaultDisplayInfoLocked();
+ mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
+ }
+
+ /**
+ * Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
+ * inset areas.
+ *
+ * @param inOutBounds The inOutBounds to subtract the stable inset areas from.
+ */
+ public void subtractStableInsets(Rect inOutBounds) {
+ synchronized (mWindowMap) {
+ getStableInsetsLocked(mTmpRect2);
final DisplayInfo di = getDefaultDisplayInfoLocked();
- mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
+ mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
+ mTmpRect.inset(mTmpRect2);
+ inOutBounds.intersect(mTmpRect);
}
}
@@ -10599,5 +10634,12 @@ public class WindowManagerService extends IWindowManager.Stub
return WindowManagerService.this.isStackVisibleLocked(stackId);
}
}
+
+ @Override
+ public boolean isDockedDividerResizing() {
+ synchronized (mWindowMap) {
+ return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 465c7e0937b6..880514cd25f6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import com.android.server.input.InputWindowHandle;
-
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
@@ -53,10 +51,13 @@ import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import com.android.server.input.InputWindowHandle;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
@@ -75,8 +76,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -1259,8 +1260,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
* it may obscure windows behind it.
*/
boolean isOpaqueDrawn() {
- return (mAttrs.format == PixelFormat.OPAQUE
- || mAttrs.type == TYPE_WALLPAPER)
+ // When there is keyguard, wallpaper could be placed over the secure app
+ // window but invisible. We need to check wallpaper visibility explicitly
+ // to determine if it's occluding apps.
+ return ((!mIsWallpaper && mAttrs.format == PixelFormat.OPAQUE)
+ || (mIsWallpaper && mWallpaperVisible))
&& isDrawnLw() && mWinAnimator.mAnimation == null
&& (mAppToken == null || mAppToken.mAppAnimator.animation == null);
}
@@ -1608,6 +1612,14 @@ final class WindowState implements WindowManagerPolicy.WindowState {
win.mAppToken.appDied = true;
}
mService.removeWindowLocked(win);
+ if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
+ // The owner of the docked divider died :( We reset the docked stack,
+ // just in case they have the divider at an unstable position.
+ final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
+ if (stack != null) {
+ stack.resetDockedStackToMiddle();
+ }
+ }
} else if (mHasSurface) {
Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
mService.removeWindowLocked(WindowState.this);
@@ -2133,7 +2145,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
// background.
return (mDisplayContent.mDividerControllerLocked.isResizing()
|| mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
- !task.inFreeformWorkspace() && !task.isFullscreen();
+ !task.inFreeformWorkspace();
+
}
void setDragResizing() {
@@ -2327,6 +2340,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
if (mDrawLock != null) {
pw.print(prefix); pw.println("mDrawLock=" + mDrawLock);
}
+ if (isDragResizing()) {
+ pw.print(prefix); pw.println("isDragResizing=" + isDragResizing());
+ }
+ if (computeDragResizing()) {
+ pw.print(prefix); pw.println("computeDragResizing=" + computeDragResizing());
+ }
}
String makeInputChannelName() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 908d2f0e8867..f296d68cedcf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4132,7 +4132,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
final IBinder response) {
// Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
- if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ if (!isCallerWithSystemUid()) {
return;
}
@@ -5860,8 +5860,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
- if (hasUserSetupCompleted(userHandle)
- && !UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
+ if (hasUserSetupCompleted(userHandle) && !isCallerWithSystemUid()) {
throw new IllegalStateException("Cannot set the profile owner on a user which is "
+ "already set-up");
}
@@ -5921,8 +5920,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void enforceManageUsers() {
final int callingUid = mInjector.binderGetCallingUid();
- if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
- || callingUid == Process.ROOT_UID)) {
+ if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
}
}
@@ -5945,8 +5943,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (userHandle == UserHandle.getUserId(callingUid)) {
return;
}
- if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
- || callingUid == Process.ROOT_UID)) {
+ if (!(isCallerWithSystemUid() || callingUid == Process.ROOT_UID)) {
mContext.enforceCallingOrSelfPermission(permission,
"Must be system or have " + permission + " permission");
}
@@ -5964,6 +5961,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private boolean isCallerWithSystemUid() {
+ return UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID);
+ }
+
private int getProfileParentId(int userHandle) {
final long ident = mInjector.binderClearCallingIdentity();
try {
@@ -6248,7 +6249,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public ComponentName getRestrictionsProvider(int userHandle) {
synchronized (this) {
- if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ if (!isCallerWithSystemUid()) {
throw new SecurityException("Only the system can query the permission provider");
}
DevicePolicyData userData = getUserData(userHandle);
@@ -6321,8 +6322,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* permittedList or are a system app.
*/
private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages,
- List<String> permittedList) {
- int userIdToCheck = UserHandle.getCallingUserId();
+ List<String> permittedList, int userIdToCheck) {
long id = mInjector.binderClearCallingIdentity();
try {
// If we have an enabled packages list for a managed profile the packages
@@ -6389,7 +6389,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
for (AccessibilityServiceInfo service : enabledServices) {
enabledPackages.add(service.getResolveInfo().serviceInfo.packageName);
}
- if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList)) {
+ if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
+ userId)) {
Slog.e(LOG_TAG, "Cannot set permitted accessibility services, "
+ "because it contains already enabled accesibility services.");
return false;
@@ -6481,6 +6482,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ @Override
+ public boolean isAccessibilityServicePermittedByAdmin(ComponentName who, String packageName,
+ int userHandle) {
+ if (!mHasFeature) {
+ return true;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkStringNotEmpty(packageName, "packageName is null");
+ if (!isCallerWithSystemUid()){
+ throw new SecurityException(
+ "Only the system can query if an accessibility service is disabled by admin");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin.permittedAccessiblityServices == null) {
+ return true;
+ }
+ return checkPackagesInPermittedListOrSystem(Arrays.asList(packageName),
+ admin.permittedAccessiblityServices, userHandle);
+ }
+ }
+
private boolean checkCallerIsCurrentUserOrProfile() {
int callingUserId = UserHandle.getCallingUserId();
long token = mInjector.binderClearCallingIdentity();
@@ -6536,7 +6559,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
for (InputMethodInfo ime : enabledImes) {
enabledPackages.add(ime.getPackageName());
}
- if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList)) {
+ if (!checkPackagesInPermittedListOrSystem(enabledPackages, packageList,
+ mInjector.binderGetCallingUserHandle().getIdentifier())) {
Slog.e(LOG_TAG, "Cannot set permitted input methods, "
+ "because it contains already enabled input method.");
return false;
@@ -6629,6 +6653,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
+ public boolean isInputMethodPermittedByAdmin(ComponentName who, String packageName,
+ int userHandle) {
+ if (!mHasFeature) {
+ return true;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ Preconditions.checkStringNotEmpty(packageName, "packageName is null");
+ if (!isCallerWithSystemUid()) {
+ throw new SecurityException(
+ "Only the system can query if an input method is disabled by admin");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin.permittedInputMethods == null) {
+ return true;
+ }
+ return checkPackagesInPermittedListOrSystem(Arrays.asList(packageName),
+ admin.permittedInputMethods, userHandle);
+ }
+ }
+
+ @Override
public UserHandle createUser(ComponentName who, String name) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
@@ -7425,7 +7471,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
@Override
public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
- if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ if (!isCallerWithSystemUid()) {
throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
}
synchronized (this) {
@@ -8180,7 +8226,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return null;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ if (!isCallerWithSystemUid()) {
throw new SecurityException("Only the system can query support message for user");
}
synchronized (this) {
@@ -8198,7 +8244,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return null;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ if (!isCallerWithSystemUid()) {
throw new SecurityException("Only the system can query support message for user");
}
synchronized (this) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b64db578decb..0cf93288714f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -496,6 +496,7 @@ public final class SystemServer {
boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
+ boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
try {
@@ -788,7 +789,9 @@ public final class SystemServer {
mSystemServiceManager.startService(
"com.android.server.wifi.WifiScanningService");
- mSystemServiceManager.startService("com.android.server.wifi.RttService");
+ if (!disableRtt) {
+ mSystemServiceManager.startService("com.android.server.wifi.RttService");
+ }
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
@@ -1088,7 +1091,9 @@ public final class SystemServer {
mSystemServiceManager.startService(TrustManagerService.class);
- mSystemServiceManager.startService(FingerprintService.class);
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ mSystemServiceManager.startService(FingerprintService.class);
+ }
traceBeginAndSlog("StartBackgroundDexOptService");
try {
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 25cb64c94215..071ec1b025f0 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
services.core \
services.devicepolicy \
services.net \
+ services.usage \
easymocklib \
guava \
android-support-test \
@@ -26,7 +27,9 @@ LOCAL_PACKAGE_NAME := FrameworksServicesTests
LOCAL_CERTIFICATE := platform
-LOCAL_JNI_SHARED_LIBRARIES := libapfjni
+LOCAL_JNI_SHARED_LIBRARIES := \
+ libapfjni \
+ libnativehelper
include $(BUILD_PACKAGE)
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 3dc1a9ab7847..53ca45dde5ae 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -29,6 +29,7 @@ import android.test.AndroidTestCase;
import java.io.File;
import java.util.List;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -135,8 +136,7 @@ public abstract class DpmTestBase extends AndroidTestCase {
doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
MockUtils.checkIntentComponent(admin),
- eq(PackageManager.GET_META_DATA
- | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+ anyInt(),
eq(UserHandle.getUserId(packageUid)));
// Set up getPackageInfo().
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
new file mode 100644
index 000000000000..9ccb1a618568
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+package com.android.server.usage;
+
+import android.os.FileUtils;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+public class AppIdleHistoryTests extends AndroidTestCase {
+
+ File mStorageDir;
+
+ final static String PACKAGE_1 = "com.android.testpackage1";
+ final static String PACKAGE_2 = "com.android.testpackage2";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mStorageDir = new File(getContext().getFilesDir(), "appidle");
+ mStorageDir.mkdirs();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ FileUtils.deleteContents(mStorageDir);
+ super.tearDown();
+ }
+
+ public void testFilesCreation() {
+ final int userId = 0;
+ AppIdleHistory aih = new AppIdleHistory(mStorageDir, 0);
+
+ aih.updateDisplayLocked(true, /* elapsedRealtime= */ 1000);
+ aih.updateDisplayLocked(false, /* elapsedRealtime= */ 2000);
+ // Screen On time file should be written right away
+ assertTrue(aih.getScreenOnTimeFile().exists());
+
+ aih.writeAppIdleTimesLocked(userId);
+ // stats file should be written now
+ assertTrue(new File(new File(mStorageDir, "users/" + userId),
+ AppIdleHistory.APP_IDLE_FILENAME).exists());
+ }
+
+ public void testScreenOnTime() {
+ AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
+ aih.updateDisplayLocked(false, 2000);
+ assertEquals(aih.getScreenOnTimeLocked(2000), 0);
+ aih.updateDisplayLocked(true, 3000);
+ assertEquals(aih.getScreenOnTimeLocked(4000), 1000);
+ assertEquals(aih.getScreenOnTimeLocked(5000), 2000);
+ aih.updateDisplayLocked(false, 6000);
+ // Screen on time should not keep progressing with screen is off
+ assertEquals(aih.getScreenOnTimeLocked(7000), 3000);
+ assertEquals(aih.getScreenOnTimeLocked(8000), 3000);
+ aih.writeElapsedTimeLocked();
+
+ // Check if the screen on time is persisted across instantiations
+ AppIdleHistory aih2 = new AppIdleHistory(mStorageDir, 0);
+ assertEquals(aih2.getScreenOnTimeLocked(11000), 3000);
+ aih2.updateDisplayLocked(true, 4000);
+ aih2.updateDisplayLocked(false, 5000);
+ assertEquals(aih2.getScreenOnTimeLocked(13000), 4000);
+ }
+
+ public void testPackageEvents() {
+ AppIdleHistory aih = new AppIdleHistory(mStorageDir, 1000);
+ aih.setThresholds(4000, 1000);
+ aih.updateDisplayLocked(true, 1000);
+ // App is not-idle by default
+ assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 1500));
+ // Still not idle
+ assertFalse(aih.isIdleLocked(PACKAGE_1, 0, 3000));
+ // Idle now
+ assertTrue(aih.isIdleLocked(PACKAGE_1, 0, 8000));
+ // Not idle
+ assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 9000));
+
+ // Screen off
+ aih.updateDisplayLocked(false, 9100);
+ // Still idle after 10 seconds because screen hasn't been on long enough
+ assertFalse(aih.isIdleLocked(PACKAGE_2, 0, 20000));
+ aih.updateDisplayLocked(true, 21000);
+ assertTrue(aih.isIdleLocked(PACKAGE_2, 0, 23000));
+ }
+} \ No newline at end of file
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index e3c0868ea3a2..3e2b43d2af5c 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -16,19 +16,45 @@
package com.android.server.usage;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.os.UserHandle;
import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Slog;
import android.util.SparseArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
/**
* Keeps track of recent active state changes in apps.
* Access should be guarded by a lock by the caller.
*/
public class AppIdleHistory {
- private SparseArray<ArrayMap<String,byte[]>> mIdleHistory = new SparseArray<>();
- private long lastPeriod = 0;
+ private static final String TAG = "AppIdleHistory";
+
+ // History for all users and all packages
+ private SparseArray<ArrayMap<String,PackageHistory>> mIdleHistory = new SparseArray<>();
+ private long mLastPeriod = 0;
private static final long ONE_MINUTE = 60 * 1000;
private static final int HISTORY_SIZE = 100;
private static final int FLAG_LAST_STATE = 2;
@@ -36,77 +62,353 @@ public class AppIdleHistory {
private static final long PERIOD_DURATION = UsageStatsService.COMPRESS_TIME ? ONE_MINUTE
: 60 * ONE_MINUTE;
- public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
- ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
- byte[] packageHistory = getPackageHistory(userHistory, packageName);
+ @VisibleForTesting
+ static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
+ private static final String TAG_PACKAGES = "packages";
+ private static final String TAG_PACKAGE = "package";
+ private static final String ATTR_NAME = "name";
+ // Screen on timebase time when app was last used
+ private static final String ATTR_SCREEN_IDLE = "screenIdleTime";
+ // Elapsed timebase time when app was last used
+ private static final String ATTR_ELAPSED_IDLE = "elapsedIdleTime";
+
+ // device on time = mElapsedDuration + (timeNow - mElapsedSnapshot)
+ private long mElapsedSnapshot; // Elapsed time snapshot when last write of mDeviceOnDuration
+ private long mElapsedDuration; // Total device on duration since device was "born"
+
+ // screen on time = mScreenOnDuration + (timeNow - mScreenOnSnapshot)
+ private long mScreenOnSnapshot; // Elapsed time snapshot when last write of mScreenOnDuration
+ private long mScreenOnDuration; // Total screen on duration since device was "born"
+
+ private long mElapsedTimeThreshold;
+ private long mScreenOnTimeThreshold;
+ private final File mStorageDir;
+
+ private boolean mScreenOn;
+
+ private static class PackageHistory {
+ final byte[] recent = new byte[HISTORY_SIZE];
+ long lastUsedElapsedTime;
+ long lastUsedScreenTime;
+ }
+
+ AppIdleHistory(long elapsedRealtime) {
+ this(Environment.getDataSystemDirectory(), elapsedRealtime);
+ }
+
+ @VisibleForTesting
+ AppIdleHistory(File storageDir, long elapsedRealtime) {
+ mElapsedSnapshot = elapsedRealtime;
+ mScreenOnSnapshot = elapsedRealtime;
+ mStorageDir = storageDir;
+ readScreenOnTimeLocked();
+ }
+
+ public void setThresholds(long elapsedTimeThreshold, long screenOnTimeThreshold) {
+ mElapsedTimeThreshold = elapsedTimeThreshold;
+ mScreenOnTimeThreshold = screenOnTimeThreshold;
+ }
+
+ public void updateDisplayLocked(boolean screenOn, long elapsedRealtime) {
+ if (screenOn == mScreenOn) return;
+
+ mScreenOn = screenOn;
+ if (mScreenOn) {
+ mScreenOnSnapshot = elapsedRealtime;
+ } else {
+ mScreenOnDuration += elapsedRealtime - mScreenOnSnapshot;
+ mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
+ writeScreenOnTimeLocked();
+ mElapsedSnapshot = elapsedRealtime;
+ }
+ }
+
+ public long getScreenOnTimeLocked(long elapsedRealtime) {
+ long screenOnTime = mScreenOnDuration;
+ if (mScreenOn) {
+ screenOnTime += elapsedRealtime - mScreenOnSnapshot;
+ }
+ return screenOnTime;
+ }
+
+ @VisibleForTesting
+ File getScreenOnTimeFile() {
+ return new File(mStorageDir, "screen_on_time");
+ }
+
+ private void readScreenOnTimeLocked() {
+ File screenOnTimeFile = getScreenOnTimeFile();
+ if (screenOnTimeFile.exists()) {
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(screenOnTimeFile));
+ mScreenOnDuration = Long.parseLong(reader.readLine());
+ mElapsedDuration = Long.parseLong(reader.readLine());
+ reader.close();
+ } catch (IOException | NumberFormatException e) {
+ }
+ } else {
+ writeScreenOnTimeLocked();
+ }
+ }
+
+ private void writeScreenOnTimeLocked() {
+ AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
+ FileOutputStream fos = null;
+ try {
+ fos = screenOnTimeFile.startWrite();
+ fos.write((Long.toString(mScreenOnDuration) + "\n"
+ + Long.toString(mElapsedDuration) + "\n").getBytes());
+ screenOnTimeFile.finishWrite(fos);
+ } catch (IOException ioe) {
+ screenOnTimeFile.failWrite(fos);
+ }
+ }
+
+ /**
+ * To be called periodically to keep track of elapsed time when app idle times are written
+ */
+ public void writeElapsedTimeLocked() {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ // Only bump up and snapshot the elapsed time. Don't change screen on duration.
+ mElapsedDuration += elapsedRealtime - mElapsedSnapshot;
+ mElapsedSnapshot = elapsedRealtime;
+ writeScreenOnTimeLocked();
+ }
+
+ public void reportUsageLocked(String packageName, int userId, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ elapsedRealtime);
+
+ shiftHistoryToNow(userHistory, elapsedRealtime);
+
+ packageHistory.lastUsedElapsedTime = mElapsedDuration
+ + (elapsedRealtime - mElapsedSnapshot);
+ packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
+ packageHistory.recent[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
+ }
+
+ public void setIdle(String packageName, int userId, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ elapsedRealtime);
+
+ shiftHistoryToNow(userHistory, elapsedRealtime);
- long thisPeriod = timeNow / PERIOD_DURATION;
+ packageHistory.recent[HISTORY_SIZE - 1] &= ~FLAG_LAST_STATE;
+ }
+
+ private void shiftHistoryToNow(ArrayMap<String, PackageHistory> userHistory,
+ long elapsedRealtime) {
+ long thisPeriod = elapsedRealtime / PERIOD_DURATION;
// Has the period switched over? Slide all users' package histories
- if (lastPeriod != 0 && lastPeriod < thisPeriod
- && (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
- int diff = (int) (thisPeriod - lastPeriod);
+ if (mLastPeriod != 0 && mLastPeriod < thisPeriod
+ && (thisPeriod - mLastPeriod) < HISTORY_SIZE - 1) {
+ int diff = (int) (thisPeriod - mLastPeriod);
final int NUSERS = mIdleHistory.size();
for (int u = 0; u < NUSERS; u++) {
userHistory = mIdleHistory.valueAt(u);
- for (byte[] history : userHistory.values()) {
+ for (PackageHistory idleState : userHistory.values()) {
// Shift left
- System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
+ System.arraycopy(idleState.recent, diff, idleState.recent, 0,
+ HISTORY_SIZE - diff);
// Replicate last state across the diff
for (int i = 0; i < diff; i++) {
- history[HISTORY_SIZE - i - 1] =
- (byte) (history[HISTORY_SIZE - diff - 1] & FLAG_LAST_STATE);
+ idleState.recent[HISTORY_SIZE - i - 1] =
+ (byte) (idleState.recent[HISTORY_SIZE - diff - 1] & FLAG_LAST_STATE);
}
}
}
}
- lastPeriod = thisPeriod;
- if (!idle) {
- packageHistory[HISTORY_SIZE - 1] = FLAG_LAST_STATE | FLAG_PARTIAL_ACTIVE;
- } else {
- packageHistory[HISTORY_SIZE - 1] &= ~FLAG_LAST_STATE;
- }
+ mLastPeriod = thisPeriod;
}
- private ArrayMap<String, byte[]> getUserHistory(int userId) {
- ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
+ private ArrayMap<String, PackageHistory> getUserHistoryLocked(int userId) {
+ ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
if (userHistory == null) {
userHistory = new ArrayMap<>();
mIdleHistory.put(userId, userHistory);
+ readAppIdleTimesLocked(userId, userHistory);
}
return userHistory;
}
- private byte[] getPackageHistory(ArrayMap<String, byte[]> userHistory, String packageName) {
- byte[] packageHistory = userHistory.get(packageName);
+ private PackageHistory getPackageHistoryLocked(ArrayMap<String, PackageHistory> userHistory,
+ String packageName, long elapsedRealtime) {
+ PackageHistory packageHistory = userHistory.get(packageName);
if (packageHistory == null) {
- packageHistory = new byte[HISTORY_SIZE];
+ packageHistory = new PackageHistory();
+ packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime);
+ packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime);
userHistory.put(packageName, packageHistory);
}
return packageHistory;
}
- public void removeUser(int userId) {
+ public void onUserRemoved(int userId) {
mIdleHistory.remove(userId);
}
- public boolean isIdle(int userId, String packageName) {
- ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
- byte[] packageHistory = getPackageHistory(userHistory, packageName);
- return (packageHistory[HISTORY_SIZE - 1] & FLAG_LAST_STATE) == 0;
+ public boolean isIdleLocked(String packageName, int userId, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ PackageHistory packageHistory =
+ getPackageHistoryLocked(userHistory, packageName, elapsedRealtime);
+ if (packageHistory == null) {
+ return false; // Default to not idle
+ } else {
+ return hasPassedThresholdsLocked(packageHistory, elapsedRealtime);
+ }
+ }
+
+ private long getElapsedTimeLocked(long elapsedRealtime) {
+ return (elapsedRealtime - mElapsedSnapshot + mElapsedDuration);
+ }
+
+ public void setIdleLocked(String packageName, int userId, boolean idle, long elapsedRealtime) {
+ ArrayMap<String, PackageHistory> userHistory = getUserHistoryLocked(userId);
+ PackageHistory packageHistory = getPackageHistoryLocked(userHistory, packageName,
+ elapsedRealtime);
+ packageHistory.lastUsedElapsedTime = getElapsedTimeLocked(elapsedRealtime)
+ - mElapsedTimeThreshold;
+ packageHistory.lastUsedScreenTime = getScreenOnTimeLocked(elapsedRealtime)
+ - (idle ? mScreenOnTimeThreshold : 0) - 1000 /* just a second more */;
+ }
+
+ private boolean hasPassedThresholdsLocked(PackageHistory packageHistory, long elapsedRealtime) {
+ return (packageHistory.lastUsedScreenTime
+ <= getScreenOnTimeLocked(elapsedRealtime) - mScreenOnTimeThreshold)
+ && (packageHistory.lastUsedElapsedTime
+ <= getElapsedTimeLocked(elapsedRealtime) - mElapsedTimeThreshold);
+ }
+
+ private File getUserFile(int userId) {
+ return new File(new File(new File(mStorageDir, "users"),
+ Integer.toString(userId)), APP_IDLE_FILENAME);
+ }
+
+ private void readAppIdleTimesLocked(int userId, ArrayMap<String, PackageHistory> userHistory) {
+ FileInputStream fis = null;
+ try {
+ AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
+ fis = appIdleFile.openRead();
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(fis, StandardCharsets.UTF_8.name());
+
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Skip
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ Slog.e(TAG, "Unable to read app idle file for user " + userId);
+ return;
+ }
+ if (!parser.getName().equals(TAG_PACKAGES)) {
+ return;
+ }
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG) {
+ final String name = parser.getName();
+ if (name.equals(TAG_PACKAGE)) {
+ final String packageName = parser.getAttributeValue(null, ATTR_NAME);
+ PackageHistory packageHistory = new PackageHistory();
+ packageHistory.lastUsedElapsedTime =
+ Long.parseLong(parser.getAttributeValue(null, ATTR_ELAPSED_IDLE));
+ packageHistory.lastUsedScreenTime =
+ Long.parseLong(parser.getAttributeValue(null, ATTR_SCREEN_IDLE));
+ userHistory.put(packageName, packageHistory);
+ }
+ }
+ }
+ } catch (IOException | XmlPullParserException e) {
+ Slog.e(TAG, "Unable to read app idle file for user " + userId);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ public void writeAppIdleTimesLocked(int userId) {
+ FileOutputStream fos = null;
+ AtomicFile appIdleFile = new AtomicFile(getUserFile(userId));
+ try {
+ fos = appIdleFile.startWrite();
+ final BufferedOutputStream bos = new BufferedOutputStream(fos);
+
+ FastXmlSerializer xml = new FastXmlSerializer();
+ xml.setOutput(bos, StandardCharsets.UTF_8.name());
+ xml.startDocument(null, true);
+ xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+
+ xml.startTag(null, TAG_PACKAGES);
+
+ ArrayMap<String,PackageHistory> userHistory = getUserHistoryLocked(userId);
+ final int N = userHistory.size();
+ for (int i = 0; i < N; i++) {
+ String packageName = userHistory.keyAt(i);
+ PackageHistory history = userHistory.valueAt(i);
+ xml.startTag(null, TAG_PACKAGE);
+ xml.attribute(null, ATTR_NAME, packageName);
+ xml.attribute(null, ATTR_ELAPSED_IDLE,
+ Long.toString(history.lastUsedElapsedTime));
+ xml.attribute(null, ATTR_SCREEN_IDLE,
+ Long.toString(history.lastUsedScreenTime));
+ xml.endTag(null, TAG_PACKAGE);
+ }
+
+ xml.endTag(null, TAG_PACKAGES);
+ xml.endDocument();
+ appIdleFile.finishWrite(fos);
+ } catch (Exception e) {
+ appIdleFile.failWrite(fos);
+ Slog.e(TAG, "Error writing app idle file for user " + userId);
+ }
}
public void dump(IndentingPrintWriter idpw, int userId) {
- ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
+ idpw.println("Package idle stats:");
+ idpw.increaseIndent();
+ ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long totalElapsedTime = getElapsedTimeLocked(elapsedRealtime);
+ final long screenOnTime = getScreenOnTimeLocked(elapsedRealtime);
+ if (userHistory == null) return;
+ final int P = userHistory.size();
+ for (int p = 0; p < P; p++) {
+ final String packageName = userHistory.keyAt(p);
+ final PackageHistory packageHistory = userHistory.valueAt(p);
+ idpw.print("package=" + packageName);
+ idpw.print(" lastUsedElapsed=");
+ TimeUtils.formatDuration(totalElapsedTime - packageHistory.lastUsedElapsedTime, idpw);
+ idpw.print(" lastUsedScreenOn=");
+ TimeUtils.formatDuration(screenOnTime - packageHistory.lastUsedScreenTime, idpw);
+ idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
+ idpw.println();
+ }
+ idpw.println();
+ idpw.print("totalElapsedTime=");
+ TimeUtils.formatDuration(getElapsedTimeLocked(elapsedRealtime), idpw);
+ idpw.println();
+ idpw.print("totalScreenOnTime=");
+ TimeUtils.formatDuration(getScreenOnTimeLocked(elapsedRealtime), idpw);
+ idpw.println();
+ idpw.decreaseIndent();
+ }
+
+ public void dumpHistory(IndentingPrintWriter idpw, int userId) {
+ ArrayMap<String, PackageHistory> userHistory = mIdleHistory.get(userId);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (userHistory == null) return;
final int P = userHistory.size();
for (int p = 0; p < P; p++) {
final String packageName = userHistory.keyAt(p);
- final byte[] history = userHistory.valueAt(p);
+ final byte[] history = userHistory.valueAt(p).recent;
for (int i = 0; i < HISTORY_SIZE; i++) {
idpw.print(history[i] == 0 ? '.' : 'A');
}
+ idpw.print(" idle=" + (isIdleLocked(packageName, userId, elapsedRealtime) ? "y" : "n"));
idpw.print(" " + packageName);
idpw.println();
}
}
-} \ No newline at end of file
+}
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 7f379fe34452..f541f70d4334 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -48,7 +48,6 @@ class IntervalStats {
usageStats.mPackageName = getCachedStringRef(packageName);
usageStats.mBeginTimeStamp = beginTime;
usageStats.mEndTimeStamp = endTime;
- usageStats.mBeginIdleTime = 0;
packageStats.put(usageStats.mPackageName, usageStats);
}
return usageStats;
@@ -113,7 +112,6 @@ class IntervalStats {
if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) {
usageStats.mLastTimeUsed = timeStamp;
}
- usageStats.mLastTimeSystemUsed = timeStamp;
usageStats.mEndTimeStamp = timeStamp;
if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
@@ -123,22 +121,6 @@ class IntervalStats {
endTime = timeStamp;
}
- /**
- * Updates the last active time for the package. The timestamp uses a timebase that
- * tracks the device usage time.
- * @param packageName
- * @param timeStamp
- */
- void updateBeginIdleTime(String packageName, long timeStamp) {
- UsageStats usageStats = getOrCreateUsageStats(packageName);
- usageStats.mBeginIdleTime = timeStamp;
- }
-
- void updateSystemLastUsedTime(String packageName, long lastUsedTime) {
- UsageStats usageStats = getOrCreateUsageStats(packageName);
- usageStats.mLastTimeSystemUsed = lastUsedTime;
- }
-
void updateConfigurationStats(Configuration config, long timeStamp) {
if (activeConfiguration != null) {
ConfigurationStats activeStats = configurations.get(activeConfiguration);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7774038740fe..46ad8a10534e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.hardware.display.DisplayManager;
@@ -62,7 +63,6 @@ import android.os.UserManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
-import android.util.AtomicFile;
import android.util.KeyValueListParser;
import android.util.Slog;
import android.util.SparseArray;
@@ -77,12 +77,8 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -106,7 +102,7 @@ public class UsageStatsService extends SystemService implements
private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
- long mAppIdleDurationMillis;
+ long mAppIdleScreenThresholdMillis;
long mCheckIdleIntervalMillis;
long mAppIdleWallclockThresholdMillis;
long mAppIdleParoleIntervalMillis;
@@ -147,11 +143,8 @@ public class UsageStatsService extends SystemService implements
private volatile boolean mPendingOneTimeCheckIdleStates;
- long mScreenOnTime;
- long mLastScreenOnEventRealtime;
-
@GuardedBy("mLock")
- private AppIdleHistory mAppIdleHistory = new AppIdleHistory();
+ private AppIdleHistory mAppIdleHistory;
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
mPackageAccessListeners = new ArrayList<>();
@@ -191,8 +184,7 @@ public class UsageStatsService extends SystemService implements
synchronized (mLock) {
cleanUpRemovedUsersLocked();
- mLastScreenOnEventRealtime = SystemClock.elapsedRealtime();
- mScreenOnTime = readScreenOnTimeLocked();
+ mAppIdleHistory = new AppIdleHistory(SystemClock.elapsedRealtime());
}
mRealTimeSnapshot = SystemClock.elapsedRealtime();
@@ -221,7 +213,7 @@ public class UsageStatsService extends SystemService implements
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
synchronized (mLock) {
- updateDisplayLocked();
+ mAppIdleHistory.updateDisplayLocked(isDisplayOn(), SystemClock.elapsedRealtime());
}
if (mPendingOneTimeCheckIdleStates) {
@@ -232,6 +224,11 @@ public class UsageStatsService extends SystemService implements
}
}
+ private boolean isDisplayOn() {
+ return mDisplayManager
+ .getDisplay(Display.DEFAULT_DISPLAY).getState() == Display.STATE_ON;
+ }
+
private class UserActionsReceiver extends BroadcastReceiver {
@Override
@@ -274,7 +271,8 @@ public class UsageStatsService extends SystemService implements
@Override public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
synchronized (UsageStatsService.this.mLock) {
- updateDisplayLocked();
+ mAppIdleHistory.updateDisplayLocked(isDisplayOn(),
+ SystemClock.elapsedRealtime());
}
}
}
@@ -291,8 +289,25 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public long getAppIdleRollingWindowDurationMillis() {
- return mAppIdleWallclockThresholdMillis * 2;
+ public void onNewUpdate(int userId) {
+ initializeDefaultsForSystemApps(userId);
+ }
+
+ private void initializeDefaultsForSystemApps(int userId) {
+ Slog.d(TAG, "Initializing defaults for system apps on user " + userId);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ List<PackageInfo> packages = getContext().getPackageManager().getInstalledPackagesAsUser(
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ userId);
+ final int packageCount = packages.size();
+ for (int i = 0; i < packageCount; i++) {
+ final PackageInfo pi = packages.get(i);
+ String packageName = pi.packageName;
+ if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
+ mAppIdleHistory.reportUsageLocked(packageName, userId, elapsedRealtime);
+ }
+ }
}
private void cleanUpRemovedUsersLocked() {
@@ -350,7 +365,7 @@ public class UsageStatsService extends SystemService implements
if (timeLeft < 0) {
timeLeft = 0;
}
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft / 10);
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_PAROLE_TIMEOUT, timeLeft);
}
private void postParoleEndTimeout() {
@@ -400,28 +415,27 @@ public class UsageStatsService extends SystemService implements
return;
}
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
for (int i = 0; i < userIds.length; i++) {
final int userId = userIds[i];
List<PackageInfo> packages =
getContext().getPackageManager().getInstalledPackagesAsUser(
- PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_UNINSTALLED_PACKAGES,
+ PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
userId);
synchronized (mLock) {
- final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked();
- UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
- timeNow);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final PackageInfo pi = packages.get(p);
final String packageName = pi.packageName;
final boolean isIdle = isAppIdleFiltered(packageName,
UserHandle.getAppId(pi.applicationInfo.uid),
- userId, service, timeNow, screenOnTime);
+ userId, elapsedRealtime);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
userId, isIdle ? 1 : 0, packageName));
- mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
+ if (isIdle) {
+ mAppIdleHistory.setIdle(packageName, userId, elapsedRealtime);
+ }
}
}
}
@@ -458,62 +472,6 @@ public class UsageStatsService extends SystemService implements
}
}
- void updateDisplayLocked() {
- boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
- == Display.STATE_ON;
-
- if (screenOn == mScreenOn) return;
-
- mScreenOn = screenOn;
- long now = SystemClock.elapsedRealtime();
- if (mScreenOn) {
- mLastScreenOnEventRealtime = now;
- } else {
- mScreenOnTime += now - mLastScreenOnEventRealtime;
- writeScreenOnTimeLocked(mScreenOnTime);
- }
- }
-
- long getScreenOnTimeLocked() {
- long screenOnTime = mScreenOnTime;
- if (mScreenOn) {
- screenOnTime += SystemClock.elapsedRealtime() - mLastScreenOnEventRealtime;
- }
- return screenOnTime;
- }
-
- private File getScreenOnTimeFile() {
- return new File(mUsageStatsDir, UserHandle.USER_SYSTEM + "/screen_on_time");
- }
-
- private long readScreenOnTimeLocked() {
- long screenOnTime = 0;
- File screenOnTimeFile = getScreenOnTimeFile();
- if (screenOnTimeFile.exists()) {
- try {
- BufferedReader reader = new BufferedReader(new FileReader(screenOnTimeFile));
- screenOnTime = Long.parseLong(reader.readLine());
- reader.close();
- } catch (IOException | NumberFormatException e) {
- }
- } else {
- writeScreenOnTimeLocked(screenOnTime);
- }
- return screenOnTime;
- }
-
- private void writeScreenOnTimeLocked(long screenOnTime) {
- AtomicFile screenOnTimeFile = new AtomicFile(getScreenOnTimeFile());
- FileOutputStream fos = null;
- try {
- fos = screenOnTimeFile.startWrite();
- fos.write(Long.toString(screenOnTime).getBytes());
- screenOnTimeFile.finishWrite(fos);
- } catch (IOException ioe) {
- screenOnTimeFile.failWrite(fos);
- }
- }
-
void onDeviceIdleModeChanged() {
final boolean deviceIdle = mPowerManager.isDeviceIdleMode();
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
@@ -549,7 +507,7 @@ public class UsageStatsService extends SystemService implements
if (service == null) {
service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
- service.init(currentTimeMillis, getScreenOnTimeLocked());
+ service.init(currentTimeMillis);
mUserState.put(userId, service);
}
return service;
@@ -569,8 +527,7 @@ public class UsageStatsService extends SystemService implements
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
final UserUsageStatsService service = mUserState.valueAt(i);
- service.onTimeChanged(expectedSystemTime, actualSystemTime, getScreenOnTimeLocked(),
- false);
+ service.onTimeChanged(expectedSystemTime, actualSystemTime);
}
mRealTimeSnapshot = actualRealtime;
mSystemTimeSnapshot = actualSystemTime;
@@ -602,26 +559,26 @@ public class UsageStatsService extends SystemService implements
void reportEvent(UsageEvents.Event event, int userId) {
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
convertToSystemTimeLocked(event);
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- final long beginIdleTime = service.getBeginIdleTime(event.mPackage);
- final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
- final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
- lastUsedTime, screenOnTime, timeNow);
- service.reportEvent(event, screenOnTime);
+ // TODO: Ideally this should call isAppIdleFiltered() to avoid calling back
+ // about apps that are on some kind of whitelist anyway.
+ final boolean previouslyIdle = mAppIdleHistory.isIdleLocked(
+ event.mPackage, userId, elapsedRealtime);
+ service.reportEvent(event);
// Inform listeners if necessary
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.MOVE_TO_BACKGROUND
|| event.mEventType == Event.SYSTEM_INTERACTION
|| event.mEventType == Event.USER_INTERACTION)) {
+ mAppIdleHistory.reportUsageLocked(event.mPackage, userId, elapsedRealtime);
if (previouslyIdle) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
notifyBatteryStats(event.mPackage, userId, false);
- mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
}
}
}
@@ -655,28 +612,23 @@ public class UsageStatsService extends SystemService implements
* the threshold for idle.
*/
void forceIdleState(String packageName, int userId, boolean idle) {
+ final int appId = getAppId(packageName);
+ if (appId < 0) return;
synchronized (mLock) {
- final long timeNow = checkAndGetTimeLocked();
- final long screenOnTime = getScreenOnTimeLocked();
- final long deviceUsageTime = screenOnTime - (idle ? mAppIdleDurationMillis : 0) - 5000;
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
- final UserUsageStatsService service =
- getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- final long beginIdleTime = service.getBeginIdleTime(packageName);
- final long lastUsedTime = service.getSystemLastUsedTime(packageName);
- final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
- lastUsedTime, screenOnTime, timeNow);
- service.setBeginIdleTime(packageName, deviceUsageTime);
- service.setSystemLastUsedTime(packageName,
- timeNow - (idle ? mAppIdleWallclockThresholdMillis : 0) - 5000);
+ final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
+ mAppIdleHistory.setIdleLocked(packageName, userId, idle, elapsedRealtime);
+ final boolean stillIdle = isAppIdleFiltered(packageName, appId,
+ userId, elapsedRealtime);
// Inform listeners if necessary
- if (previouslyIdle != idle) {
+ if (previouslyIdle != stillIdle) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
- /* idle = */ idle ? 1 : 0, packageName));
- if (!idle) {
+ /* idle = */ stillIdle ? 1 : 0, packageName));
+ if (!stillIdle) {
notifyBatteryStats(packageName, userId, idle);
}
- mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
}
}
}
@@ -693,10 +645,11 @@ public class UsageStatsService extends SystemService implements
/**
* Called by the Binder stub.
*/
- void removeUser(int userId) {
+ void onUserRemoved(int userId) {
synchronized (mLock) {
Slog.i(TAG, "Removing user " + userId + " and all data.");
mUserState.remove(userId);
+ mAppIdleHistory.onUserRemoved(userId);
cleanUpRemovedUsersLocked();
}
}
@@ -750,29 +703,12 @@ public class UsageStatsService extends SystemService implements
}
}
- private boolean isAppIdleUnfiltered(String packageName, UserUsageStatsService userService,
- long timeNow, long screenOnTime) {
+ private boolean isAppIdleUnfiltered(String packageName, int userId, long elapsedRealtime) {
synchronized (mLock) {
- long beginIdleTime = userService.getBeginIdleTime(packageName);
- long lastUsedTime = userService.getSystemLastUsedTime(packageName);
- return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime,
- timeNow);
+ return mAppIdleHistory.isIdleLocked(packageName, userId, elapsedRealtime);
}
}
- /**
- * @param beginIdleTime when the app was last used in device usage timebase
- * @param lastUsedTime wallclock time of when the app was last used
- * @param screenOnTime screen-on timebase time
- * @param currentTime current time in device usage timebase
- * @return whether it's been used far enough in the past to be considered inactive
- */
- boolean hasPassedIdleTimeoutLocked(long beginIdleTime, long lastUsedTime,
- long screenOnTime, long currentTime) {
- return (beginIdleTime <= screenOnTime - mAppIdleDurationMillis)
- && (lastUsedTime <= currentTime - mAppIdleWallclockThresholdMillis);
- }
-
void addListener(AppIdleStateChangeListener listener) {
synchronized (mLock) {
if (!mPackageAccessListeners.contains(listener)) {
@@ -787,32 +723,22 @@ public class UsageStatsService extends SystemService implements
}
}
- boolean isAppIdleFilteredOrParoled(String packageName, int userId, long timeNow) {
- if (mAppIdleParoled) {
- return false;
- }
+ int getAppId(String packageName) {
try {
ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(packageName,
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
- return isAppIdleFiltered(packageName, ai.uid, userId, timeNow);
- } catch (PackageManager.NameNotFoundException e) {
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS);
+ return ai.uid;
+ } catch (NameNotFoundException re) {
+ return -1;
}
- return false;
}
- boolean isAppIdleFiltered(String packageName, int uidForAppId, int userId, long timeNow) {
- final UserUsageStatsService userService;
- final long screenOnTime;
- synchronized (mLock) {
- if (timeNow == -1) {
- timeNow = checkAndGetTimeLocked();
- }
- userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked();
+ boolean isAppIdleFilteredOrParoled(String packageName, int userId, long elapsedRealtime) {
+ if (mAppIdleParoled) {
+ return false;
}
- return isAppIdleFiltered(packageName, UserHandle.getAppId(uidForAppId), userId,
- userService, timeNow, screenOnTime);
+ return isAppIdleFiltered(packageName, getAppId(packageName), userId, elapsedRealtime);
}
/**
@@ -822,7 +748,7 @@ public class UsageStatsService extends SystemService implements
* Called by interface impls.
*/
private boolean isAppIdleFiltered(String packageName, int appId, int userId,
- UserUsageStatsService userService, long timeNow, long screenOnTime) {
+ long elapsedRealtime) {
if (packageName == null) return false;
// If not enabled at all, of course nobody is ever idle.
if (!mAppIdleEnabled) {
@@ -864,7 +790,7 @@ public class UsageStatsService extends SystemService implements
return false;
}
- return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime);
+ return isAppIdleUnfiltered(packageName, userId, elapsedRealtime);
}
int[] getIdleUidsForUser(int userId) {
@@ -872,14 +798,7 @@ public class UsageStatsService extends SystemService implements
return new int[0];
}
- final long timeNow;
- final UserUsageStatsService userService;
- final long screenOnTime;
- synchronized (mLock) {
- timeNow = checkAndGetTimeLocked();
- userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- screenOnTime = getScreenOnTimeLocked();
- }
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
List<ApplicationInfo> apps;
try {
@@ -899,12 +818,12 @@ public class UsageStatsService extends SystemService implements
// Now resolve all app state. Iterating over all apps, keeping track of how many
// we find for each uid and how many of those are idle.
- for (int i = apps.size()-1; i >= 0; i--) {
+ for (int i = apps.size() - 1; i >= 0; i--) {
ApplicationInfo ai = apps.get(i);
// Check whether this app is idle.
boolean idle = isAppIdleFiltered(ai.packageName, UserHandle.getAppId(ai.uid),
- userId, userService, timeNow, screenOnTime);
+ userId, elapsedRealtime);
int index = uidStates.indexOfKey(ai.uid);
if (index < 0) {
@@ -990,8 +909,11 @@ public class UsageStatsService extends SystemService implements
for (int i = 0; i < userCount; i++) {
UserUsageStatsService service = mUserState.valueAt(i);
service.persistActiveStats();
+ mAppIdleHistory.writeAppIdleTimesLocked(mUserState.keyAt(i));
}
-
+ // Persist elapsed time periodically, in case screen doesn't get toggled
+ // until the next boot
+ mAppIdleHistory.writeElapsedTimeLocked();
mHandler.removeMessages(MSG_FLUSH_TO_DISK);
}
@@ -1000,7 +922,6 @@ public class UsageStatsService extends SystemService implements
*/
void dump(String[] args, PrintWriter pw) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked();
IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
ArraySet<String> argSet = new ArraySet<>();
argSet.addAll(Arrays.asList(args));
@@ -1011,27 +932,28 @@ public class UsageStatsService extends SystemService implements
idpw.println();
idpw.increaseIndent();
if (argSet.contains("--checkin")) {
- mUserState.valueAt(i).checkin(idpw, screenOnTime);
+ mUserState.valueAt(i).checkin(idpw);
} else {
- mUserState.valueAt(i).dump(idpw, screenOnTime);
+ mUserState.valueAt(i).dump(idpw);
idpw.println();
- if (args.length > 0 && "history".equals(args[0])) {
- mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
+ if (args.length > 0) {
+ if ("history".equals(args[0])) {
+ mAppIdleHistory.dumpHistory(idpw, mUserState.keyAt(i));
+ } else if ("flush".equals(args[0])) {
+ UsageStatsService.this.flushToDiskLocked();
+ pw.println("Flushed stats to disk");
+ }
}
}
+ mAppIdleHistory.dump(idpw, mUserState.keyAt(i));
idpw.decreaseIndent();
}
- pw.print("Screen On Timebase: ");
- pw.print(screenOnTime);
- pw.print(" (");
- TimeUtils.formatDuration(screenOnTime, pw);
- pw.println(")");
pw.println();
pw.println("Settings:");
pw.print(" mAppIdleDurationMillis=");
- TimeUtils.formatDuration(mAppIdleDurationMillis, pw);
+ TimeUtils.formatDuration(mAppIdleScreenThresholdMillis, pw);
pw.println();
pw.print(" mAppIdleWallclockThresholdMillis=");
@@ -1057,11 +979,6 @@ public class UsageStatsService extends SystemService implements
pw.print("mLastAppIdleParoledTime=");
TimeUtils.formatDuration(mLastAppIdleParoledTime, pw);
pw.println();
- pw.print("mScreenOnTime="); TimeUtils.formatDuration(mScreenOnTime, pw);
- pw.println();
- pw.print("mLastScreenOnEventRealtime=");
- TimeUtils.formatDuration(mLastScreenOnEventRealtime, pw);
- pw.println();
}
}
@@ -1082,7 +999,7 @@ public class UsageStatsService extends SystemService implements
break;
case MSG_REMOVE_USER:
- removeUser(msg.arg1);
+ onUserRemoved(msg.arg1);
break;
case MSG_INFORM_LISTENERS:
@@ -1179,13 +1096,13 @@ public class UsageStatsService extends SystemService implements
}
// Default: 12 hours of screen-on time sans dream-time
- mAppIdleDurationMillis = mParser.getLong(KEY_IDLE_DURATION,
+ mAppIdleScreenThresholdMillis = mParser.getLong(KEY_IDLE_DURATION,
COMPRESS_TIME ? ONE_MINUTE * 4 : 12 * 60 * ONE_MINUTE);
mAppIdleWallclockThresholdMillis = mParser.getLong(KEY_WALLCLOCK_THRESHOLD,
COMPRESS_TIME ? ONE_MINUTE * 8 : 2L * 24 * 60 * ONE_MINUTE); // 2 days
- mCheckIdleIntervalMillis = Math.min(mAppIdleDurationMillis / 4,
+ mCheckIdleIntervalMillis = Math.min(mAppIdleScreenThresholdMillis / 4,
COMPRESS_TIME ? ONE_MINUTE : 8 * 60 * ONE_MINUTE); // 8 hours
// Default: 24 hours between paroles
@@ -1194,6 +1111,8 @@ public class UsageStatsService extends SystemService implements
mAppIdleParoleDurationMillis = mParser.getLong(KEY_PAROLE_DURATION,
COMPRESS_TIME ? ONE_MINUTE : 10 * ONE_MINUTE); // 10 minutes
+ mAppIdleHistory.setThresholds(mAppIdleWallclockThresholdMillis,
+ mAppIdleScreenThresholdMillis);
}
}
}
@@ -1284,7 +1203,8 @@ public class UsageStatsService extends SystemService implements
}
final long token = Binder.clearCallingIdentity();
try {
- return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId, -1);
+ return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId,
+ SystemClock.elapsedRealtime());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1304,11 +1224,9 @@ public class UsageStatsService extends SystemService implements
"No permission to change app idle state");
final long token = Binder.clearCallingIdentity();
try {
- PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
- if (pi == null) return;
+ final int appId = getAppId(packageName);
+ if (appId < 0) return;
UsageStatsService.this.setAppIdle(packageName, idle, userId);
- } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1335,8 +1253,6 @@ public class UsageStatsService extends SystemService implements
}
UsageStatsService.this.dump(args, pw);
}
-
-
}
/**
@@ -1411,7 +1327,8 @@ public class UsageStatsService extends SystemService implements
@Override
public boolean isAppIdle(String packageName, int uidForAppId, int userId) {
- return UsageStatsService.this.isAppIdleFiltered(packageName, uidForAppId, userId, -1);
+ return UsageStatsService.this.isAppIdleFiltered(packageName, uidForAppId, userId,
+ SystemClock.elapsedRealtime());
}
@Override
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index f2ca3a4047fa..c95ff2364f2c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -26,7 +26,6 @@ import android.app.usage.TimeSparseArray;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.content.res.Configuration;
-import android.text.TextUtils;
import java.io.IOException;
import java.net.ProtocolException;
@@ -55,13 +54,11 @@ final class UsageStatsXmlV1 {
// Time attributes stored as an offset of the beginTime.
private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
- private static final String LAST_TIME_ACTIVE_SYSTEM_ATTR = "lastTimeActiveSystem";
- private static final String BEGIN_IDLE_TIME_ATTR = "beginIdleTime";
private static final String END_TIME_ATTR = "endTime";
private static final String TIME_ATTR = "time";
private static void loadUsageStats(XmlPullParser parser, IntervalStats statsOut)
- throws XmlPullParserException, IOException {
+ throws IOException {
final String pkg = parser.getAttributeValue(null, PACKAGE_ATTR);
if (pkg == null) {
throw new ProtocolException("no " + PACKAGE_ATTR + " attribute present");
@@ -72,20 +69,6 @@ final class UsageStatsXmlV1 {
// Apply the offset to the beginTime to find the absolute time.
stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
parser, LAST_TIME_ACTIVE_ATTR);
-
- final String lastTimeUsedSystem = parser.getAttributeValue(null,
- LAST_TIME_ACTIVE_SYSTEM_ATTR);
- if (TextUtils.isEmpty(lastTimeUsedSystem)) {
- // If the field isn't present, use the old one.
- stats.mLastTimeSystemUsed = stats.mLastTimeUsed;
- } else {
- stats.mLastTimeSystemUsed = statsOut.beginTime + Long.parseLong(lastTimeUsedSystem);
- }
-
- final String beginIdleTime = parser.getAttributeValue(null, BEGIN_IDLE_TIME_ATTR);
- if (!TextUtils.isEmpty(beginIdleTime)) {
- stats.mBeginIdleTime = Long.parseLong(beginIdleTime);
- }
stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
}
@@ -141,13 +124,10 @@ final class UsageStatsXmlV1 {
// Write the time offset.
XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
usageStats.mLastTimeUsed - stats.beginTime);
- XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_SYSTEM_ATTR,
- usageStats.mLastTimeSystemUsed - stats.beginTime);
XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
XmlUtils.writeIntAttribute(xml, LAST_EVENT_ATTR, usageStats.mLastEvent);
- XmlUtils.writeLongAttribute(xml, BEGIN_IDLE_TIME_ATTR, usageStats.mBeginIdleTime);
xml.endTag(null, PACKAGE_TAG);
}
@@ -255,7 +235,6 @@ final class UsageStatsXmlV1 {
}
xml.endTag(null, PACKAGES_TAG);
-
xml.startTag(null, CONFIGURATIONS_TAG);
final int configCount = stats.configurations.size();
for (int i = 0; i < configCount; i++) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index f2045d31f69c..7d003f3bf61a 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -59,7 +59,6 @@ class UserUsageStatsService {
private final Context mContext;
private final UsageStatsDatabase mDatabase;
private final IntervalStats[] mCurrentStats;
- private IntervalStats mAppIdleRollingWindow;
private boolean mStatsChanged = false;
private final UnixCalendar mDailyExpiryDate;
private final StatsUpdatedListener mListener;
@@ -74,7 +73,11 @@ class UserUsageStatsService {
interface StatsUpdatedListener {
void onStatsUpdated();
void onStatsReloaded();
- long getAppIdleRollingWindowDurationMillis();
+ /**
+ * Callback that a system update was detected
+ * @param mUserId user that needs to be initialized
+ */
+ void onNewUpdate(int mUserId);
}
UserUsageStatsService(Context context, int userId, File usageStatsDir,
@@ -88,7 +91,7 @@ class UserUsageStatsService {
mUserId = userId;
}
- void init(final long currentTimeMillis, final long deviceUsageTime) {
+ void init(final long currentTimeMillis) {
mDatabase.init(currentTimeMillis);
int nullCount = 0;
@@ -112,7 +115,7 @@ class UserUsageStatsService {
// By calling loadActiveStats, we will
// generate new stats for each bucket.
- loadActiveStats(currentTimeMillis, /*resetBeginIdleTime=*/ false);
+ loadActiveStats(currentTimeMillis);
} else {
// Set up the expiry date to be one day from the latest daily stat.
// This may actually be today and we will rollover on the first event
@@ -136,54 +139,18 @@ class UserUsageStatsService {
stat.updateConfigurationStats(null, stat.lastTimeSaved);
}
- refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
-
if (mDatabase.isNewUpdate()) {
- initializeDefaultsForApps(currentTimeMillis, deviceUsageTime,
- mDatabase.isFirstUpdate());
+ notifyNewUpdate();
}
}
- /**
- * If any of the apps don't have a last-used entry, add one now.
- * @param currentTimeMillis the current time
- * @param firstUpdate if it is the first update, touch all installed apps, otherwise only
- * touch the system apps
- */
- private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime,
- boolean firstUpdate) {
- PackageManager pm = mContext.getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackagesAsUser(0, mUserId);
- final int packageCount = packages.size();
- for (int i = 0; i < packageCount; i++) {
- final PackageInfo pi = packages.get(i);
- String packageName = pi.packageName;
- if (pi.applicationInfo != null && (firstUpdate || pi.applicationInfo.isSystemApp())
- && getBeginIdleTime(packageName) == -1) {
- for (IntervalStats stats : mCurrentStats) {
- stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
- stats.updateBeginIdleTime(packageName, deviceUsageTime);
- }
-
- mAppIdleRollingWindow.update(packageName, currentTimeMillis,
- Event.SYSTEM_INTERACTION);
- mAppIdleRollingWindow.updateBeginIdleTime(packageName, deviceUsageTime);
- mStatsChanged = true;
- }
- }
- // Persist the new OTA-related access stats.
- persistActiveStats();
- }
-
- void onTimeChanged(long oldTime, long newTime, long deviceUsageTime,
- boolean resetBeginIdleTime) {
+ void onTimeChanged(long oldTime, long newTime) {
persistActiveStats();
mDatabase.onTimeChanged(newTime - oldTime);
- loadActiveStats(newTime, resetBeginIdleTime);
- refreshAppIdleRollingWindow(newTime, deviceUsageTime);
+ loadActiveStats(newTime);
}
- void reportEvent(UsageEvents.Event event, long deviceUsageTime) {
+ void reportEvent(UsageEvents.Event event) {
if (DEBUG) {
Slog.d(TAG, mLogPrefix + "Got usage event for " + event.mPackage
+ "[" + event.mTimeStamp + "]: "
@@ -192,7 +159,7 @@ class UserUsageStatsService {
if (event.mTimeStamp >= mDailyExpiryDate.getTimeInMillis()) {
// Need to rollover
- rolloverStats(event.mTimeStamp, deviceUsageTime);
+ rolloverStats(event.mTimeStamp);
}
final IntervalStats currentDailyStats = mCurrentStats[UsageStatsManager.INTERVAL_DAILY];
@@ -218,35 +185,9 @@ class UserUsageStatsService {
stats.updateConfigurationStats(newFullConfig, event.mTimeStamp);
} else {
stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
- stats.updateBeginIdleTime(event.mPackage, deviceUsageTime);
}
}
- if (event.mEventType != Event.CONFIGURATION_CHANGE) {
- mAppIdleRollingWindow.update(event.mPackage, event.mTimeStamp, event.mEventType);
- mAppIdleRollingWindow.updateBeginIdleTime(event.mPackage, deviceUsageTime);
- }
-
- notifyStatsChanged();
- }
-
- /**
- * Sets the beginIdleTime for each of the intervals.
- * @param beginIdleTime
- */
- void setBeginIdleTime(String packageName, long beginIdleTime) {
- for (IntervalStats stats : mCurrentStats) {
- stats.updateBeginIdleTime(packageName, beginIdleTime);
- }
- mAppIdleRollingWindow.updateBeginIdleTime(packageName, beginIdleTime);
- notifyStatsChanged();
- }
-
- void setSystemLastUsedTime(String packageName, long lastUsedTime) {
- for (IntervalStats stats : mCurrentStats) {
- stats.updateSystemLastUsedTime(packageName, lastUsedTime);
- }
- mAppIdleRollingWindow.updateSystemLastUsedTime(packageName, lastUsedTime);
notifyStatsChanged();
}
@@ -404,24 +345,6 @@ class UserUsageStatsService {
return new UsageEvents(results, table);
}
- long getBeginIdleTime(String packageName) {
- UsageStats packageUsage;
- if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
- return -1;
- } else {
- return packageUsage.getBeginIdleTime();
- }
- }
-
- long getSystemLastUsedTime(String packageName) {
- UsageStats packageUsage;
- if ((packageUsage = mAppIdleRollingWindow.packageStats.get(packageName)) == null) {
- return -1;
- } else {
- return packageUsage.getLastTimeSystemUsed();
- }
- }
-
void persistActiveStats() {
if (mStatsChanged) {
Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
@@ -436,7 +359,7 @@ class UserUsageStatsService {
}
}
- private void rolloverStats(final long currentTimeMillis, final long deviceUsageTime) {
+ private void rolloverStats(final long currentTimeMillis) {
final long startTime = SystemClock.elapsedRealtime();
Slog.i(TAG, mLogPrefix + "Rolling over usage stats");
@@ -463,7 +386,7 @@ class UserUsageStatsService {
persistActiveStats();
mDatabase.prune(currentTimeMillis);
- loadActiveStats(currentTimeMillis, /*resetBeginIdleTime=*/ false);
+ loadActiveStats(currentTimeMillis);
final int continueCount = continuePreviousDay.size();
for (int i = 0; i < continueCount; i++) {
@@ -477,8 +400,6 @@ class UserUsageStatsService {
}
persistActiveStats();
- refreshAppIdleRollingWindow(currentTimeMillis, deviceUsageTime);
-
final long totalTime = SystemClock.elapsedRealtime() - startTime;
Slog.i(TAG, mLogPrefix + "Rolling over usage stats complete. Took " + totalTime
+ " milliseconds");
@@ -491,7 +412,11 @@ class UserUsageStatsService {
}
}
- private void loadActiveStats(final long currentTimeMillis, boolean resetBeginIdleTime) {
+ private void notifyNewUpdate() {
+ mListener.onNewUpdate(mUserId);
+ }
+
+ private void loadActiveStats(final long currentTimeMillis) {
for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
@@ -514,12 +439,6 @@ class UserUsageStatsService {
mCurrentStats[intervalType].beginTime = currentTimeMillis;
mCurrentStats[intervalType].endTime = currentTimeMillis + 1;
}
-
- if (resetBeginIdleTime) {
- for (UsageStats usageStats : mCurrentStats[intervalType].packageStats.values()) {
- usageStats.mBeginIdleTime = 0;
- }
- }
}
mStatsChanged = false;
@@ -538,96 +457,28 @@ class UserUsageStatsService {
mDailyExpiryDate.getTimeInMillis() + ")");
}
- private static void mergePackageStats(IntervalStats dst, IntervalStats src,
- final long deviceUsageTime) {
- dst.endTime = Math.max(dst.endTime, src.endTime);
-
- final int srcPackageCount = src.packageStats.size();
- for (int i = 0; i < srcPackageCount; i++) {
- final String packageName = src.packageStats.keyAt(i);
- final UsageStats srcStats = src.packageStats.valueAt(i);
- UsageStats dstStats = dst.packageStats.get(packageName);
- if (dstStats == null) {
- dstStats = new UsageStats(srcStats);
- dst.packageStats.put(packageName, dstStats);
- } else {
- dstStats.add(src.packageStats.valueAt(i));
- }
-
- // App idle times can not begin in the future. This happens if we had a time change.
- if (dstStats.mBeginIdleTime > deviceUsageTime) {
- dstStats.mBeginIdleTime = deviceUsageTime;
- }
- }
- }
-
- /**
- * App idle operates on a rolling window of time. When we roll over time, we end up with a
- * period of time where in-memory stats are empty and we don't hit the disk for older stats
- * for performance reasons. Suddenly all apps will become idle.
- *
- * Instead, at times we do a deep query to find all the apps that have run in the past few
- * days and keep the cached data up to date.
- *
- * @param currentTimeMillis
- */
- void refreshAppIdleRollingWindow(final long currentTimeMillis, final long deviceUsageTime) {
- // Start the rolling window for AppIdle requests.
- final long startRangeMillis = currentTimeMillis -
- mListener.getAppIdleRollingWindowDurationMillis();
-
- List<IntervalStats> stats = mDatabase.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
- startRangeMillis, currentTimeMillis, new StatCombiner<IntervalStats>() {
- @Override
- public void combine(IntervalStats stats, boolean mutable,
- List<IntervalStats> accumulatedResult) {
- IntervalStats accum;
- if (accumulatedResult.isEmpty()) {
- accum = new IntervalStats();
- accum.beginTime = stats.beginTime;
- accumulatedResult.add(accum);
- } else {
- accum = accumulatedResult.get(0);
- }
-
- mergePackageStats(accum, stats, deviceUsageTime);
- }
- });
-
- if (stats == null || stats.isEmpty()) {
- mAppIdleRollingWindow = new IntervalStats();
- mergePackageStats(mAppIdleRollingWindow,
- mCurrentStats[UsageStatsManager.INTERVAL_YEARLY], deviceUsageTime);
- } else {
- mAppIdleRollingWindow = stats.get(0);
- }
- }
-
//
// -- DUMP related methods --
//
- void checkin(final IndentingPrintWriter pw, final long screenOnTime) {
+ void checkin(final IndentingPrintWriter pw) {
mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
@Override
public boolean checkin(IntervalStats stats) {
- printIntervalStats(pw, stats, screenOnTime, false);
+ printIntervalStats(pw, stats, false);
return true;
}
});
}
- void dump(IndentingPrintWriter pw, final long screenOnTime) {
+ void dump(IndentingPrintWriter pw) {
// This is not a check-in, only dump in-memory stats.
for (int interval = 0; interval < mCurrentStats.length; interval++) {
pw.print("In-memory ");
pw.print(intervalToString(interval));
pw.println(" stats");
- printIntervalStats(pw, mCurrentStats[interval], screenOnTime, true);
+ printIntervalStats(pw, mCurrentStats[interval], true);
}
-
- pw.println("AppIdleRollingWindow cache");
- printIntervalStats(pw, mAppIdleRollingWindow, screenOnTime, true);
}
private String formatDateTime(long dateTime, boolean pretty) {
@@ -644,7 +495,7 @@ class UserUsageStatsService {
return Long.toString(elapsedTime);
}
- void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, long screenOnTime,
+ void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats,
boolean prettyDates) {
if (prettyDates) {
pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
@@ -665,10 +516,6 @@ class UserUsageStatsService {
pw.printPair("totalTime",
formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
- pw.printPair("lastTimeSystem",
- formatDateTime(usageStats.mLastTimeSystemUsed, prettyDates));
- pw.printPair("inactiveTime",
- formatElapsedTime(screenOnTime - usageStats.mBeginIdleTime, prettyDates));
pw.println();
}
pw.decreaseIndent();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4368b81b7b06..3ad7d34f6ff1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -591,6 +591,14 @@ public class CarrierConfigManager {
@SystemApi
public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
+ /**
+ * The duration in seconds that platform call and message blocking is disabled after the user
+ * contacts emergency services. Platform considers values in the range 0 to 604800 (one week) as
+ * valid. See {@link android.provider.BlockedNumberContract#isBlocked(Context, String)}).
+ */
+ public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT =
+ "duration_blocking_disabled_after_emergency_int";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -660,6 +668,7 @@ public class CarrierConfigManager {
"max_retries=3, 5000, 5000, 5000");
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
+ sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index d1d6e0dcdece..6229ed921bcc 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -25,6 +25,7 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Typeface;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DisplayMetrics;
@@ -338,7 +339,7 @@ public class SubscriptionInfo implements Parcelable {
public static String givePrintableIccid(String iccId) {
String iccIdToPrint = null;
if (iccId != null) {
- if (iccId.length() > 9) {
+ if (iccId.length() > 9 && !Build.IS_DEBUGGABLE) {
iccIdToPrint = iccId.substring(0, 9) + "XXXXXXXXXXX";
} else {
iccIdToPrint = iccId;
diff --git a/telephony/java/com/android/ims/ImsCallForwardInfo.java b/telephony/java/com/android/ims/ImsCallForwardInfo.java
index 3f8fd19a16ce..eeee0fc938bc 100644
--- a/telephony/java/com/android/ims/ImsCallForwardInfo.java
+++ b/telephony/java/com/android/ims/ImsCallForwardInfo.java
@@ -31,6 +31,8 @@ public class ImsCallForwardInfo implements Parcelable {
public int mStatus;
// 0x91: International, 0x81: Unknown
public int mToA;
+ // Service class
+ public int mServiceClass;
// Number (it will not include the "sip" or "tel" URI scheme)
public String mNumber;
// No reply timer for CF
@@ -55,13 +57,16 @@ public class ImsCallForwardInfo implements Parcelable {
out.writeInt(mToA);
out.writeString(mNumber);
out.writeInt(mTimeSeconds);
+ out.writeInt(mServiceClass);
}
@Override
public String toString() {
return super.toString() + ", Condition: " + mCondition
+ ", Status: " + ((mStatus == 0) ? "disabled" : "enabled")
- + ", ToA: " + mToA + ", Number=" + mNumber
+ + ", ToA: " + mToA
+ + ", Service Class: " + mServiceClass
+ + ", Number=" + mNumber
+ ", Time (seconds): " + mTimeSeconds;
}
@@ -71,6 +76,7 @@ public class ImsCallForwardInfo implements Parcelable {
mToA = in.readInt();
mNumber = in.readString();
mTimeSeconds = in.readInt();
+ mServiceClass = in.readInt();
}
public static final Creator<ImsCallForwardInfo> CREATOR =
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 2769a2b27968..c909c6dc518e 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -84,6 +84,8 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147;
// IMS call is already terminated (in TERMINATED state)
public static final int CODE_LOCAL_CALL_TERMINATED = 148;
+ // Handover not feasible
+ public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149;
/**
* TIMEOUT (IMS -> Telephony)
@@ -153,6 +155,9 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_SIP_USER_REJECTED = 361;
// Others
public static final int CODE_SIP_GLOBAL_ERROR = 362;
+ // Emergency failure
+ public static final int CODE_EMERGENCY_TEMP_FAILURE = 363;
+ public static final int CODE_EMERGENCY_PERM_FAILURE = 364;
/**
* MEDIA (IMS -> Telephony)
@@ -236,6 +241,14 @@ public class ImsReasonInfo implements Parcelable {
public static final int CODE_ANSWERED_ELSEWHERE = 1014;
/**
+ * Supplementary services (HOLD/RESUME) failure error codes.
+ * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+ */
+ public static final int CODE_SUPP_SVC_FAILED = 1201;
+ public static final int CODE_SUPP_SVC_CANCELLED = 1202;
+ public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/ImsStreamMediaProfile.java b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
index 5a99212ae6f4..216cef59f301 100644
--- a/telephony/java/com/android/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
@@ -51,6 +51,16 @@ public class ImsStreamMediaProfile implements Parcelable {
public static final int AUDIO_QUALITY_GSM_EFR = 8;
public static final int AUDIO_QUALITY_GSM_FR = 9;
public static final int AUDIO_QUALITY_GSM_HR = 10;
+ public static final int AUDIO_QUALITY_G711U = 11;
+ public static final int AUDIO_QUALITY_G723 = 12;
+ public static final int AUDIO_QUALITY_G711A = 13;
+ public static final int AUDIO_QUALITY_G722 = 14;
+ public static final int AUDIO_QUALITY_G711AB = 15;
+ public static final int AUDIO_QUALITY_G729 = 16;
+ public static final int AUDIO_QUALITY_EVS_NB = 17;
+ public static final int AUDIO_QUALITY_EVS_WB = 18;
+ public static final int AUDIO_QUALITY_EVS_SWB = 19;
+ public static final int AUDIO_QUALITY_EVS_FB = 20;
/**
* Video information
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index b028ce61f821..de7b9c268c99 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -356,6 +356,15 @@
</activity>
<activity
+ android:name="MovingSurfaceViewActivity"
+ android:label="SurfaceView/Animated Movement">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="GLTextureViewActivity"
android:label="TextureView/OpenGL">
<intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
new file mode 100644
index 000000000000..cd15ef156a5c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MovingSurfaceViewActivity.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.SurfaceHolder;
+import android.view.SurfaceHolder.Callback;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+
+public class MovingSurfaceViewActivity extends Activity implements Callback {
+ static final String TAG = "MovingSurfaceView";
+ SurfaceView mSurfaceView;
+ ObjectAnimator mAnimator;
+
+ class MySurfaceView extends SurfaceView {
+ boolean mSlowToggled;
+
+ public MySurfaceView(Context context) {
+ super(context);
+ setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mSlowToggled = !mSlowToggled;
+ Log.d(TAG, "SLOW MODE: " + mSlowToggled);
+ invalidate();
+ }
+ });
+ setWillNotDraw(false);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ super.draw(canvas);
+ if (mSlowToggled) {
+ try {
+ Thread.sleep(16);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ public void setMyTranslationY(float ty) {
+ setTranslationY(ty);
+ if (mSlowToggled) {
+ invalidate();
+ }
+ }
+
+ public float getMyTranslationY() {
+ return getTranslationY();
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this);
+
+ mSurfaceView = new MySurfaceView(this);
+ mSurfaceView.getHolder().addCallback(this);
+
+ final float density = getResources().getDisplayMetrics().density;
+ int size = (int) (200 * density);
+
+ content.addView(mSurfaceView, new FrameLayout.LayoutParams(
+ size, size, Gravity.CENTER));
+ mAnimator = ObjectAnimator.ofFloat(mSurfaceView, "myTranslationY",
+ 0, size);
+ mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+ mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+ mAnimator.setDuration(200);
+ mAnimator.setInterpolator(new LinearInterpolator());
+ setContentView(content);
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAnimator.start();
+ }
+
+ @Override
+ protected void onPause() {
+ mAnimator.pause();
+ super.onPause();
+ }
+}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
index 13efc361fbb3..fa666afd1c27 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ * 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,
@@ -26,7 +26,7 @@ import android.net.wifi.nan.ConfigRequest;
oneway interface IWifiNanEventListener
{
void onConfigCompleted(in ConfigRequest completedConfig);
- void onConfigFailed(int reason);
+ void onConfigFailed(in ConfigRequest failedConfig, int reason);
void onNanDown(int reason);
void onIdentityChanged();
}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ec9e4628d609..f382d97762d3 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ * 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,
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
index 50c34d946918..d60d8caae70e 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * 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
+ * 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,
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
index eae0a55f7af1..5c18bd7e0f07 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
@@ -47,7 +47,8 @@ public class WifiNanEventListener {
/**
* Configuration failed callback event registration flag. Corresponding
- * callback is {@link WifiNanEventListener#onConfigFailed(int)}.
+ * callback is
+ * {@link WifiNanEventListener#onConfigFailed(ConfigRequest, int)}.
*/
public static final int LISTEN_CONFIG_FAILED = 0x1 << 1;
@@ -93,7 +94,7 @@ public class WifiNanEventListener {
WifiNanEventListener.this.onConfigCompleted((ConfigRequest) msg.obj);
break;
case LISTEN_CONFIG_FAILED:
- WifiNanEventListener.this.onConfigFailed(msg.arg1);
+ WifiNanEventListener.this.onConfigFailed((ConfigRequest) msg.obj, msg.arg1);
break;
case LISTEN_NAN_DOWN:
WifiNanEventListener.this.onNanDown(msg.arg1);
@@ -129,7 +130,7 @@ public class WifiNanEventListener {
*
* @param reason Failure reason code, see {@code NanSessionListener.FAIL_*}.
*/
- public void onConfigFailed(int reason) {
+ public void onConfigFailed(ConfigRequest failedConfig, int reason) {
Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable");
}
@@ -173,11 +174,14 @@ public class WifiNanEventListener {
}
@Override
- public void onConfigFailed(int reason) {
- if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason);
+ public void onConfigFailed(ConfigRequest failedConfig, int reason) {
+ if (VDBG) {
+ Log.v(TAG, "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason);
+ }
Message msg = mHandler.obtainMessage(LISTEN_CONFIG_FAILED);
msg.arg1 = reason;
+ msg.obj = failedConfig;
mHandler.sendMessage(msg);
}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
index d5e59f0edaf5..092508766570 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
@@ -303,8 +303,8 @@ public class WifiNanSessionListener {
* message). Override to implement your custom response.
* <p>
* Note that either this callback or
- * {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
- * never both.
+ * {@link WifiNanSessionListener#onMessageSendFail(int, int)} will be
+ * received - never both.
*/
public void onMessageSendSuccess(int messageId) {
if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
@@ -319,8 +319,8 @@ public class WifiNanSessionListener {
* message). Override to implement your custom response.
* <p>
* Note that either this callback or
- * {@link WifiNanSessionListener#onMessageSendSuccess()} will be received -
- * never both
+ * {@link WifiNanSessionListener#onMessageSendSuccess(int)} will be received
+ * - never both
*
* @param reason The failure reason using {@code NanSessionListener.FAIL_*}
* codes.